blob: 21c12715b8752922a570a02abb39639081246de9 [file] [log] [blame]
/* -*- mode: C -*- */
/* --------------------------------------------------------------------------
libconfig - A library for processing structured configuration files
Copyright (C) 2005-2020 Mark A Lindner
This file is part of libconfig.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, see
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------
*/
%option nounistd
%option never-interactive
%option reentrant
%option noyywrap
%option yylineno
%option nounput
%option bison-bridge
%option header-file="scanner.h"
%option outfile="lex.yy.c"
%option extra-type="struct scan_context *"
%{
#ifdef _MSC_VER
#pragma warning (disable: 4996)
#endif
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include "parsectx.h"
#include "scanctx.h"
#include "grammar.h"
#include "wincompat.h"
#include "util.h"
#define YY_NO_INPUT // Suppress generation of useless input() function
%}
true [Tt][Rr][Uu][Ee]
false [Ff][Aa][Ll][Ss][Ee]
name [A-Za-z\*][-A-Za-z0-9_\*]*
integer [-+]?[0-9]+
integer64 [-+]?[0-9]+L(L)?
hex 0[Xx][0-9A-Fa-f]+
hex64 0[Xx][0-9A-Fa-f]+L(L)?
hexchar \\[Xx][0-9A-Fa-f]{2}
float ([-+]?([0-9]*)?\.[0-9]*([eE][-+]?[0-9]+)?)|([-+]?([0-9]+)(\.[0-9]*)?[eE][-+]?[0-9]+)
include_open ^[ \t]*@include[ \t]+\"
%x SINGLE_LINE_COMMENT MULTI_LINE_COMMENT STRING INCLUDE
%%
(#|\/\/) { BEGIN SINGLE_LINE_COMMENT; }
<SINGLE_LINE_COMMENT>\n { BEGIN INITIAL; }
<SINGLE_LINE_COMMENT>. { /* ignore */ }
\/\* { BEGIN MULTI_LINE_COMMENT; }
<MULTI_LINE_COMMENT>\*\/ { BEGIN INITIAL; }
<MULTI_LINE_COMMENT>. { /* ignore */ }
<MULTI_LINE_COMMENT>\n { /* ignore */ }
\" { BEGIN STRING; }
<STRING>[^\"\\]+ { libconfig_scanctx_append_string(yyextra, yytext); }
<STRING>\\n { libconfig_scanctx_append_char(yyextra, '\n'); }
<STRING>\\r { libconfig_scanctx_append_char(yyextra, '\r'); }
<STRING>\\t { libconfig_scanctx_append_char(yyextra, '\t'); }
<STRING>\\f { libconfig_scanctx_append_char(yyextra, '\f'); }
<STRING>\\\\ { libconfig_scanctx_append_char(yyextra, '\\'); }
<STRING>\\\" { libconfig_scanctx_append_char(yyextra, '\"'); }
<STRING>{hexchar} {
char c = (char)(strtol(yytext + 2, NULL, 16) & 0xFF);
libconfig_scanctx_append_char(yyextra, c);
}
<STRING>\\ { libconfig_scanctx_append_char(yyextra, '\\'); }
<STRING>\" {
yylval->sval = libconfig_scanctx_take_string(yyextra);
BEGIN INITIAL;
return(TOK_STRING);
}
{include_open} { BEGIN INCLUDE; }
<INCLUDE>[^\"\\]+ { libconfig_scanctx_append_string(yyextra, yytext); }
<INCLUDE>\\\\ { libconfig_scanctx_append_char(yyextra, '\\'); }
<INCLUDE>\\\" { libconfig_scanctx_append_char(yyextra, '\"'); }
<INCLUDE>\" {
const char *error = NULL;
const char *path = libconfig_scanctx_take_string(yyextra);
FILE *fp = libconfig_scanctx_push_include(yyextra, (void *)YY_CURRENT_BUFFER,
path, &error);
__delete(path);
if(fp)
{
yyin = fp;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
yyscanner);
}
else if(error)
{
yyextra->config->error_text = error;
yyextra->config->error_file = libconfig_scanctx_current_filename(yyextra);
yyextra->config->error_line = libconfig_yyget_lineno(yyscanner);
return TOK_ERROR;
}
BEGIN INITIAL;
}
\n|\r|\f { /* ignore */ }
[ \t]+ { /* ignore */ }
\=|\: { return(TOK_EQUALS); }
, { return(TOK_COMMA); }
\{ { return(TOK_GROUP_START); }
\} { return(TOK_GROUP_END); }
{true} { yylval->ival = 1; return(TOK_BOOLEAN); }
{false} { yylval->ival = 0; return(TOK_BOOLEAN); }
{name} { yylval->sval = yytext; return(TOK_NAME); }
{float} { yylval->fval = atof(yytext); return(TOK_FLOAT); }
{integer} {
int ok;
long long llval = libconfig_parse_integer(yytext, &ok);
if(!ok)
return(TOK_ERROR);
if((llval < INT_MIN) || (llval > INT_MAX))
{
yylval->llval = llval;
return(TOK_INTEGER64);
}
else
{
yylval->ival = (int)llval;
return(TOK_INTEGER);
}
}
{integer64} { yylval->llval = atoll(yytext); return(TOK_INTEGER64); }
{hex} {
yylval->ival = strtoul(yytext, NULL, 16);
return(TOK_HEX);
}
{hex64} {
yylval->llval = libconfig_parse_hex64(yytext);
return(TOK_HEX64);
}
\[ { return(TOK_ARRAY_START); }
\] { return(TOK_ARRAY_END); }
\( { return(TOK_LIST_START); }
\) { return(TOK_LIST_END); }
; { return(TOK_SEMICOLON); }
. { return(TOK_GARBAGE); }
<<EOF>> {
const char *error = NULL;
FILE *fp;
fp = libconfig_scanctx_next_include_file(yyextra, &error);
if(fp)
{
yyin = fp;
yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
yyscanner);
}
else if(error)
{
yyextra->config->error_text = error;
yyextra->config->error_file = libconfig_scanctx_current_filename(yyextra);
yyextra->config->error_line = libconfig_yyget_lineno(yyscanner);
return TOK_ERROR;
}
else
{
/* No more files in the current include list. */
YY_BUFFER_STATE buf = (YY_BUFFER_STATE)libconfig_scanctx_pop_include(yyextra);
if(buf)
{
yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
yy_switch_to_buffer(buf, yyscanner);
}
else
yyterminate();
}
}