From: Sebastian Harl Date: Fri, 7 Mar 2014 11:47:06 +0000 (+0100) Subject: frontend parser: Added support for parsing single expressions. X-Git-Tag: sysdb-0.1.0~173 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=e7edc6432f63f36a2508b4c426876593678c8434 frontend parser: Added support for parsing single expressions. The parser has been extended to support different modes. In SDB_PARSE_EXPR mode, a single expression will be accepted as a start condition. The new function sdb_fe_parse_matcher() uses this to parse expressions. For now, this implements only the basic framework. Any identifier will be parsed as a simple name matcher expression. --- diff --git a/src/frontend/connection-private.h b/src/frontend/connection-private.h index 39fc852..82cece9 100644 --- a/src/frontend/connection-private.h +++ b/src/frontend/connection-private.h @@ -32,9 +32,11 @@ #ifndef SDB_FRONTEND_CONNECTION_PRIVATE_H #define SDB_FRONTEND_CONNECTION_PRIVATE_H 1 +#include "frontend/connection.h" + #include "core/object.h" +#include "core/store.h" #include "utils/strbuf.h" -#include "frontend/connection.h" #include #include @@ -67,6 +69,16 @@ struct sdb_conn { }; #define CONN(obj) ((sdb_conn_t *)(obj)) +/* + * node types + */ + +typedef struct { + sdb_conn_node_t super; + sdb_store_matcher_t *matcher; +} conn_node_matcher_t; +#define CONN_MATCHER(obj) ((conn_node_matcher_t *)(obj)) + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index e6c627b..f262f3e 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -27,10 +27,12 @@ %{ -#include "frontend/connection.h" +#include "frontend/connection-private.h" #include "frontend/parser.h" #include "frontend/grammar.h" +#include "core/store.h" + #include "utils/error.h" #include "utils/llist.h" @@ -48,6 +50,9 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); /* quick access to the current parse tree */ #define pt sdb_fe_yyget_extra(scanner)->parsetree +/* quick access to the parser mode */ +#define parser_mode sdb_fe_yyget_extra(scanner)->mode + %} %pure-parser @@ -59,6 +64,8 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %name-prefix="sdb_fe_yy" %union { + char *str; + sdb_llist_t *list; sdb_conn_node_t *node; } @@ -67,12 +74,13 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %token SCANNER_ERROR -%token IDENTIFIER +%token IDENTIFIER %token LIST %type statements %type statement list_statement + expression %% @@ -87,6 +95,22 @@ statements: | statement { + if ($1) { + sdb_llist_append(pt, SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($1)); + } + } + | + expression + { + /* only accept this in expression parse mode */ + if (! (parser_mode & SDB_PARSE_EXPR)) { + sdb_fe_yyerror(&yylloc, scanner, + YY_("syntax error, unexpected expression, " + "expecting statement")); + YYABORT; + } + if ($1) { sdb_llist_append(pt, SDB_OBJ($1)); sdb_object_deref(SDB_OBJ($1)); @@ -108,7 +132,22 @@ list_statement: { $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL, sdb_conn_node_t)); - ((sdb_conn_node_t *)$$)->cmd = CONNECTION_LIST; + $$->cmd = CONNECTION_LIST; + } + ; + +expression: + IDENTIFIER + { + $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL, + conn_node_matcher_t)); + $$->cmd = CONNECTION_EXPR; + /* XXX: this is just a placeholder for now */ + CONN_MATCHER($$)->matcher = sdb_store_host_matcher($1, + /* name_re = */ NULL, /* service = */ NULL, + /* attr = */ NULL); + free($1); + $1 = NULL; } ; diff --git a/src/frontend/parser.c b/src/frontend/parser.c index 718ed68..e8c0cde 100644 --- a/src/frontend/parser.c +++ b/src/frontend/parser.c @@ -31,10 +31,38 @@ #include "frontend/parser.h" #include "frontend/grammar.h" +#include "core/store.h" + #include "utils/llist.h" #include +/* + * private helper functions + */ + +static int +scanner_init(const char *input, int len, + sdb_fe_yyscan_t *scanner, sdb_fe_yyextra_t *extra) +{ + if (! input) + return -1; + + memset(extra, 0, sizeof(*extra)); + extra->parsetree = sdb_llist_create(); + extra->mode = SDB_PARSE_DEFAULT; + + if (! extra->parsetree) + return -1; + + *scanner = sdb_fe_scanner_init(input, len, extra); + if (! scanner) { + sdb_llist_destroy(extra->parsetree); + return -1; + } + return 0; +} /* scanner_init */ + /* * public API */ @@ -46,17 +74,34 @@ sdb_fe_parse(const char *query, int len) sdb_fe_yyextra_t yyextra; int yyres; - if (! query) + if (scanner_init(query, len, &scanner, &yyextra)) return NULL; - memset(&yyextra, 0, sizeof(yyextra)); - yyextra.parsetree = sdb_llist_create(); + yyres = sdb_fe_yyparse(scanner); + sdb_fe_scanner_destroy(scanner); - scanner = sdb_fe_scanner_init(query, len, &yyextra); - if (! scanner) { + if (yyres) { sdb_llist_destroy(yyextra.parsetree); return NULL; } + return yyextra.parsetree; +} /* sdb_fe_parse */ + +sdb_store_matcher_t * +sdb_fe_parse_matcher(const char *expr, int len) +{ + sdb_fe_yyscan_t scanner; + sdb_fe_yyextra_t yyextra; + + sdb_conn_node_t *node; + sdb_store_matcher_t *m; + + int yyres; + + if (scanner_init(expr, len, &scanner, &yyextra)) + return NULL; + + yyextra.mode = SDB_PARSE_EXPR; yyres = sdb_fe_yyparse(scanner); sdb_fe_scanner_destroy(scanner); @@ -65,8 +110,19 @@ sdb_fe_parse(const char *query, int len) sdb_llist_destroy(yyextra.parsetree); return NULL; } - return yyextra.parsetree; -} /* sdb_fe_parse */ + + node = SDB_CONN_NODE(sdb_llist_get(yyextra.parsetree, 0)); + if (! node) + return NULL; + + if (node->cmd == CONNECTION_EXPR) + m = CONN_MATCHER(node)->matcher; + else + m = NULL; + + sdb_llist_destroy(yyextra.parsetree); + return m; +} /* sdb_fe_parse_matcher */ /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index 6c2bfa1..87367f6 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -93,6 +93,7 @@ identifier ([A-Za-z_][A-Za-z_0-9$]*) if (! strcasecmp(yytext, "LIST")) return LIST; + yylval->str = strdup(yytext); return IDENTIFIER; } diff --git a/src/include/core/store.h b/src/include/core/store.h index 8c46eb7..8097508 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -139,6 +139,7 @@ sdb_store_service(const char *hostname, const char *name, */ struct sdb_store_matcher; typedef struct sdb_store_matcher sdb_store_matcher_t; +#define SDB_STORE_MATCHER(obj) ((sdb_store_matcher_t *)(obj)) /* * sdb_store_attr_matcher: diff --git a/src/include/frontend/parser.h b/src/include/frontend/parser.h index 66a1a5c..738071b 100644 --- a/src/include/frontend/parser.h +++ b/src/include/frontend/parser.h @@ -28,16 +28,26 @@ #ifndef SDB_FRONTEND_PARSER_H #define SDB_FRONTEND_PARSER_H 1 +#include "core/store.h" #include "utils/llist.h" #ifdef __cplusplus extern "C" { #endif +/* parser modes */ +enum { + SDB_PARSE_DEFAULT = 0, + SDB_PARSE_EXPR, +}; + /* YY_EXTRA data */ typedef struct { /* list of sdb_conn_node_t objects */ sdb_llist_t *parsetree; + + /* parser mode */ + int mode; } sdb_fe_yyextra_t; /* see yyscan_t */ @@ -52,6 +62,9 @@ sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner); int sdb_fe_yyparse(sdb_fe_yyscan_t scanner); +sdb_store_matcher_t * +sdb_fe_parse_matcher(const char *expr, int len); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/include/frontend/proto.h b/src/include/frontend/proto.h index af336d5..76d1997 100644 --- a/src/include/frontend/proto.h +++ b/src/include/frontend/proto.h @@ -50,6 +50,9 @@ typedef enum { /* querying */ CONNECTION_QUERY, CONNECTION_LIST, + + /* command elements */ + CONNECTION_EXPR, } sdb_conn_state_t; #ifdef __cplusplus diff --git a/t/frontend/parser_test.c b/t/frontend/parser_test.c index d059474..64580b9 100644 --- a/t/frontend/parser_test.c +++ b/t/frontend/parser_test.c @@ -26,6 +26,8 @@ */ #include "frontend/connection.h" +#include "frontend/parser.h" +#include "core/object.h" #include "libsysdb_test.h" #include @@ -49,6 +51,7 @@ START_TEST(test_parse) /* valid commands */ { "LIST", -1, 1 }, + { "LIST -- comment", -1, 1 }, { "LIST;", -1, 1 }, { "LIST; INVALID", 5, 1 }, @@ -95,6 +98,48 @@ START_TEST(test_parse) } END_TEST +START_TEST(test_parse_matcher) +{ + struct { + const char *expr; + int len; + int expected; + } golden_data[] = { + /* empty expressions */ + { NULL, -1, -1 }, + { "", -1, -1 }, + + /* valid expressions */ + { "localhost", -1, 0 }, + { "localhost -- foo", -1, 0 }, + { "localhost ", 9, 0 }, + + /* syntax errors */ + { "LIST", -1, -1 }, + { "foo &^ bar", -1, -1 }, + }; + + size_t i; + sdb_store_matcher_t *m; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + _Bool ok; + + m = sdb_fe_parse_matcher(golden_data[i].expr, golden_data[i].len); + if (golden_data[i].expected < 0) + ok = m == NULL; + else + ok = m != NULL; + + fail_unless(ok, "sdb_fe_parse_matcher(%s) = %p; expected: %s", + golden_data[i].expr, m, (golden_data[i].expected < 0) + ? "NULL" : ""); + + sdb_object_deref(SDB_OBJ(m)); + } +} +END_TEST + Suite * fe_parser_suite(void) { @@ -103,6 +148,7 @@ fe_parser_suite(void) tc = tcase_create("core"); tcase_add_test(tc, test_parse); + tcase_add_test(tc, test_parse_matcher); suite_add_tcase(s, tc); return s;