Code

frontend: Added a parser for arithmetic expressions.
authorSebastian Harl <sh@tokkee.org>
Sun, 27 Jul 2014 22:27:12 +0000 (00:27 +0200)
committerSebastian Harl <sh@tokkee.org>
Sun, 27 Jul 2014 22:27:12 +0000 (00:27 +0200)
For now, the expressions are used in place of a datum but the parser will
actually evaluate the expression before passing it on to the store during
lookup. Since expressions currently cover constant results only, this is not a
limitation for now.

src/frontend/grammar.y
src/frontend/scanner.l
t/unit/frontend/parser_test.c

index e0d8e7ecc46136b01cb84546ba1d3e11d7fb9e2b..0afbd9edb32461c00eb36f2248d0259204b1d930 100644 (file)
@@ -75,6 +75,7 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
        sdb_conn_node_t *node;
 
        sdb_store_matcher_t *m;
+       sdb_store_expr_t *expr;
 }
 
 %start statements
@@ -84,6 +85,7 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
 %token AND OR IS NOT MATCHING
 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
 %token CMP_LT CMP_LE CMP_GE CMP_GT
+%token CONCAT
 
 /* NULL token */
 %token NULL_T
@@ -101,7 +103,10 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
 %left CMP_EQUAL CMP_NEQUAL
 %left CMP_LT CMP_LE CMP_GE CMP_GT
 %nonassoc CMP_REGEX CMP_NREGEX
+%left CONCAT
 %nonassoc IS
+%left '+' '-'
+%left '*' '/' '%'
 %left '(' ')'
 %left '.'
 
@@ -115,12 +120,14 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
 %type <m> matcher
        compare_matcher
 
+%type <expr> expression
+
 %type <sstr> op
 
 %type <data> data
 
 %destructor { free($$); } <str>
-%destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m>
+%destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
 
 %%
 
@@ -302,19 +309,38 @@ matcher:
  * Parse matchers comparing object attributes with a value.
  */
 compare_matcher:
-       IDENTIFIER op data
+       IDENTIFIER op expression
                {
-                       $$ = sdb_store_matcher_parse_cmp($1, NULL, $2, &$3);
+                       sdb_data_t value = SDB_DATA_INIT;
+                       if (sdb_store_expr_eval($3, &value)) {
+                               sdb_object_deref(SDB_OBJ($3));
+                               free($1); $1 = NULL;
+                               sdb_fe_yyerror(&yylloc, scanner,
+                                               YY_("syntax error, failed to evaluate expression"));
+                               YYABORT;
+                       }
+                       sdb_object_deref(SDB_OBJ($3));
+                       $$ = sdb_store_matcher_parse_cmp($1, NULL, $2, &value);
                        free($1); $1 = NULL;
-                       sdb_data_free_datum(&$3);
+                       sdb_data_free_datum(&value);
                }
        |
-       IDENTIFIER '.' IDENTIFIER op data
+       IDENTIFIER '.' IDENTIFIER op expression
                {
-                       $$ = sdb_store_matcher_parse_cmp($1, $3, $4, &$5);
+                       sdb_data_t value = SDB_DATA_INIT;
+                       if (sdb_store_expr_eval($5, &value)) {
+                               sdb_object_deref(SDB_OBJ($5));
+                               free($1); $1 = NULL;
+                               free($3); $3 = NULL;
+                               sdb_fe_yyerror(&yylloc, scanner,
+                                               YY_("syntax error, failed to evaluate expression"));
+                               YYABORT;
+                       }
+                       sdb_object_deref(SDB_OBJ($5));
+                       $$ = sdb_store_matcher_parse_cmp($1, $3, $4, &value);
                        free($1); $1 = NULL;
                        free($3); $3 = NULL;
-                       sdb_data_free_datum(&$5);
+                       sdb_data_free_datum(&value);
                }
        |
        IDENTIFIER '.' IDENTIFIER IS NULL_T
@@ -337,6 +363,54 @@ compare_matcher:
                }
        ;
 
+expression:
+       '(' expression ')'
+               {
+                       $$ = $2;
+               }
+       |
+       expression '+' expression
+               {
+                       $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
+                       sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
+                       sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
+               }
+       |
+       expression '-' expression
+               {
+                       $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
+                       sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
+                       sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
+               }
+       |
+       expression '*' expression
+               {
+                       $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
+                       sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
+                       sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
+               }
+       |
+       expression '/' expression
+               {
+                       $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
+                       sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
+                       sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
+               }
+       |
+       expression '%' expression
+               {
+                       $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
+                       sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
+                       sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
+               }
+       |
+       data
+               {
+                       $$ = sdb_store_expr_constvalue(&$1);
+                       sdb_data_free_datum(&$1);
+               }
+       ;
+
 op:
        CMP_EQUAL { $$ = "="; }
        |
index ef30682b45b837f8cb931f1e7257f7568ddd3f2b..5e80368d532872198edb7ea7bfb45dd60a9f0225 100644 (file)
@@ -150,6 +150,7 @@ float               ({float1}|{float2}|{float3}|{float4}|{float5})
 \<=    { return CMP_LE; }
 \>=    { return CMP_GE; }
 \>     { return CMP_GT; }
+\|\|   { return CONCAT; }
 
 .      { /* XXX: */ return yytext[0]; }
 
index 3ca27ba19ffb47ec637575469b398c7d85d10961..59de563f760c74e291ec47998081b03344c442c4 100644 (file)
@@ -92,7 +92,7 @@ START_TEST(test_parse)
                  "12.4",                -1,  1, CONNECTION_LOOKUP },
                { "LOOKUP hosts MATCHING "
                  "attribute.foo <= "
-                 "12.",                 -1,  1, CONNECTION_LOOKUP },
+                 "12. + .3",            -1,  1, CONNECTION_LOOKUP },
                { "LOOKUP hosts MATCHING "
                  "attribute.foo >= "
                  ".4",                  -1,  1, CONNECTION_LOOKUP },
@@ -139,6 +139,11 @@ START_TEST(test_parse)
                  "attribute.foo = "
                  "0x12",                -1, -1, 0 },
 
+               /* invalid expressions */
+               { "LOOKUP hosts MATCHING "
+                 "attribute.foo = "
+                 "1.23 + 'foo'",        -1, -1, 0 },
+
                /* comments */
                { "/* some comment */",  -1,  0, 0 },
                { "-- another comment",  -1,  0, 0 },