From ae32792b881853979265e41b49866be9ea2d6b2c Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 2 Jan 2014 01:00:07 +0100 Subject: [PATCH] frontend: Let sdb_fe_parse() return a list of parsed node objects. Each parse-tree node object represents a single command. --- src/frontend/grammar.y | 37 ++++++++++++++++++++++++++++--- src/frontend/parser.c | 28 +++++++++++++++-------- src/frontend/scanner.l | 7 +++++- src/include/frontend/connection.h | 34 ++++++++++++++++++++++++++-- src/include/frontend/parser.h | 10 ++++++++- t/frontend/parser_test.c | 29 +++++++++++++++++------- 6 files changed, 121 insertions(+), 24 deletions(-) diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index ef88272..876f48a 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -27,15 +27,24 @@ %{ +#include "frontend/connection.h" #include "frontend/parser.h" #include "frontend/grammar.h" + #include "utils/error.h" +#include "utils/llist.h" #include +sdb_fe_yyextra_t * +sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner); + void 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 + %} %pure-parser @@ -46,35 +55,57 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %expect 0 %name-prefix="sdb_fe_yy" +%union { + sdb_llist_t *list; + sdb_conn_node_t *node; +} + %start statements %token SCANNER_ERROR %token IDENTIFIER -%token LIST +%token LIST + +%type statements +%type statement + list_statement %% statements: statements ';' statement { + if ($3) { + sdb_llist_append(pt, SDB_OBJ($3)); + sdb_object_deref(SDB_OBJ($3)); + } } | statement { + if ($1) { + sdb_llist_append(pt, SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($1)); + } } ; statement: list_statement - { - } | /* empty */ + { + $$ = NULL; + } ; list_statement: LIST + { + $$ = sdb_object_create_T(/* name = */ NULL, sdb_conn_node_t); + ((sdb_conn_node_t *)$$)->cmd = CONNECTION_LIST; + } ; %% diff --git a/src/frontend/parser.c b/src/frontend/parser.c index b970e73..037550f 100644 --- a/src/frontend/parser.c +++ b/src/frontend/parser.c @@ -27,9 +27,11 @@ #include "sysdb.h" +#include "frontend/connection-private.h" #include "frontend/parser.h" #include "frontend/grammar.h" -#include "frontend/connection-private.h" + +#include "utils/llist.h" #include @@ -37,25 +39,33 @@ * public API */ -int +sdb_llist_t * sdb_fe_parse(const char *query) { sdb_fe_yyscan_t scanner; + sdb_fe_yyextra_t yyextra; int yyres; if (! query) - return -1; + return NULL; + + memset(&yyextra, 0, sizeof(yyextra)); + yyextra.parsetree = sdb_llist_create(); - scanner = sdb_fe_scanner_init(query); - if (! scanner) - return -1; + scanner = sdb_fe_scanner_init(query, &yyextra); + if (! scanner) { + sdb_llist_destroy(yyextra.parsetree); + return NULL; + } yyres = sdb_fe_yyparse(scanner); sdb_fe_scanner_destroy(scanner); - if (yyres) - return -1; - return 0; + if (yyres) { + sdb_llist_destroy(yyextra.parsetree); + return NULL; + } + return yyextra.parsetree; } /* sdb_fe_parse */ /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index cd7ea85..f300e46 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -27,6 +27,7 @@ %{ +#include "frontend/connection.h" #include "frontend/parser.h" #include "frontend/grammar.h" #include "utils/error.h" @@ -35,6 +36,8 @@ #include +#define YY_EXTRA_TYPE sdb_fe_yyextra_t * + void sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); @@ -94,7 +97,7 @@ identifier ([A-Za-z_][A-Za-z_0-9$]*) %% sdb_fe_yyscan_t -sdb_fe_scanner_init(const char *str) +sdb_fe_scanner_init(const char *str, sdb_fe_yyextra_t *yyext) { yyscan_t scanner; @@ -105,6 +108,8 @@ sdb_fe_scanner_init(const char *str) return NULL; } + sdb_fe_yyset_extra(yyext, scanner); + /* the newly allocated buffer state (YY_BUFFER_STATE) is stored inside the * scanner and, thus, will be freed by yylex_destroy */ yy_scan_string(str, scanner); diff --git a/src/include/frontend/connection.h b/src/include/frontend/connection.h index bdebe7d..c4478fb 100644 --- a/src/include/frontend/connection.h +++ b/src/include/frontend/connection.h @@ -29,6 +29,7 @@ #define SDB_FRONTEND_CONNECTION_H 1 #include "frontend/proto.h" +#include "utils/llist.h" #include "utils/strbuf.h" #include @@ -39,6 +40,18 @@ extern "C" { typedef struct sdb_conn sdb_conn_t; +/* + * sdb_conn_node_t represents an interface for the result of parsing a command + * string. The first field of an actual implementation of the interface is a + * sdb_conn_state_t in order to fascilitate casting to and from the interface + * type to the implementation type. + */ +typedef struct { + sdb_object_t super; + sdb_conn_state_t cmd; +} sdb_conn_node_t; +#define SDB_CONN_NODE(obj) ((sdb_conn_node_t *)(obj)) + /* * sdb_connection_accpet: * Accept a new connection on the specified file-descriptor 'fd' and return a @@ -95,11 +108,28 @@ sdb_connection_ping(sdb_conn_t *conn); /* * sdb_fe_parse: - * Parse the query text specified in 'query'. + * Parse the query text specified in 'query' and return a list of parse trees + * (for each command) to be executed by sdb_fe_exec. The list has to be freed + * by the caller. + * + * Returns: + * - an sdb_llist_t object of sdb_conn_node_t on success + * - NULL in case of an error */ -int +sdb_llist_t * sdb_fe_parse(const char *query); +/* + * sdb_fe_exec: + * Execute the command identified by 'node'. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_fe_exec(sdb_conn_node_t *node); + /* * session handling */ diff --git a/src/include/frontend/parser.h b/src/include/frontend/parser.h index 5491e9c..a80969c 100644 --- a/src/include/frontend/parser.h +++ b/src/include/frontend/parser.h @@ -28,15 +28,23 @@ #ifndef SDB_FRONTEND_PARSER_H #define SDB_FRONTEND_PARSER_H 1 +#include "utils/llist.h" + #ifdef __cplusplus extern "C" { #endif +/* YY_EXTRA data */ +typedef struct { + /* list of sdb_conn_node_t objects */ + sdb_llist_t *parsetree; +} sdb_fe_yyextra_t; + /* see yyscan_t */ typedef void *sdb_fe_yyscan_t; sdb_fe_yyscan_t -sdb_fe_scanner_init(const char *str); +sdb_fe_scanner_init(const char *str, sdb_fe_yyextra_t *yyext); void sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner); diff --git a/t/frontend/parser_test.c b/t/frontend/parser_test.c index bebe15e..444c8a7 100644 --- a/t/frontend/parser_test.c +++ b/t/frontend/parser_test.c @@ -47,8 +47,8 @@ START_TEST(test_parse) { ";;", 0 }, /* valid commands */ - { "LIST", 0 }, - { "LIST;", 0 }, + { "LIST", 1 }, + { "LIST;", 1 }, /* comments */ { "/* some comment */", 0 }, @@ -60,19 +60,32 @@ START_TEST(test_parse) }; size_t i; - int check; + sdb_llist_t *check; for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { _Bool ok; check = sdb_fe_parse(golden_data[i].query); if (golden_data[i].expected < 0) - ok = check < 0; + ok = check == 0; else - ok = check == golden_data[i].expected; - - fail_unless(ok, "sdb_fe_parse(%s) = %d; expected: %d", - golden_data[i].query, check, golden_data[i].expected); + ok = sdb_llist_len(check) == (size_t)golden_data[i].expected; + + fail_unless(ok, "sdb_fe_parse(%s) = %p (len: %zu); expected: %d", + golden_data[i].query, check, sdb_llist_len(check), + golden_data[i].expected); + + if (! check) + continue; + + if ((! strcmp(golden_data[i].query, "LIST")) + || (! strcmp(golden_data[i].query, "LIST;"))) { + sdb_object_t *obj = sdb_llist_get(check, 0); + fail_unless(SDB_CONN_NODE(obj)->cmd == CONNECTION_LIST, + "sdb_fe_parse(LIST)->cmd = %i; expected: %d " + "(CONNECTION_LIST)", SDB_CONN_NODE(obj)->cmd, + CONNECTION_LIST); + } } } END_TEST -- 2.30.2