[Forensics-changes] [yara] 17/407: Improve scanning speed by matching certain strings only at fixed offsets

Hilko Bengen bengen at moszumanska.debian.org
Sat Jul 1 10:27:59 UTC 2017


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag v3.3.0
in repository yara.

commit a5a8b51c99a8178f9c1454ec6f48e97f40d41098
Author: Victor Manuel Alvarez <vmalvarez at virustotal.com>
Date:   Tue Sep 2 12:50:05 2014 +0200

    Improve scanning speed by matching certain strings only at fixed offsets
---
 libyara/exec.c                |  36 ++-
 libyara/grammar.c             | 540 ++++++++++++++++++++++--------------------
 libyara/grammar.h             |   4 +-
 libyara/grammar.y             | 196 ++++++++-------
 libyara/include/yara/exec.h   |   8 +
 libyara/include/yara/lexer.h  |  23 +-
 libyara/include/yara/parser.h |   3 +-
 libyara/include/yara/types.h  |   6 +
 libyara/parser.c              |  70 +++++-
 libyara/scan.c                |   4 +
 10 files changed, 515 insertions(+), 375 deletions(-)

diff --git a/libyara/exec.c b/libyara/exec.c
index 88f5c19..d7f3344 100644
--- a/libyara/exec.c
+++ b/libyara/exec.c
@@ -43,14 +43,6 @@ limitations under the License.
 #define pop(x)  x = stack[--sp]
 
 
-#define operation(operator, op1, op2) \
-    (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (UNDEFINED) : (op1 operator op2)
-
-
-#define comparison(operator, op1, op2) \
-    (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (0) : (op1 operator op2)
-
-
 #define function_read(type) \
     int64_t read_##type(YR_MEMORY_BLOCK* block, size_t offset) \
     { \
@@ -237,37 +229,37 @@ int yr_execute_code(
       case OP_LT:
         pop(r2);
         pop(r1);
-        push(comparison(<, r1, r2));
+        push(COMPARISON(<, r1, r2));
         break;
 
       case OP_GT:
         pop(r2);
         pop(r1);
-        push(comparison(>, r1, r2));
+        push(COMPARISON(>, r1, r2));
         break;
 
       case OP_LE:
         pop(r2);
         pop(r1);
-        push(comparison(<=, r1, r2));
+        push(COMPARISON(<=, r1, r2));
         break;
 
       case OP_GE:
         pop(r2);
         pop(r1);
-        push(comparison(>=, r1, r2));
+        push(COMPARISON(>=, r1, r2));
         break;
 
       case OP_EQ:
         pop(r2);
         pop(r1);
-        push(comparison(==, r1, r2));
+        push(COMPARISON(==, r1, r2));
         break;
 
       case OP_NEQ:
         pop(r2);
         pop(r1);
-        push(comparison(!=, r1, r2));
+        push(COMPARISON(!=, r1, r2));
         break;
 
       case OP_SZ_EQ:
@@ -305,31 +297,31 @@ int yr_execute_code(
       case OP_ADD:
         pop(r2);
         pop(r1);
-        push(operation(+, r1, r2));
+        push(OPERATION(+, r1, r2));
         break;
 
       case OP_SUB:
         pop(r2);
         pop(r1);
-        push(operation(-, r1, r2));
+        push(OPERATION(-, r1, r2));
         break;
 
       case OP_MUL:
         pop(r2);
         pop(r1);
-        push(operation(*, r1, r2));
+        push(OPERATION(*, r1, r2));
         break;
 
       case OP_DIV:
         pop(r2);
         pop(r1);
-        push(operation(/, r1, r2));
+        push(OPERATION(/, r1, r2));
         break;
 
       case OP_MOD:
         pop(r2);
         pop(r1);
-        push(operation(%, r1, r2));
+        push(OPERATION(%, r1, r2));
         break;
 
       case OP_NEG:
@@ -340,19 +332,19 @@ int yr_execute_code(
       case OP_SHR:
         pop(r2);
         pop(r1);
-        push(operation(>>, r1, r2));
+        push(OPERATION(>>, r1, r2));
         break;
 
       case OP_SHL:
         pop(r2);
         pop(r1);
-        push(operation(<<, r1, r2));
+        push(OPERATION(<<, r1, r2));
         break;
 
       case OP_XOR:
         pop(r2);
         pop(r1);
-        push(operation(^, r1, r2));
+        push(OPERATION(^, r1, r2));
         break;
 
       case OP_PUSH_RULE:
diff --git a/libyara/grammar.c b/libyara/grammar.c
index a2995f9..98f1105 100644
--- a/libyara/grammar.c
+++ b/libyara/grammar.c
@@ -226,10 +226,10 @@
     } \
 
 
-#define CHECK_TYPE_WITH_CLEANUP(actual_type, expected_type, op, cleanup) \
-    if (actual_type != expected_type) \
+#define CHECK_TYPE_WITH_CLEANUP(expression, expected_type, op, cleanup) \
+    if (expression.type != expected_type) \
     { \
-      switch(actual_type) \
+      switch(expression.type) \
       { \
         case EXPRESSION_TYPE_INTEGER: \
           yr_compiler_set_error_extra_info( \
@@ -246,8 +246,9 @@
       YYERROR; \
     }
 
-#define CHECK_TYPE(actual_type, expected_type, op) \
-    CHECK_TYPE_WITH_CLEANUP(actual_type, expected_type, op, ) \
+
+#define CHECK_TYPE(expression, expected_type, op) \
+    CHECK_TYPE_WITH_CLEANUP(expression, expected_type, op, ) \
 
 
 #define MSG(op)  "wrong type \"string\" for \"" op "\" operator"
@@ -274,18 +275,18 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 186 "grammar.y"
+#line 187 "grammar.y"
 {
+  EXPRESSION      expression;
   SIZED_STRING*   sized_string;
   char*           c_string;
-  int8_t          expression_type;
   int64_t         integer;
   YR_STRING*      string;
   YR_META*        meta;
   YR_OBJECT*      object;
 }
 /* Line 193 of yacc.c.  */
-#line 289 "grammar.c"
+#line 290 "grammar.c"
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -298,7 +299,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 302 "grammar.c"
+#line 303 "grammar.c"
 
 #ifdef short
 # undef short
@@ -632,18 +633,18 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   201,   202,   203,   204,   209,   221,   240,
-     243,   271,   275,   303,   308,   309,   314,   315,   321,   324,
-     342,   355,   392,   393,   398,   414,   427,   440,   457,   458,
-     463,   477,   476,   493,   510,   511,   516,   517,   518,   519,
-     524,   612,   661,   684,   724,   727,   749,   782,   827,   845,
-     854,   863,   878,   892,   905,   920,   934,   969,   933,  1080,
-    1079,  1156,  1162,  1168,  1174,  1182,  1191,  1200,  1209,  1218,
-    1245,  1272,  1299,  1303,  1311,  1312,  1317,  1339,  1351,  1367,
-    1366,  1372,  1381,  1382,  1387,  1392,  1401,  1402,  1406,  1414,
-    1418,  1427,  1439,  1450,  1461,  1472,  1483,  1494,  1505,  1514,
-    1537,  1550,  1563,  1583,  1618,  1627,  1636,  1645,  1654,  1663,
-    1672,  1681,  1690,  1698,  1707,  1716
+       0,   200,   200,   202,   203,   204,   205,   210,   222,   241,
+     244,   272,   276,   304,   309,   310,   315,   316,   322,   325,
+     343,   356,   393,   394,   399,   415,   428,   441,   458,   459,
+     464,   478,   477,   494,   511,   512,   517,   518,   519,   520,
+     525,   613,   662,   685,   725,   728,   750,   783,   828,   845,
+     854,   863,   878,   892,   906,   922,   937,   972,   936,  1083,
+    1082,  1159,  1165,  1171,  1177,  1185,  1194,  1203,  1212,  1221,
+    1248,  1275,  1302,  1306,  1314,  1315,  1320,  1342,  1354,  1370,
+    1369,  1375,  1384,  1385,  1390,  1395,  1404,  1405,  1409,  1417,
+    1421,  1431,  1444,  1456,  1468,  1480,  1492,  1504,  1516,  1526,
+    1549,  1564,  1579,  1601,  1638,  1648,  1658,  1668,  1678,  1688,
+    1698,  1708,  1718,  1728,  1738,  1748
 };
 #endif
 
@@ -1448,44 +1449,44 @@ yydestruct (yymsg, yytype, yyvaluep, yyscanner, compiler)
   switch (yytype)
     {
       case 9: /* "_IDENTIFIER_" */
-#line 177 "grammar.y"
+#line 178 "grammar.y"
 	{ yr_free((yyvaluep->c_string)); };
-#line 1454 "grammar.c"
+#line 1455 "grammar.c"
 	break;
       case 10: /* "_STRING_IDENTIFIER_" */
-#line 178 "grammar.y"
+#line 179 "grammar.y"
 	{ yr_free((yyvaluep->c_string)); };
-#line 1459 "grammar.c"
+#line 1460 "grammar.c"
 	break;
       case 11: /* "_STRING_COUNT_" */
-#line 179 "grammar.y"
+#line 180 "grammar.y"
 	{ yr_free((yyvaluep->c_string)); };
-#line 1464 "grammar.c"
+#line 1465 "grammar.c"
 	break;
       case 12: /* "_STRING_OFFSET_" */
-#line 180 "grammar.y"
+#line 181 "grammar.y"
 	{ yr_free((yyvaluep->c_string)); };
-#line 1469 "grammar.c"
+#line 1470 "grammar.c"
 	break;
       case 13: /* "_STRING_IDENTIFIER_WITH_WILDCARD_" */
-#line 181 "grammar.y"
+#line 182 "grammar.y"
 	{ yr_free((yyvaluep->c_string)); };
-#line 1474 "grammar.c"
+#line 1475 "grammar.c"
 	break;
       case 15: /* "_TEXT_STRING_" */
-#line 182 "grammar.y"
+#line 183 "grammar.y"
 	{ yr_free((yyvaluep->sized_string)); };
-#line 1479 "grammar.c"
+#line 1480 "grammar.c"
 	break;
       case 16: /* "_HEX_STRING_" */
-#line 183 "grammar.y"
+#line 184 "grammar.y"
 	{ yr_free((yyvaluep->sized_string)); };
-#line 1484 "grammar.c"
+#line 1485 "grammar.c"
 	break;
       case 17: /* "_REGEXP_" */
-#line 184 "grammar.y"
+#line 185 "grammar.y"
 	{ yr_free((yyvaluep->sized_string)); };
-#line 1489 "grammar.c"
+#line 1490 "grammar.c"
 	break;
 
       default:
@@ -1795,7 +1796,7 @@ yyreduce:
   switch (yyn)
     {
         case 7:
-#line 210 "grammar.y"
+#line 211 "grammar.y"
     {
         int result = yr_parser_reduce_import(yyscanner, (yyvsp[(2) - (2)].sized_string));
 
@@ -1806,7 +1807,7 @@ yyreduce:
     break;
 
   case 8:
-#line 222 "grammar.y"
+#line 223 "grammar.y"
     {
         int result = yr_parser_reduce_rule_declaration(
             yyscanner,
@@ -1823,14 +1824,14 @@ yyreduce:
     break;
 
   case 9:
-#line 240 "grammar.y"
+#line 241 "grammar.y"
     {
         (yyval.meta) = NULL;
       }
     break;
 
   case 10:
-#line 244 "grammar.y"
+#line 245 "grammar.y"
     {
         // Each rule have a list of meta-data info, consisting in a
         // sequence of YR_META structures. The last YR_META structure does
@@ -1856,7 +1857,7 @@ yyreduce:
     break;
 
   case 11:
-#line 271 "grammar.y"
+#line 272 "grammar.y"
     {
         (yyval.string) = NULL;
         compiler->current_rule_strings = (yyval.string);
@@ -1864,7 +1865,7 @@ yyreduce:
     break;
 
   case 12:
-#line 276 "grammar.y"
+#line 277 "grammar.y"
     {
         // Each rule have a list of strings, consisting in a sequence
         // of YR_STRING structures. The last YR_STRING structure does not
@@ -1891,34 +1892,34 @@ yyreduce:
     break;
 
   case 14:
-#line 308 "grammar.y"
+#line 309 "grammar.y"
     { (yyval.integer) = 0;  }
     break;
 
   case 15:
-#line 309 "grammar.y"
+#line 310 "grammar.y"
     { (yyval.integer) = (yyvsp[(1) - (2)].integer) | (yyvsp[(2) - (2)].integer); }
     break;
 
   case 16:
-#line 314 "grammar.y"
+#line 315 "grammar.y"
     { (yyval.integer) = RULE_GFLAGS_PRIVATE; }
     break;
 
   case 17:
-#line 315 "grammar.y"
+#line 316 "grammar.y"
     { (yyval.integer) = RULE_GFLAGS_GLOBAL; }
     break;
 
   case 18:
-#line 321 "grammar.y"
+#line 322 "grammar.y"
     {
         (yyval.c_string) = NULL;
       }
     break;
 
   case 19:
-#line 325 "grammar.y"
+#line 326 "grammar.y"
     {
         // Tags list is represented in the arena as a sequence
         // of null-terminated strings, the sequence ends with an
@@ -1935,7 +1936,7 @@ yyreduce:
     break;
 
   case 20:
-#line 343 "grammar.y"
+#line 344 "grammar.y"
     {
         char* identifier;
 
@@ -1951,7 +1952,7 @@ yyreduce:
     break;
 
   case 21:
-#line 356 "grammar.y"
+#line 357 "grammar.y"
     {
         char* tag_name = (yyvsp[(1) - (2)].c_string);
         size_t tag_length = tag_name != NULL ? strlen(tag_name) : 0;
@@ -1986,17 +1987,17 @@ yyreduce:
     break;
 
   case 22:
-#line 392 "grammar.y"
+#line 393 "grammar.y"
     {  (yyval.meta) = (yyvsp[(1) - (1)].meta); }
     break;
 
   case 23:
-#line 393 "grammar.y"
+#line 394 "grammar.y"
     {  (yyval.meta) = (yyvsp[(1) - (2)].meta); }
     break;
 
   case 24:
-#line 399 "grammar.y"
+#line 400 "grammar.y"
     {
         SIZED_STRING* sized_string = (yyvsp[(3) - (3)].sized_string);
 
@@ -2015,7 +2016,7 @@ yyreduce:
     break;
 
   case 25:
-#line 415 "grammar.y"
+#line 416 "grammar.y"
     {
         (yyval.meta) = yr_parser_reduce_meta_declaration(
             yyscanner,
@@ -2031,7 +2032,7 @@ yyreduce:
     break;
 
   case 26:
-#line 428 "grammar.y"
+#line 429 "grammar.y"
     {
         (yyval.meta) = yr_parser_reduce_meta_declaration(
             yyscanner,
@@ -2047,7 +2048,7 @@ yyreduce:
     break;
 
   case 27:
-#line 441 "grammar.y"
+#line 442 "grammar.y"
     {
         (yyval.meta) = yr_parser_reduce_meta_declaration(
             yyscanner,
@@ -2063,17 +2064,17 @@ yyreduce:
     break;
 
   case 28:
-#line 457 "grammar.y"
+#line 458 "grammar.y"
     { (yyval.string) = (yyvsp[(1) - (1)].string); }
     break;
 
   case 29:
-#line 458 "grammar.y"
+#line 459 "grammar.y"
     { (yyval.string) = (yyvsp[(1) - (2)].string); }
     break;
 
   case 30:
-#line 464 "grammar.y"
+#line 465 "grammar.y"
     {
         (yyval.string) = yr_parser_reduce_string_declaration(
             yyscanner,
@@ -2089,14 +2090,14 @@ yyreduce:
     break;
 
   case 31:
-#line 477 "grammar.y"
+#line 478 "grammar.y"
     {
         compiler->error_line = yyget_lineno(yyscanner);
       }
     break;
 
   case 32:
-#line 481 "grammar.y"
+#line 482 "grammar.y"
     {
         (yyval.string) = yr_parser_reduce_string_declaration(
             yyscanner,
@@ -2112,7 +2113,7 @@ yyreduce:
     break;
 
   case 33:
-#line 494 "grammar.y"
+#line 495 "grammar.y"
     {
         (yyval.string) = yr_parser_reduce_string_declaration(
             yyscanner,
@@ -2128,37 +2129,37 @@ yyreduce:
     break;
 
   case 34:
-#line 510 "grammar.y"
+#line 511 "grammar.y"
     { (yyval.integer) = 0; }
     break;
 
   case 35:
-#line 511 "grammar.y"
+#line 512 "grammar.y"
     { (yyval.integer) = (yyvsp[(1) - (2)].integer) | (yyvsp[(2) - (2)].integer); }
     break;
 
   case 36:
-#line 516 "grammar.y"
+#line 517 "grammar.y"
     { (yyval.integer) = STRING_GFLAGS_WIDE; }
     break;
 
   case 37:
-#line 517 "grammar.y"
+#line 518 "grammar.y"
     { (yyval.integer) = STRING_GFLAGS_ASCII; }
     break;
 
   case 38:
-#line 518 "grammar.y"
+#line 519 "grammar.y"
     { (yyval.integer) = STRING_GFLAGS_NO_CASE; }
     break;
 
   case 39:
-#line 519 "grammar.y"
+#line 520 "grammar.y"
     { (yyval.integer) = STRING_GFLAGS_FULL_WORD; }
     break;
 
   case 40:
-#line 525 "grammar.y"
+#line 526 "grammar.y"
     {
         YR_OBJECT* object = NULL;
         YR_RULE* rule;
@@ -2249,7 +2250,7 @@ yyreduce:
     break;
 
   case 41:
-#line 613 "grammar.y"
+#line 614 "grammar.y"
     {
         YR_OBJECT* object = (yyvsp[(1) - (3)].object);
         YR_OBJECT* field = NULL;
@@ -2301,7 +2302,7 @@ yyreduce:
     break;
 
   case 42:
-#line 662 "grammar.y"
+#line 663 "grammar.y"
     {
         if ((yyvsp[(1) - (4)].object) != NULL && (yyvsp[(1) - (4)].object)->type == OBJECT_TYPE_ARRAY)
         {
@@ -2326,7 +2327,7 @@ yyreduce:
     break;
 
   case 43:
-#line 685 "grammar.y"
+#line 686 "grammar.y"
     {
         int args_count;
 
@@ -2364,18 +2365,18 @@ yyreduce:
     break;
 
   case 44:
-#line 724 "grammar.y"
+#line 725 "grammar.y"
     {
         (yyval.c_string) = yr_strdup("");
       }
     break;
 
   case 45:
-#line 728 "grammar.y"
+#line 729 "grammar.y"
     {
         (yyval.c_string) = yr_malloc(MAX_FUNCTION_ARGS + 1);
 
-        switch((yyvsp[(1) - (1)].expression_type))
+        switch((yyvsp[(1) - (1)].expression).type)
         {
           case EXPRESSION_TYPE_INTEGER:
             strlcpy((yyval.c_string), "i", MAX_FUNCTION_ARGS);
@@ -2396,7 +2397,7 @@ yyreduce:
     break;
 
   case 46:
-#line 750 "grammar.y"
+#line 751 "grammar.y"
     {
         if (strlen((yyvsp[(1) - (3)].c_string)) == MAX_FUNCTION_ARGS)
         {
@@ -2404,7 +2405,7 @@ yyreduce:
         }
         else
         {
-          switch((yyvsp[(3) - (3)].expression_type))
+          switch((yyvsp[(3) - (3)].expression).type)
           {
             case EXPRESSION_TYPE_INTEGER:
               strlcat((yyvsp[(1) - (3)].c_string), "i", MAX_FUNCTION_ARGS);
@@ -2428,7 +2429,7 @@ yyreduce:
     break;
 
   case 47:
-#line 783 "grammar.y"
+#line 784 "grammar.y"
     {
         SIZED_STRING* sized_string = (yyvsp[(1) - (1)].sized_string);
         RE* re;
@@ -2467,14 +2468,14 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_REGEXP;
+        (yyval.expression).type = EXPRESSION_TYPE_REGEXP;
       }
     break;
 
   case 48:
-#line 828 "grammar.y"
+#line 829 "grammar.y"
     {
-        if ((yyvsp[(1) - (1)].expression_type) == EXPRESSION_TYPE_STRING)
+        if ((yyvsp[(1) - (1)].expression).type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -2484,8 +2485,7 @@ yyreduce:
           ERROR_IF(compiler->last_result != ERROR_SUCCESS);
         }
 
-
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
@@ -2497,7 +2497,7 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
@@ -2509,15 +2509,15 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 51:
 #line 864 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_STRING, "matches");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_REGEXP, "matches");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_STRING, "matches");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_REGEXP, "matches");
 
         if (compiler->last_result == ERROR_SUCCESS)
           compiler->last_result = yr_parser_emit(
@@ -2527,15 +2527,15 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 52:
 #line 879 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_STRING, "contains");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_STRING, "contains");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_STRING, "contains");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_STRING, "contains");
 
         compiler->last_result = yr_parser_emit(
             yyscanner,
@@ -2544,7 +2544,7 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
@@ -2554,52 +2554,55 @@ yyreduce:
         int result = yr_parser_reduce_string_identifier(
             yyscanner,
             (yyvsp[(1) - (1)].c_string),
-            OP_STR_FOUND);
+            OP_STR_FOUND,
+            UNDEFINED);
 
         yr_free((yyvsp[(1) - (1)].c_string));
 
         ERROR_IF(result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 54:
-#line 906 "grammar.y"
+#line 907 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "at");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "at");
 
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             (yyvsp[(1) - (3)].c_string),
-            OP_STR_FOUND_AT);
+            OP_STR_FOUND_AT,
+            (yyvsp[(3) - (3)].expression).value.integer);
 
         yr_free((yyvsp[(1) - (3)].c_string));
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 55:
-#line 921 "grammar.y"
+#line 923 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             (yyvsp[(1) - (3)].c_string),
-            OP_STR_FOUND_IN);
+            OP_STR_FOUND_IN,
+            UNDEFINED);
 
         yr_free((yyvsp[(1) - (3)].c_string));
 
         ERROR_IF(compiler->last_result!= ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 56:
-#line 934 "grammar.y"
+#line 937 "grammar.y"
     {
         int var_index;
 
@@ -2637,7 +2640,7 @@ yyreduce:
     break;
 
   case 57:
-#line 969 "grammar.y"
+#line 972 "grammar.y"
     {
         int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth;
         int8_t* addr;
@@ -2675,7 +2678,7 @@ yyreduce:
     break;
 
   case 58:
-#line 1004 "grammar.y"
+#line 1007 "grammar.y"
     {
         int mem_offset;
 
@@ -2749,12 +2752,12 @@ yyreduce:
         compiler->loop_identifier[compiler->loop_depth] = NULL;
         yr_free((yyvsp[(3) - (11)].c_string));
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 59:
-#line 1080 "grammar.y"
+#line 1083 "grammar.y"
     {
         int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth;
         int8_t* addr;
@@ -2787,7 +2790,7 @@ yyreduce:
     break;
 
   case 60:
-#line 1110 "grammar.y"
+#line 1113 "grammar.y"
     {
         int mem_offset;
 
@@ -2831,107 +2834,107 @@ yyreduce:
 
         yr_parser_emit(yyscanner, OP_LE, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
 
       }
     break;
 
   case 61:
-#line 1157 "grammar.y"
+#line 1160 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_OF, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 62:
-#line 1163 "grammar.y"
+#line 1166 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_NOT, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 63:
-#line 1169 "grammar.y"
+#line 1172 "grammar.y"
     {
         yr_parser_emit(yyscanner, OP_AND, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 64:
-#line 1175 "grammar.y"
+#line 1178 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_BOOLEAN, "or");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_BOOLEAN, "or");
 
         yr_parser_emit(yyscanner, OP_OR, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 65:
-#line 1183 "grammar.y"
+#line 1186 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<");
 
         yr_parser_emit(yyscanner, OP_LT, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 66:
-#line 1192 "grammar.y"
+#line 1195 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">");
 
         yr_parser_emit(yyscanner, OP_GT, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 67:
-#line 1201 "grammar.y"
+#line 1204 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<=");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<=");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<=");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<=");
 
         yr_parser_emit(yyscanner, OP_LE, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 68:
-#line 1210 "grammar.y"
+#line 1213 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">=");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">=");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">=");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">=");
 
         yr_parser_emit(yyscanner, OP_GE, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 69:
-#line 1219 "grammar.y"
+#line 1222 "grammar.y"
     {
-        if ((yyvsp[(1) - (3)].expression_type) != (yyvsp[(3) - (3)].expression_type))
+        if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for == operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ((yyvsp[(1) - (3)].expression_type) == EXPRESSION_TYPE_STRING)
+        else if ((yyvsp[(1) - (3)].expression).type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -2948,20 +2951,20 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 70:
-#line 1246 "grammar.y"
+#line 1249 "grammar.y"
     {
-        if ((yyvsp[(1) - (3)].expression_type) != (yyvsp[(3) - (3)].expression_type))
+        if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for == operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ((yyvsp[(1) - (3)].expression_type) == EXPRESSION_TYPE_STRING)
+        else if ((yyvsp[(1) - (3)].expression).type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -2978,20 +2981,20 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 71:
-#line 1273 "grammar.y"
+#line 1276 "grammar.y"
     {
-        if ((yyvsp[(1) - (3)].expression_type) != (yyvsp[(3) - (3)].expression_type))
+        if ((yyvsp[(1) - (3)].expression).type != (yyvsp[(3) - (3)].expression).type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for != operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ((yyvsp[(1) - (3)].expression_type) == EXPRESSION_TYPE_STRING)
+        else if ((yyvsp[(1) - (3)].expression).type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -3008,45 +3011,45 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+        (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
       }
     break;
 
   case 72:
-#line 1300 "grammar.y"
+#line 1303 "grammar.y"
     {
-        (yyval.expression_type) = (yyvsp[(1) - (1)].expression_type);
+        (yyval.expression) = (yyvsp[(1) - (1)].expression);
       }
     break;
 
   case 73:
-#line 1304 "grammar.y"
+#line 1307 "grammar.y"
     {
-        (yyval.expression_type) = (yyvsp[(2) - (3)].expression_type);
+        (yyval.expression) = (yyvsp[(2) - (3)].expression);
       }
     break;
 
   case 74:
-#line 1311 "grammar.y"
+#line 1314 "grammar.y"
     { (yyval.integer) = INTEGER_SET_ENUMERATION; }
     break;
 
   case 75:
-#line 1312 "grammar.y"
+#line 1315 "grammar.y"
     { (yyval.integer) = INTEGER_SET_RANGE; }
     break;
 
   case 76:
-#line 1318 "grammar.y"
+#line 1321 "grammar.y"
     {
-        if ((yyvsp[(2) - (6)].expression_type) != EXPRESSION_TYPE_INTEGER)
+        if ((yyvsp[(2) - (6)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for range's lower bound");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
 
-        if ((yyvsp[(5) - (6)].expression_type) != EXPRESSION_TYPE_INTEGER)
+        if ((yyvsp[(5) - (6)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for range's upper bound");
@@ -3058,9 +3061,9 @@ yyreduce:
     break;
 
   case 77:
-#line 1340 "grammar.y"
+#line 1343 "grammar.y"
     {
-        if ((yyvsp[(1) - (1)].expression_type) != EXPRESSION_TYPE_INTEGER)
+        if ((yyvsp[(1) - (1)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for enumeration item");
@@ -3073,9 +3076,9 @@ yyreduce:
     break;
 
   case 78:
-#line 1352 "grammar.y"
+#line 1355 "grammar.y"
     {
-        if ((yyvsp[(3) - (3)].expression_type) != EXPRESSION_TYPE_INTEGER)
+        if ((yyvsp[(3) - (3)].expression).type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for enumeration item");
@@ -3087,7 +3090,7 @@ yyreduce:
     break;
 
   case 79:
-#line 1367 "grammar.y"
+#line 1370 "grammar.y"
     {
         // Push end-of-list marker
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
@@ -3095,7 +3098,7 @@ yyreduce:
     break;
 
   case 81:
-#line 1373 "grammar.y"
+#line 1376 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
         yr_parser_emit_pushes_for_strings(yyscanner, "$*");
@@ -3103,7 +3106,7 @@ yyreduce:
     break;
 
   case 84:
-#line 1388 "grammar.y"
+#line 1391 "grammar.y"
     {
         yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[(1) - (1)].c_string));
         yr_free((yyvsp[(1) - (1)].c_string));
@@ -3111,7 +3114,7 @@ yyreduce:
     break;
 
   case 85:
-#line 1393 "grammar.y"
+#line 1396 "grammar.y"
     {
         yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[(1) - (1)].c_string));
         yr_free((yyvsp[(1) - (1)].c_string));
@@ -3119,40 +3122,41 @@ yyreduce:
     break;
 
   case 87:
-#line 1403 "grammar.y"
+#line 1406 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL);
       }
     break;
 
   case 88:
-#line 1407 "grammar.y"
+#line 1410 "grammar.y"
     {
         yr_parser_emit_with_arg(yyscanner, OP_PUSH, 1, NULL);
       }
     break;
 
   case 89:
-#line 1415 "grammar.y"
+#line 1418 "grammar.y"
     {
-        (yyval.expression_type) = (yyvsp[(2) - (3)].expression_type);
+        (yyval.expression) = (yyvsp[(2) - (3)].expression);
       }
     break;
 
   case 90:
-#line 1419 "grammar.y"
+#line 1422 "grammar.y"
     {
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_FILESIZE, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
-
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 91:
-#line 1428 "grammar.y"
+#line 1432 "grammar.y"
     {
         yywarning(yyscanner,
             "Using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " "function from PE module instead.");
@@ -3162,108 +3166,116 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 92:
-#line 1440 "grammar.y"
+#line 1445 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "int8");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int8");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_INT8, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 93:
-#line 1451 "grammar.y"
+#line 1457 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "int16");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int16");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_INT16, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 94:
-#line 1462 "grammar.y"
+#line 1469 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "int32");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "int32");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_INT32, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 95:
-#line 1473 "grammar.y"
+#line 1481 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "uint8");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint8");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_UINT8, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 96:
-#line 1484 "grammar.y"
+#line 1493 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "uint16");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint16");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_UINT16, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 97:
-#line 1495 "grammar.y"
+#line 1505 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(3) - (4)].expression_type), EXPRESSION_TYPE_INTEGER, "uint32");
+        CHECK_TYPE((yyvsp[(3) - (4)].expression), EXPRESSION_TYPE_INTEGER, "uint32");
 
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_UINT32, NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 98:
-#line 1506 "grammar.y"
+#line 1517 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner, OP_PUSH, (yyvsp[(1) - (1)].integer), NULL);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = (yyvsp[(1) - (1)].integer);
       }
     break;
 
   case 99:
-#line 1515 "grammar.y"
+#line 1527 "grammar.y"
     {
         SIZED_STRING* sized_string = (yyvsp[(1) - (1)].sized_string);
         char* string;
@@ -3284,44 +3296,48 @@ yyreduce:
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_STRING;
+        (yyval.expression).type = EXPRESSION_TYPE_STRING;
       }
     break;
 
   case 100:
-#line 1538 "grammar.y"
+#line 1550 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             (yyvsp[(1) - (1)].c_string),
-            OP_STR_COUNT);
+            OP_STR_COUNT,
+            UNDEFINED);
 
         yr_free((yyvsp[(1) - (1)].c_string));
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 101:
-#line 1551 "grammar.y"
+#line 1565 "grammar.y"
     {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             (yyvsp[(1) - (4)].c_string),
-            OP_STR_OFFSET);
+            OP_STR_OFFSET,
+            UNDEFINED);
 
         yr_free((yyvsp[(1) - (4)].c_string));
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 102:
-#line 1564 "grammar.y"
+#line 1580 "grammar.y"
     {
         compiler->last_result = yr_parser_emit_with_arg(
             yyscanner,
@@ -3333,26 +3349,29 @@ yyreduce:
           compiler->last_result = yr_parser_reduce_string_identifier(
               yyscanner,
               (yyvsp[(1) - (1)].c_string),
-              OP_STR_OFFSET);
+              OP_STR_OFFSET,
+              UNDEFINED);
 
         yr_free((yyvsp[(1) - (1)].c_string));
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = UNDEFINED;
       }
     break;
 
   case 103:
-#line 1584 "grammar.y"
+#line 1602 "grammar.y"
     {
         if ((yyvsp[(1) - (1)].object) == (YR_OBJECT*) -1)  // loop identifier
         {
-          (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+          (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+          (yyval.expression).value.integer = UNDEFINED;
         }
         else if ((yyvsp[(1) - (1)].object) == (YR_OBJECT*) -2)  // rule identifier
         {
-          (yyval.expression_type) = EXPRESSION_TYPE_BOOLEAN;
+          (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN;
         }
         else if ((yyvsp[(1) - (1)].object) != NULL)
         {
@@ -3362,10 +3381,11 @@ yyreduce:
           switch((yyvsp[(1) - (1)].object)->type)
           {
             case OBJECT_TYPE_INTEGER:
-              (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+              (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+              (yyval.expression).value.integer = UNDEFINED;
               break;
             case OBJECT_TYPE_STRING:
-              (yyval.expression_type) = EXPRESSION_TYPE_STRING;
+              (yyval.expression).type = EXPRESSION_TYPE_STRING;
               break;
             default:
               assert(FALSE);
@@ -3382,146 +3402,158 @@ yyreduce:
     break;
 
   case 104:
-#line 1619 "grammar.y"
+#line 1639 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "+");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "+");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "+");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "+");
 
         yr_parser_emit(yyscanner, OP_ADD, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(+, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 105:
-#line 1628 "grammar.y"
+#line 1649 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "-");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "-");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "-");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "-");
 
         yr_parser_emit(yyscanner, OP_SUB, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(-, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 106:
-#line 1637 "grammar.y"
+#line 1659 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "*");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "*");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "*");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "*");
 
         yr_parser_emit(yyscanner, OP_MUL, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(*, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 107:
-#line 1646 "grammar.y"
+#line 1669 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "\\");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "\\");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "\\");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "\\");
 
         yr_parser_emit(yyscanner, OP_DIV, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(/, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 108:
-#line 1655 "grammar.y"
+#line 1679 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "%");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "%");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "%");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "%");
 
         yr_parser_emit(yyscanner, OP_MOD, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(%, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 109:
-#line 1664 "grammar.y"
+#line 1689 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "^");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "^");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
 
         yr_parser_emit(yyscanner, OP_XOR, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(^, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 110:
-#line 1673 "grammar.y"
+#line 1699 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "^");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "^");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "^");
 
         yr_parser_emit(yyscanner, OP_AND, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(&, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 111:
-#line 1682 "grammar.y"
+#line 1709 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "|");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "|");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "|");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "|");
 
         yr_parser_emit(yyscanner, OP_OR, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(|, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 112:
-#line 1691 "grammar.y"
+#line 1719 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(2) - (2)].expression_type), EXPRESSION_TYPE_INTEGER, "~");
+        CHECK_TYPE((yyvsp[(2) - (2)].expression), EXPRESSION_TYPE_INTEGER, "~");
 
         yr_parser_emit(yyscanner, OP_NEG, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = ((yyvsp[(2) - (2)].expression).value.integer == UNDEFINED) ?
+                              UNDEFINED : (yyvsp[(2) - (2)].expression).value.integer;
       }
     break;
 
   case 113:
-#line 1699 "grammar.y"
+#line 1729 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<<");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, "<<");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<<");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, "<<");
 
         yr_parser_emit(yyscanner, OP_SHL, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(<<, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 114:
-#line 1708 "grammar.y"
+#line 1739 "grammar.y"
     {
-        CHECK_TYPE((yyvsp[(1) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">>");
-        CHECK_TYPE((yyvsp[(3) - (3)].expression_type), EXPRESSION_TYPE_INTEGER, ">>");
+        CHECK_TYPE((yyvsp[(1) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">>");
+        CHECK_TYPE((yyvsp[(3) - (3)].expression), EXPRESSION_TYPE_INTEGER, ">>");
 
         yr_parser_emit(yyscanner, OP_SHR, NULL);
 
-        (yyval.expression_type) = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).type = EXPRESSION_TYPE_INTEGER;
+        (yyval.expression).value.integer = OPERATION(>>, (yyvsp[(1) - (3)].expression).value.integer, (yyvsp[(3) - (3)].expression).value.integer);
       }
     break;
 
   case 115:
-#line 1717 "grammar.y"
+#line 1749 "grammar.y"
     {
-        (yyval.expression_type) = (yyvsp[(1) - (1)].expression_type);
+        (yyval.expression) = (yyvsp[(1) - (1)].expression);
       }
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 3525 "grammar.c"
+#line 3557 "grammar.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3735,6 +3767,6 @@ yyreturn:
 }
 
 
-#line 1722 "grammar.y"
+#line 1754 "grammar.y"
 
 
diff --git a/libyara/grammar.h b/libyara/grammar.h
index 9865021..05c3426 100644
--- a/libyara/grammar.h
+++ b/libyara/grammar.h
@@ -150,11 +150,11 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 186 "grammar.y"
+#line 187 "grammar.y"
 {
+  EXPRESSION      expression;
   SIZED_STRING*   sized_string;
   char*           c_string;
-  int8_t          expression_type;
   int64_t         integer;
   YR_STRING*      string;
   YR_META*        meta;
diff --git a/libyara/grammar.y b/libyara/grammar.y
index 23391a7..b54e279 100644
--- a/libyara/grammar.y
+++ b/libyara/grammar.y
@@ -55,10 +55,10 @@ limitations under the License.
     } \
 
 
-#define CHECK_TYPE_WITH_CLEANUP(actual_type, expected_type, op, cleanup) \
-    if (actual_type != expected_type) \
+#define CHECK_TYPE_WITH_CLEANUP(expression, expected_type, op, cleanup) \
+    if (expression.type != expected_type) \
     { \
-      switch(actual_type) \
+      switch(expression.type) \
       { \
         case EXPRESSION_TYPE_INTEGER: \
           yr_compiler_set_error_extra_info( \
@@ -75,8 +75,9 @@ limitations under the License.
       YYERROR; \
     }
 
-#define CHECK_TYPE(actual_type, expected_type, op) \
-    CHECK_TYPE_WITH_CLEANUP(actual_type, expected_type, op, ) \
+
+#define CHECK_TYPE(expression, expected_type, op) \
+    CHECK_TYPE_WITH_CLEANUP(expression, expected_type, op, ) \
 
 
 #define MSG(op)  "wrong type \"string\" for \"" op "\" operator"
@@ -166,10 +167,10 @@ limitations under the License.
 
 %type <object> identifier
 
-%type <expression_type> primary_expression
-%type <expression_type> boolean_expression
-%type <expression_type> expression
-%type <expression_type> regexp
+%type <expression> primary_expression
+%type <expression> boolean_expression
+%type <expression> expression
+%type <expression> regexp
 
 %type <c_string> arguments_list
 
@@ -184,9 +185,9 @@ limitations under the License.
 %destructor { yr_free($$); } _REGEXP_
 
 %union {
+  EXPRESSION      expression;
   SIZED_STRING*   sized_string;
   char*           c_string;
-  int8_t          expression_type;
   int64_t         integer;
   YR_STRING*      string;
   YR_META*        meta;
@@ -728,7 +729,7 @@ arguments_list
       {
         $$ = yr_malloc(MAX_FUNCTION_ARGS + 1);
 
-        switch($1)
+        switch($1.type)
         {
           case EXPRESSION_TYPE_INTEGER:
             strlcpy($$, "i", MAX_FUNCTION_ARGS);
@@ -754,7 +755,7 @@ arguments_list
         }
         else
         {
-          switch($3)
+          switch($3.type)
           {
             case EXPRESSION_TYPE_INTEGER:
               strlcat($1, "i", MAX_FUNCTION_ARGS);
@@ -818,7 +819,7 @@ regexp
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_REGEXP;
+        $$.type = EXPRESSION_TYPE_REGEXP;
       }
     ;
 
@@ -826,7 +827,7 @@ regexp
 boolean_expression
     : expression
       {
-        if ($1 == EXPRESSION_TYPE_STRING)
+        if ($1.type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -836,8 +837,7 @@ boolean_expression
           ERROR_IF(compiler->last_result != ERROR_SUCCESS);
         }
 
-
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     ;
 
@@ -849,7 +849,7 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _FALSE_
       {
@@ -858,7 +858,7 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _MATCHES_ regexp
       {
@@ -873,7 +873,7 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _CONTAINS_ primary_expression
       {
@@ -887,20 +887,21 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _STRING_IDENTIFIER_
       {
         int result = yr_parser_reduce_string_identifier(
             yyscanner,
             $1,
-            OP_STR_FOUND);
+            OP_STR_FOUND,
+            UNDEFINED);
 
         yr_free($1);
 
         ERROR_IF(result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _STRING_IDENTIFIER_ _AT_ primary_expression
       {
@@ -909,26 +910,28 @@ expression
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             $1,
-            OP_STR_FOUND_AT);
+            OP_STR_FOUND_AT,
+            $3.value.integer);
 
         yr_free($1);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _STRING_IDENTIFIER_ _IN_ range
       {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             $1,
-            OP_STR_FOUND_IN);
+            OP_STR_FOUND_IN,
+            UNDEFINED);
 
         yr_free($1);
 
         ERROR_IF(compiler->last_result!= ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _FOR_ for_expression _IDENTIFIER_ _IN_
       {
@@ -1074,7 +1077,7 @@ expression
         compiler->loop_identifier[compiler->loop_depth] = NULL;
         yr_free($3);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _FOR_ for_expression _OF_ string_set ':'
       {
@@ -1150,26 +1153,26 @@ expression
 
         yr_parser_emit(yyscanner, OP_LE, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
 
       }
     | for_expression _OF_ string_set
       {
         yr_parser_emit(yyscanner, OP_OF, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | _NOT_ boolean_expression
       {
         yr_parser_emit(yyscanner, OP_NOT, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | boolean_expression _AND_ boolean_expression
       {
         yr_parser_emit(yyscanner, OP_AND, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | boolean_expression _OR_ boolean_expression
       {
@@ -1177,7 +1180,7 @@ expression
 
         yr_parser_emit(yyscanner, OP_OR, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _LT_ primary_expression
       {
@@ -1186,7 +1189,7 @@ expression
 
         yr_parser_emit(yyscanner, OP_LT, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _GT_ primary_expression
       {
@@ -1195,7 +1198,7 @@ expression
 
         yr_parser_emit(yyscanner, OP_GT, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _LE_ primary_expression
       {
@@ -1204,7 +1207,7 @@ expression
 
         yr_parser_emit(yyscanner, OP_LE, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _GE_ primary_expression
       {
@@ -1213,17 +1216,17 @@ expression
 
         yr_parser_emit(yyscanner, OP_GE, NULL);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _EQ_ primary_expression
       {
-        if ($1 != $3)
+        if ($1.type != $3.type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for == operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ($1 == EXPRESSION_TYPE_STRING)
+        else if ($1.type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -1240,17 +1243,17 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _IS_ primary_expression
       {
-        if ($1 != $3)
+        if ($1.type != $3.type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for == operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ($1 == EXPRESSION_TYPE_STRING)
+        else if ($1.type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -1267,17 +1270,17 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression _NEQ_ primary_expression
       {
-        if ($1 != $3)
+        if ($1.type != $3.type)
         {
           yr_compiler_set_error_extra_info(
               compiler, "mismatching types for != operator");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
-        else if ($1 == EXPRESSION_TYPE_STRING)
+        else if ($1.type == EXPRESSION_TYPE_STRING)
         {
           compiler->last_result = yr_parser_emit(
               yyscanner,
@@ -1294,7 +1297,7 @@ expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_BOOLEAN;
+        $$.type = EXPRESSION_TYPE_BOOLEAN;
       }
     | primary_expression
       {
@@ -1316,14 +1319,14 @@ integer_set
 range
     : '(' primary_expression '.' '.'  primary_expression ')'
       {
-        if ($2 != EXPRESSION_TYPE_INTEGER)
+        if ($2.type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for range's lower bound");
           compiler->last_result = ERROR_WRONG_TYPE;
         }
 
-        if ($5 != EXPRESSION_TYPE_INTEGER)
+        if ($5.type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for range's upper bound");
@@ -1338,7 +1341,7 @@ range
 integer_enumeration
     : primary_expression
       {
-        if ($1 != EXPRESSION_TYPE_INTEGER)
+        if ($1.type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for enumeration item");
@@ -1350,7 +1353,7 @@ integer_enumeration
       }
     | integer_enumeration ',' primary_expression
       {
-        if ($3 != EXPRESSION_TYPE_INTEGER)
+        if ($3.type != EXPRESSION_TYPE_INTEGER)
         {
           yr_compiler_set_error_extra_info(
               compiler, "wrong type for enumeration item");
@@ -1420,9 +1423,10 @@ primary_expression
         compiler->last_result = yr_parser_emit(
             yyscanner, OP_FILESIZE, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
-
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
+
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _ENTRYPOINT_
       {
@@ -1434,9 +1438,10 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
-    | _INT8_  '(' primary_expression ')'
+    | _INT8_ '(' primary_expression ')'
       {
         CHECK_TYPE($3, EXPRESSION_TYPE_INTEGER, "int8");
 
@@ -1445,7 +1450,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _INT16_ '(' primary_expression ')'
       {
@@ -1456,7 +1462,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _INT32_ '(' primary_expression ')'
       {
@@ -1467,7 +1474,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _UINT8_ '(' primary_expression ')'
       {
@@ -1478,7 +1486,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _UINT16_ '(' primary_expression ')'
       {
@@ -1489,7 +1498,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _UINT32_ '(' primary_expression ')'
       {
@@ -1500,7 +1510,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _NUMBER_
       {
@@ -1509,7 +1520,8 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = $1;
       }
     | _TEXT_STRING_
       {
@@ -1532,33 +1544,37 @@ primary_expression
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_STRING;
+        $$.type = EXPRESSION_TYPE_STRING;
       }
     | _STRING_COUNT_
       {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             $1,
-            OP_STR_COUNT);
+            OP_STR_COUNT,
+            UNDEFINED);
 
         yr_free($1);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _STRING_OFFSET_ '[' primary_expression ']'
       {
         compiler->last_result = yr_parser_reduce_string_identifier(
             yyscanner,
             $1,
-            OP_STR_OFFSET);
+            OP_STR_OFFSET,
+            UNDEFINED);
 
         yr_free($1);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | _STRING_OFFSET_
       {
@@ -1572,23 +1588,26 @@ primary_expression
           compiler->last_result = yr_parser_reduce_string_identifier(
               yyscanner,
               $1,
-              OP_STR_OFFSET);
+              OP_STR_OFFSET,
+              UNDEFINED);
 
         yr_free($1);
 
         ERROR_IF(compiler->last_result != ERROR_SUCCESS);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = UNDEFINED;
       }
     | identifier
       {
         if ($1 == (YR_OBJECT*) -1)  // loop identifier
         {
-          $$ = EXPRESSION_TYPE_INTEGER;
+          $$.type = EXPRESSION_TYPE_INTEGER;
+          $$.value.integer = UNDEFINED;
         }
         else if ($1 == (YR_OBJECT*) -2)  // rule identifier
         {
-          $$ = EXPRESSION_TYPE_BOOLEAN;
+          $$.type = EXPRESSION_TYPE_BOOLEAN;
         }
         else if ($1 != NULL)
         {
@@ -1598,10 +1617,11 @@ primary_expression
           switch($1->type)
           {
             case OBJECT_TYPE_INTEGER:
-              $$ = EXPRESSION_TYPE_INTEGER;
+              $$.type = EXPRESSION_TYPE_INTEGER;
+              $$.value.integer = UNDEFINED;
               break;
             case OBJECT_TYPE_STRING:
-              $$ = EXPRESSION_TYPE_STRING;
+              $$.type = EXPRESSION_TYPE_STRING;
               break;
             default:
               assert(FALSE);
@@ -1622,7 +1642,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_ADD, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(+, $1.value.integer, $3.value.integer);
       }
     | primary_expression '-' primary_expression
       {
@@ -1631,7 +1652,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_SUB, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(-, $1.value.integer, $3.value.integer);
       }
     | primary_expression '*' primary_expression
       {
@@ -1640,7 +1662,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_MUL, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(*, $1.value.integer, $3.value.integer);
       }
     | primary_expression '\\' primary_expression
       {
@@ -1649,7 +1672,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_DIV, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(/, $1.value.integer, $3.value.integer);
       }
     | primary_expression '%' primary_expression
       {
@@ -1658,7 +1682,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_MOD, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(%, $1.value.integer, $3.value.integer);
       }
     | primary_expression '^' primary_expression
       {
@@ -1667,7 +1692,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_XOR, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(^, $1.value.integer, $3.value.integer);
       }
     | primary_expression '&' primary_expression
       {
@@ -1676,7 +1702,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_AND, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(&, $1.value.integer, $3.value.integer);
       }
     | primary_expression '|' primary_expression
       {
@@ -1685,7 +1712,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_OR, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(|, $1.value.integer, $3.value.integer);
       }
     | '~' primary_expression
       {
@@ -1693,7 +1721,9 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_NEG, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = ($2.value.integer == UNDEFINED) ?
+                              UNDEFINED : $2.value.integer;
       }
     | primary_expression _SHIFT_LEFT_ primary_expression
       {
@@ -1702,7 +1732,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_SHL, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(<<, $1.value.integer, $3.value.integer);
       }
     | primary_expression _SHIFT_RIGHT_ primary_expression
       {
@@ -1711,7 +1742,8 @@ primary_expression
 
         yr_parser_emit(yyscanner, OP_SHR, NULL);
 
-        $$ = EXPRESSION_TYPE_INTEGER;
+        $$.type = EXPRESSION_TYPE_INTEGER;
+        $$.value.integer = OPERATION(>>, $1.value.integer, $3.value.integer);
       }
     | regexp
       {
diff --git a/libyara/include/yara/exec.h b/libyara/include/yara/exec.h
index 7fbe7ac..97b3012 100644
--- a/libyara/include/yara/exec.h
+++ b/libyara/include/yara/exec.h
@@ -85,6 +85,14 @@ limitations under the License.
 #define OP_IMPORT         55
 
 
+#define OPERATION(operator, op1, op2) \
+    (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (UNDEFINED) : (op1 operator op2)
+
+
+#define COMPARISON(operator, op1, op2) \
+    (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (0) : (op1 operator op2)
+
+
 int yr_execute_code(
     YR_RULES* rules,
     YR_SCAN_CONTEXT* context,
diff --git a/libyara/include/yara/lexer.h b/libyara/include/yara/lexer.h
index b2d708f..fb9bf88 100644
--- a/libyara/include/yara/lexer.h
+++ b/libyara/include/yara/lexer.h
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 #include <yara/compiler.h>
-#include <grammar.h>
+
 
 #undef yyparse
 #undef yylex
@@ -48,9 +48,26 @@ limitations under the License.
 typedef void* yyscan_t;
 #endif
 
+#ifndef YY_TYPEDEF_EXPRESSION_T
+#define YY_TYPEDEF_EXPRESSION_T
+
+typedef struct _EXPRESSION
+{
+  int type;
+
+  union {
+    int64_t integer;
+  } value;
+
+} EXPRESSION;
+
+union YYSTYPE;
+
+#endif
+
 
 #define YY_DECL int yylex( \
-    YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler)
+    union YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler)
 
 
 #define YY_FATAL_ERROR(msg) yara_yyfatal(yyscanner, msg)
@@ -63,7 +80,7 @@ typedef void* yyscan_t;
 int yyget_lineno(yyscan_t yyscanner);
 
 int yylex(
-    YYSTYPE* yylval_param,
+    union YYSTYPE* yylval_param,
     yyscan_t yyscanner,
     YR_COMPILER* compiler);
 
diff --git a/libyara/include/yara/parser.h b/libyara/include/yara/parser.h
index 6625897..a032c98 100644
--- a/libyara/include/yara/parser.h
+++ b/libyara/include/yara/parser.h
@@ -84,7 +84,8 @@ YR_META* yr_parser_reduce_meta_declaration(
 int yr_parser_reduce_string_identifier(
     yyscan_t yyscanner,
     const char* identifier,
-    int8_t instruction);
+    int8_t instruction,
+    uint64_t at_offset);
 
 
 int yr_parser_emit_pushes_for_strings(
diff --git a/libyara/include/yara/types.h b/libyara/include/yara/types.h
index 0e2c284..32c8186 100644
--- a/libyara/include/yara/types.h
+++ b/libyara/include/yara/types.h
@@ -117,6 +117,7 @@ typedef struct _YR_MATCHES
 #define STRING_GFLAGS_NULL              0x1000
 #define STRING_GFLAGS_CHAIN_PART        0x2000
 #define STRING_GFLAGS_CHAIN_TAIL        0x4000
+#define STRING_GFLAGS_FIXED_OFFSET      0x8000
 
 
 #define STRING_IS_HEX(x) \
@@ -146,6 +147,9 @@ typedef struct _YR_MATCHES
 #define STRING_IS_SINGLE_MATCH(x) \
     (((x)->g_flags) & STRING_GFLAGS_SINGLE_MATCH)
 
+#define STRING_IS_FIXED_OFFSET(x) \
+    (((x)->g_flags) & STRING_GFLAGS_FIXED_OFFSET)
+
 #define STRING_IS_LITERAL(x) \
     (((x)->g_flags) & STRING_GFLAGS_LITERAL)
 
@@ -183,6 +187,8 @@ typedef struct _YR_STRING
   int32_t chain_gap_min;
   int32_t chain_gap_max;
 
+  int64_t fixed_offset;
+
   YR_MATCHES matches[MAX_THREADS];
   YR_MATCHES unconfirmed_matches[MAX_THREADS];
 
diff --git a/libyara/parser.c b/libyara/parser.c
index 87e7931..3f8dd5a 100644
--- a/libyara/parser.c
+++ b/libyara/parser.c
@@ -329,6 +329,7 @@ int _yr_parser_write_string(
 
   (*string)->g_flags = flags;
   (*string)->chained_to = NULL;
+  (*string)->fixed_offset = UNDEFINED;
 
   #ifdef PROFILING_ENABLED
   (*string)->clock_ticks = 0;
@@ -489,6 +490,14 @@ YR_STRING* yr_parser_reduce_string_declaration(
 
   string_flags |= STRING_GFLAGS_SINGLE_MATCH;
 
+  // The STRING_GFLAGS_FIXED_OFFSET indicates that the string doesn't
+  // need to be searched all over the file because the user is using the
+  // "at" operator. The string must be searched at a fixed offset in the
+  // file. All strings are marked STRING_GFLAGS_FIXED_OFFSET initially,
+  // and unmarked later if required.
+
+  string_flags |= STRING_GFLAGS_FIXED_OFFSET;
+
   if (string_flags & STRING_GFLAGS_HEXADECIMAL ||
       string_flags & STRING_GFLAGS_REGEXP)
   {
@@ -730,14 +739,15 @@ int yr_parser_reduce_rule_declaration(
 int yr_parser_reduce_string_identifier(
     yyscan_t yyscanner,
     const char* identifier,
-    int8_t instruction)
+    int8_t instruction,
+    uint64_t at_offset)
 {
   YR_STRING* string;
   YR_COMPILER* compiler = yyget_extra(yyscanner);
 
-  if (strcmp(identifier, "$") == 0)
+  if (strcmp(identifier, "$") == 0) // is an anonymous string ?
   {
-    if (compiler->loop_for_of_mem_offset >= 0)
+    if (compiler->loop_for_of_mem_offset >= 0) // inside a loop ?
     {
       yr_parser_emit_with_arg(
           yyscanner,
@@ -747,22 +757,41 @@ int yr_parser_reduce_string_identifier(
 
       yr_parser_emit(yyscanner, instruction, NULL);
 
-      if (instruction != OP_STR_FOUND)
+      string = compiler->current_rule_strings;
+
+      while(!STRING_IS_NULL(string))
       {
-        string = compiler->current_rule_strings;
+        if (instruction != OP_STR_FOUND)
+          string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH;
 
-        while(!STRING_IS_NULL(string))
+        if (instruction == OP_STR_FOUND_AT)
         {
-          string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH;
-          string = yr_arena_next_address(
-              compiler->strings_arena,
-              string,
-              sizeof(YR_STRING));
+          // Avoid overwriting any previous fixed offset
+
+          if (string->fixed_offset == UNDEFINED)
+            string->fixed_offset = at_offset;
+
+          // If a previous fixed offset was different, disable
+          // the STRING_GFLAGS_FIXED_OFFSET flag because we only
+          // have room to store a single fixed offset value
+
+          if (string->fixed_offset != at_offset)
+            string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
+        }
+        else
+        {
+          string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
         }
+
+        string = yr_arena_next_address(
+            compiler->strings_arena,
+            string,
+            sizeof(YR_STRING));
       }
     }
     else
     {
+      // Anonymous strings not allowed outside of a loop
       compiler->last_result = ERROR_MISPLACED_ANONYMOUS_STRING;
     }
   }
@@ -781,6 +810,25 @@ int yr_parser_reduce_string_identifier(
       if (instruction != OP_STR_FOUND)
         string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH;
 
+      if (instruction == OP_STR_FOUND_AT)
+      {
+        // Avoid overwriting any previous fixed offset
+
+        if (string->fixed_offset == UNDEFINED)
+          string->fixed_offset = at_offset;
+
+        // If a previous fixed offset was different, disable
+        // the STRING_GFLAGS_FIXED_OFFSET flag because we only
+        // have room to store a single fixed offset value
+
+        if (string->fixed_offset != at_offset)
+          string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
+      }
+      else
+      {
+        string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
+      }
+
       yr_parser_emit(yyscanner, instruction, NULL);
 
       string->g_flags |= STRING_GFLAGS_REFERENCED;
diff --git a/libyara/scan.c b/libyara/scan.c
index 44ddf5c..abce84c 100644
--- a/libyara/scan.c
+++ b/libyara/scan.c
@@ -858,6 +858,10 @@ int yr_scan_verify_match(
       STRING_FOUND(string))
     return ERROR_SUCCESS;
 
+  if (STRING_IS_FIXED_OFFSET(string) &&
+      string->fixed_offset != data_base + offset)
+    return ERROR_SUCCESS;
+
   if (STRING_IS_LITERAL(string))
   {
     FAIL_ON_ERROR(_yr_scan_verify_literal_match(

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/forensics/yara.git



More information about the forensics-changes mailing list