strongswan/src/starter/parser/lexer.l

203 lines
4.4 KiB
Plaintext

%{
/*
* Copyright (C) 2013-2014 Tobias Brunner
* HSR 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.
*/
#include <utils/parser_helper.h>
#include <parser/conf_parser.h>
#include "parser.h"
bool conf_parser_open_next_file(parser_helper_t *ctx);
static void include_files(parser_helper_t *ctx);
%}
%option debug
%option warn
/* use start conditions stack */
%option stack
/* do not declare unneeded functions */
%option noinput noyywrap
/* do not include unistd.h as it might conflict with our scanner states */
%option nounistd
/* due to that disable interactive mode, which requires isatty() */
%option never-interactive
/* don't use global variables */
%option reentrant
/* maintain the line number */
%option yylineno
/* don't generate a default rule */
%option nodefault
/* prefix function/variable declarations */
%option prefix="conf_parser_"
/* don't change the name of the output file otherwise autotools has issues */
%option outfile="lex.yy.c"
/* type of our extra data */
%option extra-type="parser_helper_t*"
/* state used to scan include file patterns */
%x inc
/* state used to scan quoted strings */
%x str
%%
^[\t ]*"version"[^\n]*$ /* eat legacy version declaration */
^[\t ]+ return SPACES;
[\t ]+ /* eat other whitespace */
[\t ]*#[^\n]* /* eat comments */
\n return NEWLINE;
"=" return EQ;
^"config setup" return CONFIG_SETUP;
^"conn" return CONN;
^"ca" return CA;
"include"[\t ]+/[^=] {
yyextra->string_init(yyextra);
yy_push_state(inc, yyscanner);
}
"\"" {
yyextra->string_init(yyextra);
yy_push_state(str, yyscanner);
}
(@#)?[^\"#= \t\n]+ {
yylval->s = strdup(yytext);
return STRING;
}
<inc>{
/* we allow all characters except # and spaces, they can be escaped */
<<EOF>> |
[#\n\t ] {
if (*yytext)
{
switch (yytext[0])
{
case '\n':
/* put the newline back to fix the line numbers */
unput('\n');
yy_set_bol(0);
break;
case '#':
/* comments are parsed outside of this start condition */
unput(yytext[0]);
break;
}
}
include_files(yyextra);
yy_pop_state(yyscanner);
}
"\"" { /* string include */
yy_push_state(str, yyscanner);
}
\\ {
yyextra->string_add(yyextra, yytext);
}
\\["#} ] {
yyextra->string_add(yyextra, yytext+1);
}
[^"\\#\n\t ]+ {
yyextra->string_add(yyextra, yytext);
}
}
<str>{
"\"" |
<<EOF>> |
\\ {
if (!streq(yytext, "\""))
{
PARSER_DBG1(yyextra, "unterminated string detected");
return STRING_ERROR;
}
if (yy_top_state(yyscanner) == inc)
{ /* string include */
include_files(yyextra);
yy_pop_state(yyscanner);
yy_pop_state(yyscanner);
}
else
{
yy_pop_state(yyscanner);
yylval->s = yyextra->string_get(yyextra);
return STRING;
}
}
\\n yyextra->string_add(yyextra, "\n");
\\r yyextra->string_add(yyextra, "\r");
\\t yyextra->string_add(yyextra, "\t");
\\\r?\n /* merge lines that end with EOL characters */
\\. yyextra->string_add(yyextra, yytext+1);
[^\\"]+ {
yyextra->string_add(yyextra, yytext);
}
}
<<EOF>> {
conf_parser_pop_buffer_state(yyscanner);
if (!conf_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
{
yyterminate();
}
}
%%
/**
* Open the next file, if any is queued and readable, otherwise returns FALSE.
*/
bool conf_parser_open_next_file(parser_helper_t *ctx)
{
FILE *file;
file = ctx->file_next(ctx);
if (!file)
{
return FALSE;
}
conf_parser_set_in(file, ctx->scanner);
conf_parser_push_buffer_state(
conf_parser__create_buffer(file, YY_BUF_SIZE,
ctx->scanner), ctx->scanner);
return TRUE;
}
/**
* Assumes that the file pattern to include is currently stored as string on
* the helper object.
*/
static void include_files(parser_helper_t *ctx)
{
char *pattern = ctx->string_get(ctx);
ctx->file_include(ctx, pattern);
free(pattern);
conf_parser_open_next_file(ctx);
}