/* MeTA1 configuration lexer for GNU Pies. -*- c -*- */
%top {
/* MeTA1 configuration lexer for GNU Pies.
Copyright (C) 2008, 2009 Sergey Poznyakoff
GNU Pies 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, or (at your option)
any later version.
GNU Pies 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 GNU Pies. If not, see . */
/* This file implements a lexical analyzer for MeTA1 main configuration file.
*/
#ifndef HAVE_CONFIG_H
# include
#endif
}
%{
#include "pies.h"
#include "meta1gram.h"
#include "meta1lex.h"
grecs_locus_t meta1_locus;
size_t meta1_error_count;
struct obstack meta1_stk;
int meta1_stk_init;
char *meta1_queue_dir;
#define yylval meta1lval
%}
%x COMMENT STR
X [0-9a-fA-F]
%%
/* C-style comments */
"/*" BEGIN (COMMENT);
[^*\n]* /* eat anything that's not a '*' */
"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
\n ++meta1_locus.line;
"*"+"/" BEGIN (INITIAL);
/* End-of-line comments */
#.*\n { meta1_locus.line++; }
#.* /* end-of-file comment */;
/* Number */
0[xX]{X}+ |
0[0-7]+ |
[1-9][0-9]+ { meta1_line_begin ();
meta1_line_add (yytext, yyleng);
yylval.string = meta1_line_finish ();
return META1_NUMBER; }
/* Identifiers (unquoted strings) */
[a-zA-Z0-9_\./:\*-]+ { meta1_line_begin ();
meta1_line_add (yytext, yyleng);
yylval.string = meta1_line_finish ();
return META1_IDENT; }
/* Quoted strings */
\"[^\\"\n]*\" { meta1_line_begin ();
meta1_line_add (yytext + 1, yyleng - 2);
yylval.string = meta1_line_finish ();
return META1_STRING; }
\"[^\\"\n]*\\x{X}{1,2} { BEGIN(STR);
meta1_line_begin ();
meta1_line_add_unescape_hex (yytext + 1, yyleng - 1);
}
\"[^\\"\n]*\\. { BEGIN(STR);
meta1_line_begin ();
meta1_line_add_unescape_last (yytext + 1, yyleng - 1); }
[^\\"\n]*\\x{X}{1,2} { meta1_line_add_unescape_hex (yytext, yyleng); }
[^\\"\n]*\\. { meta1_line_add_unescape_last (yytext, yyleng); }
[^\\"\n]*\" { BEGIN (INITIAL);
if (yyleng > 1)
meta1_line_add (yytext, yyleng - 1);
yylval.string = meta1_line_finish ();
return META1_STRING; }
[^\\"\n]*\n { BEGIN (INITIAL);
meta1_parse_error (_("newline in a string"));
meta1_line_add (yytext, yyleng - 1);
yylval.string = meta1_line_finish ();
return META1_STRING; }
/* Other tokens */
[ \t\f][ \t\f]* ;
\n { meta1_locus.line++; }
[,;{}=] return yytext[0];
. { if (isascii (yytext[0]) && isprint (yytext[0]))
meta1_parse_error (_("stray character %c"), yytext[0]);
else
meta1_parse_error (_("stray character \\%03o"),
(unsigned char) yytext[0]); }
%%
int
yywrap ()
{
return 1;
}
void
meta1_line_add (const char *text, size_t len)
{
obstack_grow (&meta1_stk, text, len);
}
static char quote_transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
static int
unescape_char (int c)
{
char *p;
for (p = quote_transtab; *p; p += 2)
{
if (*p == c)
return p[1];
}
return c;
}
static void
unescape_to_line (int c)
{
char t;
if (c == 'v')
t = '\v';
else
{
t = unescape_char (c);
if (t == c && t != '\\' && t != '\"')
meta1_parse_error (_("unknown escape sequence '\\%c'"), c);
}
obstack_1grow (&meta1_stk, t);
}
void
meta1_line_add_unescape_last (const char *text, size_t len)
{
obstack_grow (&meta1_stk, text, len - 2);
unescape_to_line (text[len - 1]);
}
void
meta1_line_add_unescape_hex (const char *text, size_t len)
{
for (; text[len-1] != 'x' && len > 0; len--)
;
obstack_grow (&meta1_stk, text, len - 2);
obstack_1grow (&meta1_stk, (char) strtoul (text + len, NULL, 16));
}
void
meta1_line_begin ()
{
if (!meta1_stk_init)
{
obstack_init (&meta1_stk);
meta1_stk_init = 1;
}
}
char *
meta1_line_finish ()
{
obstack_1grow (&meta1_stk, 0);
return obstack_finish (&meta1_stk);
}
char *
meta1_string (const char *str, size_t len)
{
meta1_line_begin ();
meta1_line_add (str, len);
return meta1_line_finish ();
}
void
meta1_parse_error (const char *fmt, ...)
{
va_list ap;
logmsg_printf (LOG_ERR, "%s:%lu: ", meta1_locus.file,
(unsigned long) meta1_locus.line);
va_start (ap, fmt);
logmsg_vprintf (LOG_ERR, fmt, ap);
va_end (ap);
logmsg_printf (LOG_ERR, "\n");
meta1_error_count++;
}
void
meta1_lexer_set_debug ()
{
char *p = getenv ("META1_DEBUG_LEX");
yy_flex_debug = p && (*p - '0') > 0;
}
/* Parse MeTA1 configuration file `name'. Populate `meta1_parse_tree' with
the parse tree. */
int
meta1_config_parse (const char *name)
{
int rc;
FILE *fp;
fp = fopen (name, "r");
if (!fp)
{
logmsg (LOG_ERR,
_("%s: cannot open file: %s"), name, strerror (errno));
return 1;
}
meta1_locus.file = meta1_string (name, strlen (name));
meta1_locus.line = 1;
meta1_lexer_set_debug ();
meta1_parser_set_debug ();
yyrestart (fp);
rc = meta1parse ();
fclose (fp);
if (meta1_error_count)
rc = 1;
return rc;
}