diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-03-05 23:40:11 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-03-05 23:44:50 +0200 |
commit | 2dbad2727f1d00b223353965b326cfffa96fc776 (patch) | |
tree | 3e76daff8a9bf0a1268e183acce13d6ef828ccf7 /src | |
parent | 8241dc04501f62b613f17f5c165f915a216ba30c (diff) | |
download | grecs-2dbad2727f1d00b223353965b326cfffa96fc776.tar.gz grecs-2dbad2727f1d00b223353965b326cfffa96fc776.tar.bz2 |
Improve dhcpd parser
* src/dhcpd-gram.y: Support assignments and conditional
expressions.
* src/dhcpd-lex.l: New exclusive states BOOL and EXPR.
* src/parsertab.c (parser_tab) [ENABLE_DHCPD_PARSER]: Define
dhcpd parser.
* tests/parser-dhcpd.at: New file.
* tests/Makefile.am: Add parser-dhcpd.at
* tests/testsuite.at: Likewise.
Diffstat (limited to 'src')
-rw-r--r-- | src/dhcpd-gram.y | 123 | ||||
-rw-r--r-- | src/dhcpd-lex.l | 77 | ||||
-rw-r--r-- | src/parsertab.c | 4 |
3 files changed, 198 insertions, 6 deletions
diff --git a/src/dhcpd-gram.y b/src/dhcpd-gram.y index b4f1476..e40f473 100644 --- a/src/dhcpd-gram.y +++ b/src/dhcpd-gram.y @@ -34,6 +34,20 @@ extern int yy_flex_debug; extern int grecs_dhcpd_new_source(const char *name, grecs_locus_t *loc); extern void grecs_dhcpd_close_sources(void); +extern void grecs_dhcpd_begin_bool(void); +extern void grecs_dhcpd_begin_expr(void); + +/* NOTE: STRING must be allocated */ +static grecs_value_t * +make_string_value(char *string) +{ + grecs_value_t *val; + val = grecs_malloc(sizeof(val[0])); + val->type = GRECS_TYPE_STRING; + val->v.string = string; + return val; +} + %} %error-verbose @@ -48,13 +62,16 @@ extern void grecs_dhcpd_close_sources(void); struct { struct grecs_node *head, *tail; } node_list; } -%token <string> DHCPD_STRING DHCPD_IDENT +%token <string> DHCPD_IF DHCPD_ELSIF DHCPD_EXPR +%token DHCPD_ELSE +%token <string> DHCPD_STRING DHCPD_IDENT %type <string> string %type <svalue> value %type <pvalue> vallist tag %type <list> vlist strlist %type <node> stmt simple block maybe_stmtlist -%type <node_list> stmtlist +%type <node> cond elsecond opt_elsecond elsifcond +%type <node_list> stmtlist elsifchain opt_elsifchain %% @@ -95,6 +112,7 @@ stmtlist: stmt stmt : simple | block + | cond ; simple : DHCPD_IDENT vallist ';' @@ -111,6 +129,14 @@ simple : DHCPD_IDENT vallist ';' $$->v.value = $2; } } + | DHCPD_IDENT '=' { grecs_dhcpd_begin_expr(); } DHCPD_EXPR ';' + { + $$ = grecs_node_create_points(grecs_node_stmt, + @1.beg, @5.end); + $$->ident = $1; + $$->idloc = @1; + $$->v.value = make_string_value($4); + } | string ';' { $$ = grecs_node_create(grecs_node_stmt, &@1); @@ -222,6 +248,99 @@ strlist : DHCPD_STRING ',' DHCPD_STRING } ; +cond : if DHCPD_EXPR '{' maybe_stmtlist '}' opt_elsifchain opt_elsecond + { + $$ = grecs_node_create_points(grecs_node_block, + @1.beg, @7.end); + + grecs_line_begin(); + grecs_line_add("if", 2); + + $$->ident = grecs_line_finish(); + $$->idloc = @1; + + $$->v.value = make_string_value ($2); + grecs_node_bind($$, $4, 1); + + if ($6.head) { + grecs_node_bind($6.tail, $7, 0); + grecs_node_bind($$, $6.head, 0); + } + } + ; + +if : DHCPD_IF + { + grecs_dhcpd_begin_bool(); + } + ; + +elsif : DHCPD_ELSIF + { + grecs_dhcpd_begin_bool(); + } + ; + +opt_elsifchain: /* empty */ + { + $$.head = $$.tail = NULL; + } + | elsifchain + ; + +elsifchain: elsifcond + { + $$.head = $$.tail = $1; + } + | elsifchain elsifcond + { + if ($2) { + if (!$1.head) + $1.head = $1.tail = $2; + else + grecs_node_bind($1.tail, $2, 0); + } + $$ = $1; + } + ; + +elsifcond: elsif DHCPD_EXPR '{' maybe_stmtlist '}' + { + $$ = grecs_node_create_points(grecs_node_block, + @1.beg, @5.end); + + grecs_line_begin(); + grecs_line_add("elsif", 5); + + $$->ident = grecs_line_finish(); + $$->idloc = @1; + $$->v.value = make_string_value ($2); + grecs_node_bind($$, $4, 1); + } + ; + +opt_elsecond: /* empty */ + { + $$ = NULL; + } + | elsecond + ; + +elsecond: DHCPD_ELSE '{' maybe_stmtlist '}' + { + $$ = grecs_node_create_points(grecs_node_block, + @1.beg, @4.end); + + grecs_line_begin(); + grecs_line_add("else", 4); + + $$->ident = grecs_line_finish(); + $$->idloc = @1; + $$->v.value = NULL; + grecs_node_bind($$, $3, 1); + } + ; + %% int diff --git a/src/dhcpd-lex.l b/src/dhcpd-lex.l index 12e64c6..450a54b 100644 --- a/src/dhcpd-lex.l +++ b/src/dhcpd-lex.l @@ -1,6 +1,5 @@ /* grecs - Gray's Extensible Configuration System -*- c -*- */ %option noinput -%option nounput %top { #ifdef HAVE_CONFIG_H # include <config.h> @@ -43,10 +42,13 @@ grecs_current_locus_point.col += yyleng; \ yylloc.end = grecs_current_locus_point; \ } while (0); + +#define ISWS(c) ((c)==' '||(c)=='\t') %} - -%x COMMENT STR +%x COMMENT STR BOOL EXPR + +OWS [ \t\f]* WS [ \t\f][ \t\f]* ID [a-zA-Z_][a-zA-Z_0-9-]* P [1-9][0-9]* @@ -66,6 +68,61 @@ P [1-9][0-9]* #.* /* end-of-file comment */; "//".*\n { grecs_locus_point_advance_line(grecs_current_locus_point); } "//".* /* end-of-file comment */; +"if" return DHCPD_IF; +"elsif" return DHCPD_ELSIF; +"else" return DHCPD_ELSE; + +<BOOL>[^\{\n]*\n { + char *p; + size_t len; + for (p = yytext, len = yyleng - 1; ISWS(*p) && len > 0; p++, len--) + ; + if (len) { + grecs_line_add(p, len); + grecs_line_add(" ", 1); + } + grecs_locus_point_advance_line(grecs_current_locus_point); +} +<BOOL>[^\{\n]*\{ { + char *p; + size_t len; + + unput('{'); + for (p = yytext, len = yyleng - 1; ISWS(*p) && len > 0; p++, len--) + ; + for (; len > 0 && ISWS(p[len-1]); len--) + ; + grecs_line_add(p, len); + BEGIN(INITIAL); + yylval.string = grecs_line_finish(); + return DHCPD_EXPR; +} + +<EXPR>[^;\n]*\n { + char *p; + size_t len; + for (p = yytext, len = yyleng - 1; ISWS(*p) && len > 0; p++, len--) + ; + if (len) { + grecs_line_add(p, len); + grecs_line_add(" ", 1); + } + grecs_locus_point_advance_line(grecs_current_locus_point); +} +<EXPR>[^;\n]*; { + char *p; + size_t len; + + unput(';'); + for (p = yytext, len = yyleng - 1; ISWS(*p) && len > 0; p++, len--) + ; + for (; len > 0 && ISWS(p[len-1]); len--) + ; + grecs_line_add(p, len); + BEGIN(INITIAL); + yylval.string = grecs_line_finish(); + return DHCPD_EXPR; +} /* Identifiers */ {ID} { grecs_line_begin(); grecs_line_add(yytext, yyleng); @@ -103,7 +160,7 @@ P [1-9][0-9]* {WS} ; /* Other tokens */ \n { grecs_locus_point_advance_line(grecs_current_locus_point); } -[,;{}()!] return yytext[0]; +[,;{}()!=] return yytext[0]; . { if (isascii(yytext[0]) && isprint(yytext[0])) grecs_error(&yylloc, 0, _("stray character %c"), yytext[0]); @@ -112,6 +169,18 @@ P [1-9][0-9]* (unsigned char) yytext[0]); } %% +void +grecs_dhcpd_begin_bool(void) +{ + BEGIN(BOOL); +} + +void +grecs_dhcpd_begin_expr(void) +{ + BEGIN(EXPR); +} + struct dhcpd_input_context { ino_t i_node; dev_t i_dev; diff --git a/src/parsertab.c b/src/parsertab.c index 8baec2e..0f3544f 100644 --- a/src/parsertab.c +++ b/src/parsertab.c @@ -34,6 +34,10 @@ static struct parser_tab { #ifdef ENABLE_BIND_PARSER { "BIND", grecs_bind_parser }, #endif +#ifdef ENABLE_DHCPD_PARSER + { "DHCPD", grecs_dhcpd_parser }, + { "DHCP", grecs_dhcpd_parser }, +#endif #ifdef ENABLE_GIT_PARSER { "GIT", grecs_git_parser }, #endif |