diff options
Diffstat (limited to 'src/starter/parser/parser.y')
-rw-r--r-- | src/starter/parser/parser.y | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/src/starter/parser/parser.y b/src/starter/parser/parser.y new file mode 100644 index 000000000..54dedc12b --- /dev/null +++ b/src/starter/parser/parser.y @@ -0,0 +1,254 @@ +%{ +/* + * Copyright (C) 2013-2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program 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 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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. + */ + +#define _GNU_SOURCE /* for asprintf() */ +#include <stdio.h> + +#include <utils/parser_helper.h> +#include <settings/settings_types.h> +#include <parser/conf_parser.h> + +#include "parser.h" + +#define YYDEBUG 1 + +/** + * Defined by the lexer + */ +int conf_parser_lex(YYSTYPE *lvalp, void *scanner); +int conf_parser_lex_init_extra(parser_helper_t *extra, void *scanner); +int conf_parser_lex_destroy(void *scanner); +int conf_parser_set_in(FILE *in, void *scanner); +void conf_parser_set_debug(int debug, void *scanner); +char *conf_parser_get_text(void *scanner); +int conf_parser_get_leng(void *scanner); +int conf_parser_get_lineno(void *scanner); +/* Custom functions in lexer */ +bool conf_parser_open_next_file(parser_helper_t *ctx); + +/** + * Forward declaration + */ +static void conf_parser_error(parser_helper_t *ctx, const char *s); + +/** + * Make sure to call lexer with the proper context + */ +#undef yylex +static int yylex(YYSTYPE *lvalp, parser_helper_t *ctx) +{ + return conf_parser_lex(lvalp, ctx->scanner); +} + +%} +%debug + +/* generate verbose error messages */ +%error-verbose +/* generate a reentrant parser */ +%define api.pure +/* prefix function/variable declarations */ +%name-prefix "conf_parser_" + +/* interact properly with the reentrant lexer */ +%lex-param {parser_helper_t *ctx} +%parse-param {parser_helper_t *ctx} + +/* types for terminal symbols... */ +%union { + char *s; + conf_parser_section_t t; +} +%token <s> STRING +%token EQ SPACES NEWLINE CONFIG_SETUP CONN CA + +/* ...and other symbols */ +%type <t> section_type +%type <s> section_name value + +/* make the equal sign left associative */ +%left EQ + +/* properly destroy STRING tokens, which are strdup()ed, on errors */ +%destructor { free($$); } STRING section_name value + +/* there are two shift/reduce conflicts because we allow empty lines (and lines + * with spaces) within settings and anywhere else (i.e. in the beginning) */ +//%expect 2 + +%% + +/** + * ipsec.conf grammar rules + */ +statements: + /* empty */ + | statements NEWLINE + | statements statement + ; + +statement: + section + | SPACES setting + ; + +section: + section_type section_name + { + if ($1 != CONF_PARSER_CONFIG_SETUP && (!$2 || !strlen($2))) + { + PARSER_DBG1(ctx, "section name missing"); + free($2); + YYERROR; + } + conf_parser_t *parser = (conf_parser_t*)ctx->context; + parser->add_section(parser, $1, $2); + } + ; + +section_type: + CONFIG_SETUP + { + $$ = CONF_PARSER_CONFIG_SETUP; + } + | + CONN + { + $$ = CONF_PARSER_CONN; + } + | + CA + { + $$ = CONF_PARSER_CA; + } + ; + +section_name: + /* empty */ + { + $$ = NULL; + } + | STRING + { + $$ = $1; + } + ; + +setting: + /* empty */ + | + STRING EQ value + { + if (!strlen($1)) + { + PARSER_DBG1(ctx, "setting name can't be empty"); + free($1); + free($3); + YYERROR; + } + conf_parser_t *parser = (conf_parser_t*)ctx->context; + parser->add_setting(parser, $1, $value); + } + | + STRING EQ + { + if (!strlen($1)) + { + PARSER_DBG1(ctx, "setting name can't be empty"); + free($1); + YYERROR; + } + conf_parser_t *parser = (conf_parser_t*)ctx->context; + parser->add_setting(parser, $1, NULL); + } + | + STRING + { + PARSER_DBG1(ctx, "missing value for setting '%s'", $1); + free($1); + YYERROR; + } + ; + +value: + STRING + | value STRING + { /* just put a single space between them, use strings for more */ + if (asprintf(&$$, "%s %s", $1, $2) < 0) + { + free($1); + free($2); + YYERROR; + } + free($1); + free($2); + } + ; + +%% + +/** + * Referenced by the generated parser + */ +static void conf_parser_error(parser_helper_t *ctx, const char *s) +{ + char *text = conf_parser_get_text(ctx->scanner); + int len = conf_parser_get_leng(ctx->scanner); + + if (len && text[len-1] == '\n') + { /* cut off newline at the end to avoid muti-line log messages */ + len--; + } + PARSER_DBG1(ctx, "%s [%.*s]", s, (int)len, text); +} + +/** + * Parse the given file + */ +bool conf_parser_parse_file(conf_parser_t *this, char *name) +{ + parser_helper_t *helper; + bool success = FALSE; + + helper = parser_helper_create(this); + helper->get_lineno = conf_parser_get_lineno; + if (conf_parser_lex_init_extra(helper, &helper->scanner) != 0) + { + helper->destroy(helper); + return FALSE; + } + helper->file_include(helper, name); + if (!conf_parser_open_next_file(helper)) + { + DBG1(DBG_CFG, "failed to open config file '%s'", name); + } + else + { + if (getenv("DEBUG_CONF_PARSER")) + { + yydebug = 1; + conf_parser_set_debug(1, helper->scanner); + } + success = yyparse(helper) == 0; + if (!success) + { + DBG1(DBG_CFG, "invalid config file '%s'", name); + } + } + conf_parser_lex_destroy(helper->scanner); + helper->destroy(helper); + return success; +} |