summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 51b387d)
raw | patch | inline | side by side (parent: 51b387d)
author | Sebastian Harl <sh@tokkee.org> | |
Fri, 7 Mar 2014 11:47:06 +0000 (12:47 +0100) | ||
committer | Sebastian 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.
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.
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>
};
#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 e6c627b3a4b966e288c9aadbbcf02ddfea5e0eb6..f262f3e11d9ace504a2fa08dc4b3ef8bb7c9befe 100644 (file)
--- a/src/frontend/grammar.y
+++ b/src/frontend/grammar.y
%{
-#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"
/* 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
%name-prefix="sdb_fe_yy"
%union {
+ char *str;
+
sdb_llist_t *list;
sdb_conn_node_t *node;
}
%token SCANNER_ERROR
-%token IDENTIFIER
+%token <str> IDENTIFIER
%token <node> LIST
%type <list> statements
%type <node> statement
list_statement
+ expression
%%
|
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));
{
$$ = 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 718ed681c7dcbab31f7bc3e51540fa529a3c6bb2..e8c0cdef314c7b186110f578ec3ab84f6f9cf908 100644 (file)
--- a/src/frontend/parser.c
+++ b/src/frontend/parser.c
#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
*/
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);
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 6c2bfa148fd802ff4365187015d7636895af86bf..87367f6e4324886fa0e2b0aa93a457c918326b68 100644 (file)
--- a/src/frontend/scanner.l
+++ b/src/frontend/scanner.l
if (! strcasecmp(yytext, "LIST"))
return LIST;
+ yylval->str = strdup(yytext);
return IDENTIFIER;
}
index 8c46eb740065cccde034cf39cab73e6e037e9c1e..80975087227882a4810fbc9790a15c017b2ba2db 100644 (file)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
*/
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 */
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)
/* querying */
CONNECTION_QUERY,
CONNECTION_LIST,
+
+ /* command elements */
+ CONNECTION_EXPR,
} sdb_conn_state_t;
#ifdef __cplusplus
index d05947499c4fe50803f9bf8a3e3279515e54085e..64580b9e70412aebc8800f599da6bc52f6f5d960 100644 (file)
--- a/t/frontend/parser_test.c
+++ b/t/frontend/parser_test.c
*/
#include "frontend/connection.h"
+#include "frontend/parser.h"
+#include "core/object.h"
#include "libsysdb_test.h"
#include <check.h>
/* valid commands */
{ "LIST", -1, 1 },
+ { "LIST -- comment", -1, 1 },
{ "LIST;", -1, 1 },
{ "LIST; INVALID", 5, 1 },
}
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)
{
tc = tcase_create("core");
tcase_add_test(tc, test_parse);
+ tcase_add_test(tc, test_parse_matcher);
suite_add_tcase(s, tc);
return s;