Code

frontend parser: Added support for parsing single expressions.
authorSebastian Harl <sh@tokkee.org>
Fri, 7 Mar 2014 11:47:06 +0000 (12:47 +0100)
committerSebastian Harl <sh@tokkee.org>
Fri, 7 Mar 2014 11:47:06 +0000 (12:47 +0100)
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.

src/frontend/connection-private.h
src/frontend/grammar.y
src/frontend/parser.c
src/frontend/scanner.l
src/include/core/store.h
src/include/frontend/parser.h
src/include/frontend/proto.h
t/frontend/parser_test.c

index 39fc85240e7c637817f2495a1e9bea07f62737df..82cece90f00cdae17c59557f5f651979fb1c6013 100644 (file)
 #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 <inttypes.h>
 #include <arpa/inet.h>
@@ -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
index e6c627b3a4b966e288c9aadbbcf02ddfea5e0eb6..f262f3e11d9ace504a2fa08dc4b3ef8bb7c9befe 100644 (file)
 
 %{
 
-#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 <str> IDENTIFIER
 %token <node> LIST
 
 %type <list> statements
 %type <node> 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;
                }
        ;
 
index 718ed681c7dcbab31f7bc3e51540fa529a3c6bb2..e8c0cdef314c7b186110f578ec3ab84f6f9cf908 100644 (file)
 #include "frontend/parser.h"
 #include "frontend/grammar.h"
 
+#include "core/store.h"
+
 #include "utils/llist.h"
 
 #include <string.h>
 
+/*
+ * 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 : */
 
index 6c2bfa148fd802ff4365187015d7636895af86bf..87367f6e4324886fa0e2b0aa93a457c918326b68 100644 (file)
@@ -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;
        }
 
index 8c46eb740065cccde034cf39cab73e6e037e9c1e..80975087227882a4810fbc9790a15c017b2ba2db 100644 (file)
@@ -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:
index 66a1a5c4a4da8bf90f9981752961637de243725d..738071b75da0344a9b09e48cdc3e2d4226ea6135 100644 (file)
 #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
index af336d535f6bfb91bf2bf93e18c98fe8b7994390..76d1997be470b33c592f5f93aa5837656515f5c5 100644 (file)
@@ -50,6 +50,9 @@ typedef enum {
        /* querying */
        CONNECTION_QUERY,
        CONNECTION_LIST,
+
+       /* command elements */
+       CONNECTION_EXPR,
 } sdb_conn_state_t;
 
 #ifdef __cplusplus
index d05947499c4fe50803f9bf8a3e3279515e54085e..64580b9e70412aebc8800f599da6bc52f6f5d960 100644 (file)
@@ -26,6 +26,8 @@
  */
 
 #include "frontend/connection.h"
+#include "frontend/parser.h"
+#include "core/object.h"
 #include "libsysdb_test.h"
 
 #include <check.h>
@@ -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 <garbage>", 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" : "<matcher>");
+
+               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;