summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org>2016-03-05 21:40:11 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2016-03-05 21:44:50 (GMT)
commit2dbad2727f1d00b223353965b326cfffa96fc776 (patch) (side-by-side diff)
tree3e76daff8a9bf0a1268e183acce13d6ef828ccf7 /src
parent8241dc04501f62b613f17f5c165f915a216ba30c (diff)
downloadgrecs-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') (more/less context) (ignore whitespace changes)
-rw-r--r--src/dhcpd-gram.y123
-rw-r--r--src/dhcpd-lex.l77
-rw-r--r--src/parsertab.c4
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

Return to:

Send suggestions and report system problems to the System administrator.