From 4215d1d8c69367c1d43bed9d39d428a92b329a92 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 31 Dec 2013 01:05:22 +0100 Subject: [PATCH] frontend: Added flex/bison based parser skeleton. For now, this implements a mostly empty parser and helper functions to parse strings (rather than open files). The parser accepts the "LIST" command and ignores SQL and C style comments. --- .gitignore | 3 + src/Makefile.am | 13 +++- src/frontend/grammar.y | 89 ++++++++++++++++++++++ src/frontend/parser.c | 62 +++++++++++++++ src/frontend/scanner.l | 121 ++++++++++++++++++++++++++++++ src/include/frontend/connection.h | 7 ++ src/include/frontend/parser.h | 51 +++++++++++++ src/include/frontend/proto.h | 1 + src/tools/sysdb/scanner.l | 7 ++ t/Makefile.am | 1 + t/frontend/parser_test.c | 94 +++++++++++++++++++++++ t/libsysdb_test.c | 1 + t/libsysdb_test.h | 4 + 13 files changed, 452 insertions(+), 2 deletions(-) create mode 100644 src/frontend/grammar.y create mode 100644 src/frontend/parser.c create mode 100644 src/frontend/scanner.l create mode 100644 src/include/frontend/parser.h create mode 100644 t/frontend/parser_test.c diff --git a/.gitignore b/.gitignore index 9cbc7c5..f097f95 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ libtool ltmain.sh # build output +src/frontend/grammar.c +src/frontend/grammar.h +src/frontend/scanner.c src/liboconfig/parser.c src/liboconfig/parser.h src/liboconfig/scanner.c diff --git a/src/Makefile.am b/src/Makefile.am index 53f4efb..c0b7576 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,8 @@ AM_CPPFLAGS += -DSYSCONFDIR='"${sysconfdir}"' AM_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"' AM_CPPFLAGS += -DPKGLIBDIR='"${pkglibdir}"' +AM_YFLAGS = -d + BUILT_SOURCES = include/client/sysdb.h include/sysdb.h EXTRA_DIST = include/client/sysdb.h.in include/sysdb.h.in @@ -53,6 +55,11 @@ libsysdbclient_la_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) libsysdbclient_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0 -pthread libsysdbclient_la_LIBADD = $(LIBLTDL) +# don't use strict CFLAGS for flex code +noinst_LTLIBRARIES += libsysdb_fe_parser.la +libsysdb_fe_parser_la_SOURCES = \ + frontend/grammar.y frontend/scanner.l +libsysdb_fe_parser_la_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" libsysdb_la_SOURCES = \ sysdb.c include/sysdb.h \ core/object.c include/core/object.h \ @@ -61,6 +68,7 @@ libsysdb_la_SOURCES = \ include/core/data.h \ frontend/connection.c include/frontend/connection.h \ frontend/connection-private.h \ + frontend/parser.c \ frontend/sock.c include/frontend/sock.h \ frontend/session.c \ frontend/query.c \ @@ -74,8 +82,9 @@ libsysdb_la_SOURCES = \ libsysdb_la_CFLAGS = $(AM_CFLAGS) libsysdb_la_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) libsysdb_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0 -pthread -libsysdb_la_LIBADD = $(LIBLTDL) -lrt liboconfig/liboconfig.la -libsysdb_la_DEPENDENCIES = liboconfig/liboconfig.la +libsysdb_la_LIBADD = libsysdb_fe_parser.la \ + $(LIBLTDL) -lrt liboconfig/liboconfig.la +libsysdb_la_DEPENDENCIES = libsysdb_fe_parser.la liboconfig/liboconfig.la if BUILD_WITH_LIBDBI libsysdb_la_SOURCES += \ diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y new file mode 100644 index 0000000..ef88272 --- /dev/null +++ b/src/frontend/grammar.y @@ -0,0 +1,89 @@ +/* + * SysDB - src/frontend/grammar.y + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +%{ + +#include "frontend/parser.h" +#include "frontend/grammar.h" +#include "utils/error.h" + +#include + +void +sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); + +%} + +%pure-parser +%lex-param {sdb_fe_yyscan_t scanner} +%parse-param {sdb_fe_yyscan_t scanner} +%locations +%error-verbose +%expect 0 +%name-prefix="sdb_fe_yy" + +%start statements + +%token SCANNER_ERROR + +%token IDENTIFIER +%token LIST + +%% + +statements: + statements ';' statement + { + } + | + statement + { + } + ; + +statement: + list_statement + { + } + | + /* empty */ + ; + +list_statement: + LIST + ; + +%% + +void +sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg) +{ + sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg); +} /* sdb_fe_yyerror */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/frontend/parser.c b/src/frontend/parser.c new file mode 100644 index 0000000..b970e73 --- /dev/null +++ b/src/frontend/parser.c @@ -0,0 +1,62 @@ +/* + * SysDB - src/frontend/parser.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sysdb.h" + +#include "frontend/parser.h" +#include "frontend/grammar.h" +#include "frontend/connection-private.h" + +#include + +/* + * public API + */ + +int +sdb_fe_parse(const char *query) +{ + sdb_fe_yyscan_t scanner; + int yyres; + + if (! query) + return -1; + + scanner = sdb_fe_scanner_init(query); + if (! scanner) + return -1; + + yyres = sdb_fe_yyparse(scanner); + sdb_fe_scanner_destroy(scanner); + + if (yyres) + return -1; + return 0; +} /* sdb_fe_parse */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l new file mode 100644 index 0000000..cd7ea85 --- /dev/null +++ b/src/frontend/scanner.l @@ -0,0 +1,121 @@ +/* + * SysDB - src/frontend/scanner.l + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +%{ + +#include "frontend/parser.h" +#include "frontend/grammar.h" +#include "utils/error.h" + +#include + +#include + +void +sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); + +%} + +%option never-interactive +%option reentrant +%option bison-bridge +%option bison-locations +%option 8bit +%option yylineno +%option nodefault +%option noinput +%option nounput +%option noyywrap +%option verbose +%option warn +%option prefix="sdb_fe_yy" outfile="lex.yy.c" + +%x CSC + +whitespace ([ \t\n\r\f]+) +simple_comment ("--"[^\n\r]*) + +/* + * C style comments + */ +csc_start \/\* +csc_inside ([^*/]+|[^*]\/|\*[^/]) +csc_end \*\/ + +identifier ([A-Za-z_][A-Za-z_0-9$]*) + +%% + +{whitespace} | +{simple_comment} { /* ignore */ } + +{csc_start} { BEGIN(CSC); } +{csc_inside} { /* ignore */ } +{csc_end} { BEGIN(INITIAL); } +<> { + sdb_fe_yyerror(yylval, yyscanner, "unterminated C-style comment"); + return SCANNER_ERROR; + } + +{identifier} { + /* XXX */ + if (! strcasecmp(yytext, "LIST")) + return LIST; + + return IDENTIFIER; + } + +. { /* do nothing for now */ } + +%% + +sdb_fe_yyscan_t +sdb_fe_scanner_init(const char *str) +{ + yyscan_t scanner; + + if (sdb_fe_yylex_init(&scanner)) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "frontend: yylex_init failed: %s", + sdb_strerror(errno, errbuf, sizeof(errbuf))); + return NULL; + } + + /* 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); + return scanner; +} /* sdb_fe_scanner_init */ + +void +sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner) +{ + sdb_fe_yylex_destroy(scanner); +} /* sdb_fe_scanner_destroy */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/frontend/connection.h b/src/include/frontend/connection.h index a2163bc..bdebe7d 100644 --- a/src/include/frontend/connection.h +++ b/src/include/frontend/connection.h @@ -93,6 +93,13 @@ sdb_connection_send(sdb_conn_t *conn, uint32_t code, int sdb_connection_ping(sdb_conn_t *conn); +/* + * sdb_fe_parse: + * Parse the query text specified in 'query'. + */ +int +sdb_fe_parse(const char *query); + /* * session handling */ diff --git a/src/include/frontend/parser.h b/src/include/frontend/parser.h new file mode 100644 index 0000000..b942248 --- /dev/null +++ b/src/include/frontend/parser.h @@ -0,0 +1,51 @@ +/* + * SysDB - src/include/frontend/parser.h + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SDB_FRONTEND_PARSER_H +#define SDB_FRONTEND_PARSER_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* see yyscan_t */ +typedef void *sdb_fe_yyscan_t; + +sdb_fe_yyscan_t +sdb_fe_scanner_init(const char *str); + +void +sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SDB_FRONTEND_PARSER_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/frontend/proto.h b/src/include/frontend/proto.h index 1d02151..fd78c26 100644 --- a/src/include/frontend/proto.h +++ b/src/include/frontend/proto.h @@ -46,6 +46,7 @@ typedef enum { CONNECTION_STARTUP, /* querying */ + CONNECTION_QUERY, CONNECTION_LIST, } sdb_conn_state_t; diff --git a/src/tools/sysdb/scanner.l b/src/tools/sysdb/scanner.l index 3ec4b04..07a9413 100644 --- a/src/tools/sysdb/scanner.l +++ b/src/tools/sysdb/scanner.l @@ -26,6 +26,12 @@ */ %{ + +/* + * This is a simplified version of frontend/scanner.l. The only purpose is to + * find queries (terminated by semicolon). + */ + #include "tools/sysdb/input.h" #ifdef YY_INPUT @@ -37,6 +43,7 @@ } while (0) static sdb_input_t *sdb_input; + %} %option interactive diff --git a/t/Makefile.am b/t/Makefile.am index 7aa6d77..6adf484 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -12,6 +12,7 @@ libsysdb_test_SOURCES = \ libsysdb_test.c libsysdb_test.h \ core/object_test.c \ core/store_test.c \ + frontend/parser_test.c \ frontend/sock_test.c \ utils/channel_test.c \ utils/dbi_test.c \ diff --git a/t/frontend/parser_test.c b/t/frontend/parser_test.c new file mode 100644 index 0000000..bebe15e --- /dev/null +++ b/t/frontend/parser_test.c @@ -0,0 +1,94 @@ +/* + * SysDB - t/frontend/parser_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "frontend/connection.h" +#include "libsysdb_test.h" + +#include + +/* + * tests + */ + +START_TEST(test_parse) +{ + struct { + const char *query; + int expected; + } golden_data[] = { + /* empty commands */ + { NULL, -1 }, + { "", 0 }, + { ";", 0 }, + { ";;", 0 }, + + /* valid commands */ + { "LIST", 0 }, + { "LIST;", 0 }, + + /* comments */ + { "/* some comment */", 0 }, + { "-- another comment", 0 }, + + /* syntax errors */ + { "INVALID", -1 }, + { "/* some incomplete", -1 }, + }; + + size_t i; + int 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; + 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); + } +} +END_TEST + +Suite * +fe_parser_suite(void) +{ + Suite *s = suite_create("frontend::parser"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_parse); + suite_add_tcase(s, tc); + + return s; +} /* util_parser_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/libsysdb_test.c b/t/libsysdb_test.c index 110df8b..2fa83dc 100644 --- a/t/libsysdb_test.c +++ b/t/libsysdb_test.c @@ -40,6 +40,7 @@ main(void) suite_creator_t creators[] = { { core_object_suite, NULL }, { core_store_suite, NULL }, + { fe_parser_suite, NULL }, { fe_sock_suite, NULL }, { util_channel_suite, NULL }, { util_dbi_suite, NULL }, diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h index 616a84e..64558cd 100644 --- a/t/libsysdb_test.h +++ b/t/libsysdb_test.h @@ -67,6 +67,10 @@ core_object_suite(void); Suite * core_store_suite(void); +/* t/frontend/parser_test */ +Suite * +fe_parser_suite(void); + /* t/frontend/sock_test */ Suite * fe_sock_suite(void); -- 2.30.2