diff --git a/src/macro/Expressions.cc b/src/macro/Expressions.cc
index 64d6f1e80bcedcee7fa2fab75c1548f869139520..dff5e5481e116032e1286d3bac5df1f0c700aafc 100644
--- a/src/macro/Expressions.cc
+++ b/src/macro/Expressions.cc
@@ -861,6 +861,8 @@ UnaryOp::eval()
           return argbt->normpdf();
         case codes::UnaryOp::normcdf:
           return argbt->normcdf();
+        case codes::UnaryOp::defined:
+          return argbt->defined();
         }
     }
   catch (StackTrace &ex)
@@ -1203,6 +1205,8 @@ UnaryOp::to_string() const noexcept
       return "normpdf(" + retval + ")";
     case codes::UnaryOp::normcdf:
       return "normcdf(" + retval + ")";
+    case codes::UnaryOp::defined:
+      return "defined(" + retval + ")";
     }
   // Suppress GCC warning
   exit(EXIT_FAILURE);
@@ -1463,6 +1467,9 @@ UnaryOp::print(ostream &output, bool matlab_output) const noexcept
     case codes::UnaryOp::normcdf:
       output << "normcdf(";
       break;
+    case codes::UnaryOp::defined:
+      output << "defined(";
+      break;
     }
 
   arg->print(output, matlab_output);
diff --git a/src/macro/Expressions.hh b/src/macro/Expressions.hh
index 757dacdfde841c9d7d494a05ede8346916bd574a..d77599a9b2df4bf4d0f5c080696645988c18e07c 100644
--- a/src/macro/Expressions.hh
+++ b/src/macro/Expressions.hh
@@ -191,6 +191,7 @@ namespace macro
     virtual StringPtr cast_string() const { throw StackTrace("This type cannot be cast to a string"); }
     virtual TuplePtr cast_tuple() const { throw StackTrace("This type cannot be cast to a tuple"); }
     virtual ArrayPtr cast_array() const { throw StackTrace("This type cannot be cast to an array"); }
+    virtual BoolPtr defined() const { throw StackTrace("Operator `defined` does not exist for this type"); }
   };
 
 
@@ -358,6 +359,10 @@ namespace macro
     {
       return make_shared<Array>(vector<ExpressionPtr>{make_shared<String>(value, env)}, env);
     }
+    inline BoolPtr defined() const override
+    {
+      return make_shared<Bool>(env.isSymbolDefined(value), env);
+    }
   };
 
 
diff --git a/src/macro/ForwardDeclarationsAndEnums.hh b/src/macro/ForwardDeclarationsAndEnums.hh
index 5b342e8caf3819f6e47c25acb4449667adabd95d..d34b0a49b417128b3962f59f0c7aacbf2e907083 100644
--- a/src/macro/ForwardDeclarationsAndEnums.hh
+++ b/src/macro/ForwardDeclarationsAndEnums.hh
@@ -104,7 +104,8 @@ namespace macro
        lgamma,
        round,
        normpdf,
-       normcdf
+       normcdf,
+       defined
       };
 
     enum class BinaryOp
diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy
index 2de754cf61c40d02d09282c8f354199db3dab50b..13244b40a32faa36513913e143191610b9b53554 100644
--- a/src/macro/Parser.yy
+++ b/src/macro/Parser.yy
@@ -70,6 +70,8 @@ using namespace macro;
 
 %token BOOL REAL STRING TUPLE ARRAY
 
+%token DEFINED
+
 %left OR
 %left AND
 %left EQUAL_EQUAL NOT_EQUAL
@@ -392,6 +394,8 @@ primary_expr : LPAREN expr RPAREN
                { $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normpdf, $3, $5, $7, driver.env, @$); }
              | NORMCDF LPAREN expr COMMA expr COMMA expr RPAREN
                { $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normcdf, $3, $5, $7, driver.env, @$); }
+             | DEFINED LPAREN NAME RPAREN
+               { $$ = make_shared<UnaryOp>(codes::UnaryOp::defined, make_shared<String>($3, driver.env, @3), driver.env, @$); }
              ;
 
 oper_expr : primary_expr
diff --git a/src/macro/Tokenizer.ll b/src/macro/Tokenizer.ll
index 941b30d742e54486996d219ccbd27e682b367744..e93b4f791481588e9d8eded081611deff6c8ae25 100644
--- a/src/macro/Tokenizer.ll
+++ b/src/macro/Tokenizer.ll
@@ -156,6 +156,8 @@ CONT \\\\{SPC}*
 <expr,eval>tuple           { return token::TUPLE; }
 <expr,eval>array           { return token::ARRAY; }
 
+<expr,eval>defined         { return token::DEFINED; }
+
 <expr,eval>((([0-9]*\.[0-9]+)|([0-9]+\.))([ed][-+]?[0-9]+)?)|([0-9]+([ed][-+]?[0-9]+)?)|nan|inf {
   yylval->build<string>(yytext);
   return token::NUMBER;