diff --git a/src/macro/MacroBison.yy b/src/macro/MacroBison.yy
index 9372964d58911aec4ad66429beb08b6708505f77..868379b84e954b03fc34cf33bcbf6680ad742436 100644
--- a/src/macro/MacroBison.yy
+++ b/src/macro/MacroBison.yy
@@ -66,7 +66,7 @@ class MacroDriver;
 
 }
 
-%token COMMA DEFINE LINE FOR IN IF ECHO_DIR ERROR IFDEF IFNDEF
+%token COMMA DEFINE LINE FOR IN IF ECHO_DIR ERROR IFDEF IFNDEF POWER
 %token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL LENGTH ECHOMACROVARS SAVE
 
 %token <int> INTEGER
@@ -78,7 +78,7 @@ class MacroDriver;
 %nonassoc IN
 %nonassoc COLON
 %left PLUS MINUS
-%left TIMES DIVIDE UNION INTERSECTION
+%left TIMES DIVIDE UNION INTERSECTION POWER
 %precedence UMINUS UPLUS EXCLAMATION
 %precedence LBRACKET
 
@@ -209,6 +209,8 @@ expr : INTEGER
        { TYPERR_CATCH($$ = $1->set_union($3), @$); }
      | expr INTERSECTION expr
        { TYPERR_CATCH($$ = $1->set_intersection($3), @$); }
+     | expr POWER expr
+       { TYPERR_CATCH($$ = $1->power($3), @$); }
      ;
 
 comma_expr : %empty
diff --git a/src/macro/MacroFlex.ll b/src/macro/MacroFlex.ll
index f4640784c744797202f37d2e63d304da3306f1db..7502f662bb1ff9f874a509c35e1625c85989ecca 100644
--- a/src/macro/MacroFlex.ll
+++ b/src/macro/MacroFlex.ll
@@ -220,6 +220,7 @@ CONT \\\\
 <STMT,EXPR>&&               { return token::LOGICAL_AND; }
 <STMT,EXPR>"|"              { return token::UNION; }
 <STMT,EXPR>"&"              { return token::INTERSECTION; }
+<STMT,EXPR>"^"              { return token::POWER; }
 <STMT,EXPR>"<="             { return token::LESS_EQUAL; }
 <STMT,EXPR>">="             { return token::GREATER_EQUAL; }
 <STMT,EXPR>"<"              { return token::LESS; }
diff --git a/src/macro/MacroValue.cc b/src/macro/MacroValue.cc
index 73695d9493b0fdfd283702438b6292b577aab708..737168c93f7bbfdd2cba9a3c111dd0960aa8dc1c 100644
--- a/src/macro/MacroValue.cc
+++ b/src/macro/MacroValue.cc
@@ -138,6 +138,12 @@ MacroValue::set_intersection(const MacroValuePtr &mv) noexcept(false)
   throw TypeError("Operator & does not exist for this type");
 }
 
+MacroValuePtr
+MacroValue::power(const MacroValuePtr &mv) noexcept(false)
+{
+  throw TypeError("Operator ^ does not exist for this type");
+}
+
 IntMV::IntMV(int value_arg) : value{value_arg}
 {
 }
@@ -648,6 +654,23 @@ ArrayMV::set_intersection(const MacroValuePtr &mv) noexcept(false)
   return make_shared<ArrayMV>(new_values);
 }
 
+MacroValuePtr
+ArrayMV::power(const MacroValuePtr &mv) noexcept(false)
+{
+  auto mv2 = dynamic_pointer_cast<IntMV>(mv);
+  if (!mv2)
+    throw TypeError("The second argument of the power operator (^) must be an integer");
+
+  shared_ptr<ArrayMV> retval = make_shared<ArrayMV>(values);
+  for (int i = 1; i < mv2->value; i++)
+    {
+      shared_ptr<MacroValue> mvp = retval->times(make_shared<ArrayMV>(values));
+      retval = make_shared<ArrayMV>(dynamic_pointer_cast<ArrayMV>(mvp)->values);
+    }
+
+  return retval;
+}
+
 TupleMV::TupleMV(vector<MacroValuePtr> values_arg) : values{move(values_arg)}
 {
 }
diff --git a/src/macro/MacroValue.hh b/src/macro/MacroValue.hh
index 5e35292f66657569761e11ac35253d43c5fd3c00..37a41dad57c493470acd8591abb7c50f6d5db864 100644
--- a/src/macro/MacroValue.hh
+++ b/src/macro/MacroValue.hh
@@ -109,6 +109,8 @@ public:
   virtual shared_ptr<ArrayMV> set_union(const MacroValuePtr &mv) noexcept(false);
   //! Creates the intersection of two sets
   virtual shared_ptr<ArrayMV> set_intersection(const MacroValuePtr &mv) noexcept(false);
+  //! Power as shortcut for Cartesion product
+  virtual MacroValuePtr power(const MacroValuePtr &mv) noexcept(false);
 };
 
 //! Represents an integer value in macro language
@@ -218,6 +220,8 @@ public:
   shared_ptr<ArrayMV> set_intersection(const MacroValuePtr &mvp) noexcept(false) override;
   // Computes the Cartesian product of two sets
   MacroValuePtr times(const MacroValuePtr &mv) noexcept(false) override;
+  // Shortcut for Cartesian product of two sets
+  MacroValuePtr power(const MacroValuePtr &mv) noexcept(false) override;
 };
 
 //! Represents a tuple value in macro language