From 0d93606de8723dfe170b43883b9edc09f2bf060d Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Mon, 28 Jul 2014 00:27:12 +0200 Subject: [PATCH] frontend: Added a parser for arithmetic expressions. 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 | 88 ++++++++++++++++++++++++++++++++--- src/frontend/scanner.l | 1 + t/unit/frontend/parser_test.c | 7 ++- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index e0d8e7e..0afbd9e 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -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 matcher compare_matcher +%type expression + %type op %type data %destructor { free($$); } -%destructor { sdb_object_deref(SDB_OBJ($$)); } +%destructor { sdb_object_deref(SDB_OBJ($$)); } %% @@ -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 { $$ = "="; } | diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index ef30682..5e80368 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -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]; } diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index 3ca27ba..59de563 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -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 }, -- 2.30.2