diff options
Diffstat (limited to 'src/argot-gram.y')
-rw-r--r-- | src/argot-gram.y | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/argot-gram.y b/src/argot-gram.y new file mode 100644 index 0000000..b92794c --- /dev/null +++ b/src/argot-gram.y @@ -0,0 +1,274 @@ +%{ +/* argot - Gray's Extensible Configuration System + Copyright (C) 2007-2016 Sergey Poznyakoff + + Grecs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Grecs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <argot.h> +#include <argot-gram.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +int yylex(void); +int yyerror(char const *s); + +static struct argot_node *parse_tree; +%} + +%error-verbose +%locations + +%union { + char *string; + argot_value_t svalue, *pvalue; + struct argot_list *list; + struct argot_node *node; + argot_locus_t locus; + struct { struct argot_node *head, *tail; } node_list; +} + +%token <string> STRING QSTRING MSTRING IDENT +%type <string> string slist +%type <list> slist0 +%type <svalue> value +%type <pvalue> vallist tag +%type <list> values list vlist +%type <node> stmt simple block maybe_stmtlist +%type <node_list> stmtlist + +%% + +input : maybe_stmtlist + { + parse_tree = argot_node_create(argot_node_root, &@1); + parse_tree->v.texttab = argot_text_table(); + argot_node_bind(parse_tree, $1, 1); + } + ; + +maybe_stmtlist: + /* empty */ + { + $$ = NULL; + } + | stmtlist + { + $$ = $1.head; + } + ; + +stmtlist: stmt + { + $$.head = $$.tail = $1; + } + | stmtlist stmt + { + argot_node_bind($1.tail, $2, 0); + } + ; + +stmt : simple + | block + ; + +simple : IDENT vallist ';' + { + $$ = argot_node_create_points(argot_node_stmt, + @1.beg, @2.end); + $$->ident = $1; + $$->idloc = @1; + $$->v.value = $2; + } + | IDENT ';' + { + $$ = argot_node_create(argot_node_stmt, &@1); + $$->ident = $1; + $$->idloc = @1; + $$->v.value = NULL; + } + ; + +block : IDENT tag '{' stmtlist '}' opt_sc + { + $$ = argot_node_create_points(argot_node_block, + @1.beg, @5.end); + $$->ident = $1; + $$->idloc = @1; + $$->v.value = $2; + argot_node_bind($$, $4.head, 1); + } + ; + +tag : /* empty */ + { + $$ = NULL; + } + | vallist + ; + +vallist : vlist + { + size_t n; + + if ((n = argot_list_size($1)) == 1) { + $$ = argot_list_index($1, 0); + } else { + size_t i; + struct argot_list_entry *ep; + + $$ = argot_malloc(sizeof($$[0])); + $$->type = ARGOT_TYPE_ARRAY; + $$->locus = @1; + $$->v.arg.c = n; + $$->v.arg.v = argot_calloc(n, + sizeof($$->v.arg.v[0])); + for (i = 0, ep = $1->head; ep; i++, ep = ep->next) + $$->v.arg.v[i] = ep->data; + } + $1->free_entry = NULL; + argot_list_free($1); + } + ; + +vlist : value + { + $$ = argot_value_list_create(); + argot_list_append($$, argot_value_ptr_from_static(&$1)); + } + | vlist value + { + argot_list_append($1, argot_value_ptr_from_static(&$2)); + } + ; + +value : string + { + $$.type = ARGOT_TYPE_STRING; + $$.locus = @1; + $$.v.string = $1; + } + | list + { + $$.type = ARGOT_TYPE_LIST; + $$.locus = @1; + $$.v.list = $1; + } + | MSTRING + { + $$.type = ARGOT_TYPE_STRING; + $$.locus = @1; + $$.v.string = $1; + } + ; + +string : STRING + | IDENT + | slist + ; + +slist : slist0 + { + struct argot_list_entry *ep; + + argot_line_begin(); + for (ep = $1->head; ep; ep = ep->next) { + argot_line_add(ep->data, strlen(ep->data)); + free(ep->data); + ep->data = NULL; + } + $$ = argot_line_finish(); + argot_list_free($1); + } + ; + +slist0 : QSTRING + { + $$ = argot_list_create(); + argot_list_append($$, $1); + } + | slist0 QSTRING + { + argot_list_append($1, $2); + $$ = $1; + } + ; + +list : '(' ')' + { + $$ = NULL; + } + | '(' values ')' + { + $$ = $2; + } + | '(' values ',' ')' + { + $$ = $2; + } + ; + +values : value + { + $$ = argot_value_list_create(); + argot_list_append($$, argot_value_ptr_from_static(&$1)); + } + | values ',' value + { + argot_list_append($1, argot_value_ptr_from_static(&$3)); + $$ = $1; + } + ; + +opt_sc : /* empty */ + | ';' + ; + +%% + +int +yyerror(char const *s) +{ + argot_error(&yylloc, 0, "%s", s); + return 0; +} + +struct argot_node * +argot_argot_parser(const char *name, int traceflags) +{ + int rc; + if (argot_lex_begin(name, traceflags & ARGOT_TRACE_LEX)) + return NULL; + yydebug = traceflags & ARGOT_TRACE_GRAM; + parse_tree = NULL; + rc = yyparse(); + if (argot_error_count) + rc = 1; + argot_lex_end(rc); + if (rc) { + argot_tree_free(parse_tree); + parse_tree = NULL; + } + return parse_tree; +} + + + + + + |