diff options
Diffstat (limited to 'src/meta1lex.l')
-rw-r--r-- | src/meta1lex.l | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/src/meta1lex.l b/src/meta1lex.l new file mode 100644 index 0000000..312a1fd --- /dev/null +++ b/src/meta1lex.l @@ -0,0 +1,231 @@ +%{ +/* MeTA1 configuration lexer for Mailfromd. + Copyright (C) 2008 Sergey Poznyakoff + + 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 3, or (at your option) + any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This file implements a lexical analyzer for MeTA1 main configuration file. + */ + +#include "pies.h" +#include "meta1gram.h" +#include "meta1lex.h" + +mu_cfg_locus_t meta1_locus; +size_t meta1_error_count; +mu_opool_t meta1_pool; +char *meta1_queue_dir; + +#define yylval meta1lval +%} + +%x COMMENT STR +X [0-9a-fA-F] +%% + /* C-style comments */ +"/*" BEGIN (COMMENT); +<COMMENT>[^*\n]* /* eat anything that's not a '*' */ +<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +<COMMENT>\n ++meta1_locus.line; +<COMMENT>"*"+"/" 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); } +<STR>[^\\"\n]*\\x{X}{1,2} { meta1_line_add_unescape_hex (yytext, yyleng); } +<STR>[^\\"\n]*\\. { meta1_line_add_unescape_last (yytext, yyleng); } +<STR>[^\\"\n]*\" { BEGIN (INITIAL); + if (yyleng > 1) + meta1_line_add (yytext, yyleng - 1); + yylval.string = meta1_line_finish (); + return META1_STRING; } +<STR>[^\\"\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) +{ + mu_opool_append (meta1_pool, text, len); +} + +static void +unescape_to_line (int c) +{ + char t; + + if (c == 'v') + t = '\v'; + else + { + t = mu_argcv_unquote_char (c); + if (t == c && t != '\\' && t != '\"') + meta1_parse_error (_("unknown escape sequence '\\%c'"), c); + } + mu_opool_append_char (meta1_pool, t); +} + +void +meta1_line_add_unescape_last (const char *text, size_t len) +{ + mu_opool_append (meta1_pool, 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--) + ; + mu_opool_append (meta1_pool, text, len - 2); + mu_opool_append_char (meta1_pool, (char) strtoul (text + len, NULL, 16)); +} + +void +meta1_line_begin () +{ + if (!meta1_pool) + mu_opool_create (&meta1_pool, 1); + else + mu_opool_clear (meta1_pool); +} + +char * +meta1_line_finish () +{ + mu_opool_append_char (meta1_pool, 0); + return mu_opool_finish (meta1_pool, NULL); +} + +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; + mu_debug_t debug; + + mu_diag_get_debug (&debug); + mu_debug_printf (debug, 0, "%s:%lu: ", meta1_locus.file, + (unsigned long) meta1_locus.line); + va_start (ap, fmt); + mu_debug_vprintf (debug, 0, fmt, ap); + mu_debug_printf (debug, 0, "\n"); + va_end (ap); + meta1_error_count++; +} + +void +meta1_lexer_set_debug () +{ + mu_log_level_t lev = mu_global_debug_level ("meta1"); + yy_flex_debug = (lev & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE7)); +} + +static int +_cfg_default_printer (void *unused, mu_log_level_t level, const char *str) +{ + fprintf (stderr, "%s", str); + return 0; +} + +mu_cfg_tree_t *meta1_parse_tree; + +/* 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) + { + mu_error (_("%s: cannot open file: %s"), name, mu_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; + if (rc == 0) + { + meta1_parse_tree = mu_alloc (sizeof (*meta1_parse_tree)); + mu_debug_create (&meta1_parse_tree->debug, NULL); + mu_debug_set_print (meta1_parse_tree->debug, _cfg_default_printer, NULL); + mu_debug_set_level (meta1_parse_tree->debug, + mu_global_debug_level ("meta1")); + meta1_parse_tree->node = meta1_parse_head; + meta1_parse_tree->pool = meta1_pool; + } + return rc; +} + + + + |