diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-05-11 05:01:49 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-05-11 05:01:49 +0000 |
commit | 4785154fda6411a384a4ead5abb18c22bb77a8f0 (patch) | |
tree | a066bdac8c98434cb3b0edaf13ee4f48769117b9 | |
parent | 19f30b06d3dacb1ab87ebc654411ea84e6123d08 (diff) | |
download | gdbm-4785154fda6411a384a4ead5abb18c22bb77a8f0.tar.gz gdbm-4785154fda6411a384a4ead5abb18c22bb77a8f0.tar.bz2 |
Rewrite gdbmtool parser.
* src/testgdbm.c: Remove.
* src/gdbmtool.c: New file.
* src/gdbmtool.h: New file.
* src/gram.y: New file.
* src/lex.l: New file.
* src/Makefile.am: Update.
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/.cvsignore | 4 | ||||
-rw-r--r-- | src/Makefile.am | 11 | ||||
-rw-r--r-- | src/gdbmtool.c (renamed from src/testgdbm.c) | 384 | ||||
-rw-r--r-- | src/gdbmtool.h | 122 | ||||
-rw-r--r-- | src/gram.y | 107 | ||||
-rw-r--r-- | src/lex.l | 263 |
8 files changed, 705 insertions, 201 deletions
@@ -1,3 +1,14 @@ +2013-05-11 Sergey Poznyakoff <gray@gnu.org.ua> + + Rewrite gdbmtool parser. + + * src/testgdbm.c: Remove. + * src/gdbmtool.c: New file. + * src/gdbmtool.h: New file. + * src/gram.y: New file. + * src/lex.l: New file. + * src/Makefile.am: Update. + 2013-05-09 Sergey Poznyakoff <gray@gnu.org.ua> Add new prompt escapes. diff --git a/configure.ac b/configure.ac index ce00344..f2a37e5 100644 --- a/configure.ac +++ b/configure.ac @@ -84,8 +84,8 @@ AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LIBTOOL AC_SYS_LARGEFILE -dnl AC_PROG_RANLIB -dnl AC_C_BIGENDIAN([]) +AC_PROG_YACC +AC_PROG_LEX AC_C_CONST dnl Internationalization macros. diff --git a/src/.cvsignore b/src/.cvsignore index 70e7a26..bc1099e 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -6,7 +6,9 @@ Makefile.in gdbm.h *.lo libgdbm.la -testgdbm gdbmtool gdbm_dump gdbm_load +gram.[ch] +gram.output +lex.c diff --git a/src/Makefile.am b/src/Makefile.am index 7b1a2d2..d5561ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,7 +77,16 @@ libgdbmapp_a_SOURCES =\ # Programs bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump + gdbmtool_LDADD = ./libgdbmapp.a ./libgdbm.la -gdbmtool_SOURCES = testgdbm.c +gdbmtool_SOURCES = \ + gram.y\ + lex.l\ + gdbmtool.h\ + gdbmtool.c + +AM_YFLAGS = -dtv +#AM_LFLAGS = -d + gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la diff --git a/src/testgdbm.c b/src/gdbmtool.c index 5214526..82da808 100644 --- a/src/testgdbm.c +++ b/src/gdbmtool.c @@ -15,12 +15,8 @@ You should have received a copy of the GNU General Public License along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ -/* Include system configuration before all else. */ -#include "autoconf.h" - -#include "gdbmdefs.h" +#include "gdbmtool.h" #include "gdbm.h" -#include "gdbmapp.h" #include <errno.h> #include <ctype.h> @@ -34,8 +30,6 @@ # include <locale.h> #endif -const char *progname; /* Program name */ - #define DEFAULT_PROMPT "%p>%_" char *prompt; @@ -67,22 +61,6 @@ terror (int code, const char *fmt, ...) exit (code); } -void -syntax_error (const char *fmt, ...) -{ - va_list ap; - if (!interactive) - fprintf (stderr, "%s: ", progname); - fprintf (stderr, "%u: ", input_line); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - if (!interactive) - exit (EXIT_USAGE); -} - - size_t bucket_print_lines (hash_bucket *bucket) @@ -870,7 +848,7 @@ expand_char (int c) } void -outprompt () +print_prompt () { char *s; @@ -906,7 +884,6 @@ struct command { char *name; /* Command name */ size_t len; /* Name length */ - int abbrev; /* Single-letter shortkey (optional) */ int (*begin) (struct handler_param *param, size_t *); void (*handler) (struct handler_param *param); void (*end) (void *data); @@ -917,81 +894,81 @@ struct command struct command command_tab[] = { #define S(s) #s, sizeof (#s) - 1 - { S(count), 'c', + { S(count), NULL, count_handler, NULL, { NULL, NULL, }, N_("count (number of entries)") }, - { S(delete), 'd', + { S(delete), NULL, delete_handler, NULL, { N_("key"), NULL, }, N_("delete") }, - { S(export), 'e', + { S(export), NULL, export_handler, NULL, { N_("file"), "[truncate]", "[binary|ascii]" }, N_("export") }, - { S(fetch), 'f', + { S(fetch), NULL, fetch_handler, NULL, { N_("key"), NULL }, N_("fetch") }, - { S(import), 'i', + { S(import), NULL, import_handler, NULL, { N_("file"), "[replace]", "[nometa]" }, N_("import") }, - { S(list), 'l', + { S(list), list_begin, list_handler, NULL, { NULL, NULL }, N_("list") }, - { S(next), 'n', + { S(next), NULL, nextkey_handler, NULL, { N_("[key]"), NULL }, N_("nextkey") }, - { S(store), 's', + { S(store), NULL, store_handler, NULL, { N_("key"), N_("data") }, N_("store") }, - { S(first), '1', + { S(first), NULL, firstkey_handler, NULL, { NULL, NULL }, N_("firstkey") }, - { S(read), '<', + { S(read), NULL, read_handler, NULL, { N_("file"), "[replace]" }, N_("read entries from file and store") }, - { S(reorganize), 'r', + { S(reorganize), NULL, reorganize_handler, NULL, { NULL, NULL, }, N_("reorganize") }, - { S(key-zero), 'z', + { S(key-zero), NULL, key_z_handler, NULL, { NULL, NULL }, N_("toggle key nul-termination") }, - { S(avail), 'A', + { S(avail), avail_begin, avail_handler, NULL, { NULL, NULL, }, N_("print avail list") }, - { S(bucket), 'B', + { S(bucket), print_bucket_begin, print_current_bucket_handler, NULL, { N_("bucket-number"), NULL, }, N_("print a bucket") }, - { S(current), 'C', + { S(current), print_current_bucket_begin, print_current_bucket_handler, NULL, { NULL, NULL, }, N_("print current bucket") }, - { S(dir), 'D', + { S(dir), print_dir_begin, print_dir_handler, NULL, { NULL, NULL, }, N_("print hash directory") }, - { S(header), 'F', + { S(header), print_header_begin , print_header_handler, NULL, { NULL, NULL, }, N_("print file header") }, - { S(hash), 'H', + { S(hash), NULL, hash_handler, NULL, { N_("key"), NULL, }, N_("hash value of key") }, - { S(cache), 'K', + { S(cache), print_cache_begin, print_cache_handler, NULL, { NULL, NULL, }, N_("print the bucket cache") }, - { S(status), 'S', + { S(status), NULL, status_handler, NULL, { NULL, NULL }, N_("print current program status") }, - { S(version), 'v', + { S(version), NULL, print_version_handler, NULL, { NULL, NULL, }, N_("print version of gdbm") }, - { S(data-zero), 'Z', + { S(data-zero), NULL, data_z_handler, NULL, { NULL, NULL }, N_("toggle data nul-termination") }, - { S(help), '?', + { S(help), help_begin, help_handler, NULL, { NULL, NULL, }, N_("print this help list") }, - { S(prompt), 0, + { S(prompt), NULL, prompt_handler, NULL, { N_("text") }, N_("set command prompt") }, - { S(quit), 'q', + { S(quit), NULL, quit_handler, NULL, { NULL, NULL, }, N_("quit the program") }, #undef S @@ -1036,12 +1013,7 @@ help_handler (struct handler_param *param) int i; int n; - if (cmd->abbrev) - n = fprintf (fp, " %c, ", cmd->abbrev); - else - n = fprintf (fp, " "); - - n += fprintf (fp, "%s", cmd->name); + n = fprintf (fp, " %s", cmd->name); for (i = 0; i < NARGS && cmd->args[i]; i++) n += fprintf (fp, " %s", gettext (cmd->args[i])); @@ -1054,19 +1026,12 @@ help_handler (struct handler_param *param) } struct command * -find_command (char *str) +find_command (const char *str) { enum { fcom_init, fcom_found, fcom_ambig, fcom_abort } state = fcom_init; struct command *cmd, *found = NULL; size_t len = strlen (str); - if (len == 1) - { - for (cmd = command_tab; cmd->name; cmd++) - if (cmd->abbrev == *str) - return cmd; - } - for (cmd = command_tab; state != fcom_abort && cmd->name; cmd++) { if (memcmp (cmd->name, str, len < cmd->len ? len : cmd->len) == 0) @@ -1097,30 +1062,11 @@ find_command (char *str) } if (state == fcom_init) - terror (0, interactive ? _("Invalid command. Try ? for help.") : - _("Unknown command")); + syntax_error (interactive ? _("Invalid command. Try ? for help.") : + _("Unknown command")); return found; } - -#define SKIPWS(p) while (*(p) && isspace (*(p))) (p)++ -#define SKIPWORD(p) while (*(p) && !isspace (*(p))) (p)++ - -char * -getword (char *s, char **endp) -{ - char *p; - SKIPWS (s); - p = s; - SKIPWORD (s); - if (*s) - { - *s++ = 0; - SKIPWS (s); - } - *endp = s; - return p; -} - + char *parseopt_program_doc = N_("examine and/or modify a GDBM database"); char *parseopt_program_args = N_("DBFILE"); @@ -1139,6 +1085,156 @@ struct gdbm_option optab[] = { #define ARGINC 16 + +void +gdbmarglist_init (struct gdbmarglist *lst, struct gdbmarg *arg) +{ + if (arg) + arg->next = NULL; + lst->head = lst->tail = arg; +} + +void +gdbmarglist_add (struct gdbmarglist *lst, struct gdbmarg *arg) +{ + arg->next = NULL; + if (lst->tail) + lst->tail->next = arg; + else + lst->head = arg; + lst->tail = arg; +} + +void +gdbmarglist_free (struct gdbmarglist *lst) +{ + struct gdbmarg *arg; + + for (arg = lst->head; arg; ) + { + struct gdbmarg *next = arg->next; + free (arg->string); + free (arg); + arg = next; + } +} + +struct gdbmarg * +gdbmarg_new (char *string) +{ + struct gdbmarg *arg = emalloc (sizeof (*arg)); + arg->next = NULL; + arg->string = string; + return arg; +} + + +struct handler_param param; +size_t argmax; + +int +run_command (const char *verb, struct gdbmarglist *arglist) +{ + int i; + struct command *cmd; + struct gdbmarg *arg; + char *pager = getenv ("PAGER"); + char argbuf[128]; + size_t expected_lines, *expected_lines_ptr; + FILE *pagfp = NULL; + + cmd = find_command (verb); + if (!cmd) + return 1; + + arg = arglist ? arglist->head : NULL; + + for (i = 0; cmd->args[i] && arg; i++, arg = arg->next) + { + if (i >= argmax) + { + argmax += ARGINC; + param.argv = erealloc (param.argv, + sizeof (param.argv[0]) * argmax); + } + param.argv[i] = estrdup (arg->string); + } + + for (; cmd->args[i]; i++) + { + char *argname = cmd->args[i]; + if (*argname == '[') + /* Optional argument */ + break; + if (!interactive) + { + syntax_error (_("%s: not enough arguments"), cmd->name); + return 1; + } + printf ("%s? ", argname); + fflush (stdout); + if (fgets (argbuf, sizeof argbuf, stdin) == NULL) + terror (EXIT_USAGE, _("unexpected eof")); + + trimnl (argbuf); + if (i >= argmax) + { + argmax += ARGINC; + param.argv = erealloc (param.argv, + sizeof (param.argv[0]) * argmax); + } + param.argv[i] = estrdup (argbuf); + } + + if (arg) + { + syntax_error (_("%s: too many arguments"), cmd->name); + return 1; + } + + /* Prepare for calling the handler */ + param.argc = i; + param.fp = NULL; + param.data = NULL; + pagfp = NULL; + + expected_lines = 0; + expected_lines_ptr = (interactive && pager) ? &expected_lines : NULL; + if (!(cmd->begin && cmd->begin (¶m, expected_lines_ptr))) + { + if (pager && expected_lines > get_screen_lines ()) + { + pagfp = popen (pager, "w"); + if (pagfp) + param.fp = pagfp; + else + { + terror (0, _("cannot run pager `%s': %s"), pager, + strerror (errno)); + pager = NULL; + param.fp = stdout; + } + } + else + param.fp = stdout; + + cmd->handler (¶m); + if (cmd->end) + cmd->end (param.data); + else if (param.data) + free (param.data); + + if (pagfp) + pclose (pagfp); + } + + for (i = 0; i < param.argc; i++) + free (param.argv[i]); + param.argc = 0; + + return 0; +} + int main (int argc, char *argv[]) { @@ -1151,11 +1247,7 @@ main (int argc, char *argv[]) char reader = FALSE; char newdb = FALSE; int flags = 0; - char *pager = getenv ("PAGER"); - struct handler_param param; - size_t argmax; - set_progname (argv[0]); #ifdef HAVE_SETLOCALE @@ -1263,115 +1355,13 @@ main (int argc, char *argv[]) printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n")); if (interactive) prompt = estrdup (DEFAULT_PROMPT); - + memset (¶m, 0, sizeof (param)); argmax = 0; - - while (1) - { - int i; - char *p, *sp; - char argbuf[128]; - struct command *cmd; - size_t expected_lines, *expected_lines_ptr; - FILE *pagfp = NULL; - - for (i = 0; i < param.argc; i++) - free (param.argv[i]); - param.argc = 0; - - input_line++; - - if (interactive) - outprompt (); - - if (fgets (cmdbuf, sizeof cmdbuf, stdin) == NULL) - { - putchar ('\n'); - break; - } - - trimnl (cmdbuf); - p = getword (cmdbuf, &sp); - if (!*p) - continue; - cmd = find_command (p); - if (!cmd) - continue; - - for (i = 0; cmd->args[i]; i++) - { - char *arg = cmd->args[i]; - - p = getword (sp, &sp); - if (!*p) - { - if (*arg == '[') - /* Optional argument */ - break; - if (!interactive) - syntax_error (_("%s: not enough arguments"), cmd->name); - printf ("%s? ", arg); - if (fgets (argbuf, sizeof argbuf, stdin) == NULL) - terror (EXIT_USAGE, _("unexpected eof")); - - trimnl (argbuf); - p = argbuf; - } - - if (i >= argmax) - { - argmax += ARGINC; - param.argv = erealloc (param.argv, - sizeof (param.argv[0]) * argmax); - } - param.argv[i] = estrdup (p); - } - - if (*sp) - { - syntax_error (_("%s: too many arguments"), cmd->name); - continue; - } - - /* Prepare for calling the handler */ - param.argc = i; - param.fp = NULL; - param.data = NULL; - pagfp = NULL; - - expected_lines = 0; - expected_lines_ptr = (interactive && pager) ? &expected_lines : NULL; - if (cmd->begin && cmd->begin (¶m, expected_lines_ptr)) - continue; - if (pager && expected_lines > get_screen_lines ()) - { - pagfp = popen (pager, "w"); - if (pagfp) - param.fp = pagfp; - else - { - terror (0, _("cannot run pager `%s': %s"), pager, - strerror (errno)); - pager = NULL; - param.fp = stdout; - } - } - else - param.fp = stdout; - - cmd->handler (¶m); - if (cmd->end) - cmd->end (param.data); - else if (param.data) - free (param.data); - - if (pagfp) - pclose (pagfp); - - } - /* Quit normally. */ - quit_handler (NULL); + setsource ("stdin", stdin); + //FIXME + return yyparse (); + return 0; } diff --git a/src/gdbmtool.h b/src/gdbmtool.h new file mode 100644 index 0000000..f2807b9 --- /dev/null +++ b/src/gdbmtool.h @@ -0,0 +1,122 @@ +/* This file is part of GDBM, the GNU data base manager. + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation, + Inc. + + GDBM 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. + + GDBM 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 GDBM. If not, see <http://www.gnu.org/licenses/>. */ + +#include "autoconf.h" +#include "gdbmdefs.h" +#include "gdbm.h" +#include "gdbmapp.h" +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +/* Position in input file */ +struct point +{ + char *file; /* file name */ + unsigned line; /* line number */ + unsigned col; /* column number */ +}; + +/* Location in input file */ +struct locus +{ + struct point beg, end; +}; + +typedef struct locus gdbm_yyltype_t; + +#define YYLTYPE gdbm_yyltype_t + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + { \ + if (N) \ + { \ + (Current).beg = YYRHSLOC(Rhs, 1).beg; \ + (Current).end = YYRHSLOC(Rhs, N).end; \ + } \ + else \ + { \ + (Current).beg = YYRHSLOC(Rhs, 0).end; \ + (Current).end = (Current).beg; \ + } \ + } \ + while (0) + +#define YY_LOCATION_PRINT(File, Loc) \ + do \ + { \ + if ((Loc).beg.col == 0) \ + fprintf (File, "%s:%u", \ + (Loc).beg.file, \ + (Loc).beg.line); \ + else if (strcmp ((Loc).beg.file, (Loc).end.file)) \ + fprintf (File, "%s:%u.%u-%s:%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.file, \ + (Loc).end.line, (Loc).end.col); \ + else if ((Loc).beg.line != (Loc).end.line) \ + fprintf (File, "%s:%u.%u-%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.line, (Loc).end.col); \ + else if ((Loc).beg.col != (Loc).end.col) \ + fprintf (File, "%s:%u.%u-%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.col); \ + else \ + fprintf (File, "%s:%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line, \ + (Loc).beg.col); \ + } \ + while (0) + +void vparse_error (struct locus *loc, const char *fmt, va_list ap); +void parse_error (struct locus *loc, const char *fmt, ...); + +void syntax_error (const char *fmt, ...); + +void print_prompt (void); + +void setsource (const char *filename, FILE *file); + +extern int interactive; + +/* Argument to a command handler */ +struct gdbmarg +{ + struct gdbmarg *next; + char *string; +}; + +/* List of arguments */ +struct gdbmarglist +{ + struct gdbmarg *head, *tail; +}; + +void gdbmarglist_init (struct gdbmarglist *, struct gdbmarg *); +void gdbmarglist_add (struct gdbmarglist *, struct gdbmarg *); +void gdbmarglist_free (struct gdbmarglist *lst); + +struct gdbmarg *gdbmarg_new (char *); + +int run_command (const char *verb, struct gdbmarglist *arglist); + diff --git a/src/gram.y b/src/gram.y new file mode 100644 index 0000000..d9db0d7 --- /dev/null +++ b/src/gram.y @@ -0,0 +1,107 @@ +%{ +/* This file is part of GDBM, the GNU data base manager. + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation, + Inc. + + GDBM 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. + + GDBM 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 GDBM. If not, see <http://www.gnu.org/licenses/>. */ + +#include <autoconf.h> +#include "gdbmtool.h" + +%} + +%error-verbose +%locations + +%token <string> T_IDENT T_WORD +%type <string> arg verb +%type <arglist> arglist arg1list + +%union { + char *string; + struct gdbmarglist arglist; +} + +%% + +input : /* empty */ + | stmtlist + ; + +stmtlist : stmt + | stmtlist stmt + ; + +stmt : /* empty */ '\n' + | verb arglist '\n' + { + if (run_command ($1, &$2) && !interactive) + exit (EXIT_USAGE); + gdbmarglist_free (&$2); + } + | error '\n' + { + if (interactive) + { + yyclearin; + yyerrok; + } + else + YYERROR; + } + ; + +verb : T_IDENT + ; + +arglist : /* empty */ + { + gdbmarglist_init (&$$, NULL); + } + | arg1list + ; + +arg1list : arg + { + gdbmarglist_init (&$$, gdbmarg_new ($1)); + } + | arg1list arg + { + gdbmarglist_add (&$1, gdbmarg_new ($2)); + $$ = $1; + } + ; + +arg : T_IDENT + | T_WORD + ; + +%% + +void +syntax_error (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vparse_error (&yylloc, fmt, ap); + va_end (ap); +} + +int +yyerror (char *s) +{ + syntax_error ("%s", s); + return 0; +} diff --git a/src/lex.l b/src/lex.l new file mode 100644 index 0000000..7a8c99b --- /dev/null +++ b/src/lex.l @@ -0,0 +1,263 @@ +%{ +/* This file is part of GDBM, the GNU data base manager. + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation, + Inc. + + GDBM 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. + + GDBM 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 GDBM. If not, see <http://www.gnu.org/licenses/>. */ + +#include <autoconf.h> +#include "gdbmtool.h" +#include "gram.h" + +struct point point; + +/* Advance locus to the next line */ +void +advance_line () +{ + ++point.line; + point.col = 0; +} + +#define YY_USER_ACTION \ + do \ + { \ + if (YYSTATE == 0) \ + { \ + yylloc.beg = point; \ + yylloc.beg.col++; \ + } \ + point.col += yyleng; \ + yylloc.end = point; \ + } \ + while (0); + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + do \ + { \ + result = read_input (buf, max_size); \ + } \ + while (0); + +void string_begin (void); +void string_add (const char *s, int l); +void string_addc (int c); +char *string_end (void); +int unescape (int c); + +static ssize_t read_input (char *buf, size_t size); + +%} + +%x STR + +WS [ \t][ \t]* +IDENT [a-zA-Z_][a-zA-Z_0-9]* + +%% +^[ \t]*#[ \t]*line[ \t].*\n { + char *p, *q; + char *file = NULL; + int line, len; + + for (p = strchr (yytext, '#') + 1; *p == ' ' || *p == '\t'; p++); + p += 4; + for (; *p == ' ' || *p == '\t'; p++); + if (*p == '"') + { + p++; + len = strcspn (p, "\""); + if (p[len] == 0) + { + yyerror (_("invalid #line statement")); + REJECT; + } + file = emalloc (len + 1); + memcpy (file, p, len); + file[len] = 0; + for (p += len + 1; *p == ' ' || *p == '\t'; p++); + } + line = strtol (p, &q, 10); + if (*q && *q != ' ') + { + yyerror (_("invalid #line statement")); + free (file); + REJECT; + } + point.file = file; + point.line = line; + point.col = 0; +} +#.*\n advance_line (); +#.* /* end-of-file comment */; + +{IDENT} { yylval.string = estrdup (yytext); return T_IDENT; } +[^ \t\n{},=]+ { yylval.string = estrdup (yytext); return T_WORD; } +\"[^\\\"\n]*\" { yylval.string = emalloc (yyleng - 1); + memcpy (yylval.string, yytext+1, yyleng-2); + yylval.string[yyleng-2] = 0; + return T_WORD; } +\"[^\\\"\n]*\\. { string_begin (); + string_add (yytext + 1, yyleng - 3); + string_addc (unescape (yytext[yyleng-1])); + BEGIN(STR); } +<STR>[^\\\"\n]*\" { if (yyleng > 1) + string_add (yytext, yyleng - 1); + yylval.string = string_end (); + BEGIN(INITIAL); + return T_WORD; } +<STR>[^\\\"\n]*\\. { string_add (yytext, yyleng - 2); + string_addc (unescape (yytext[yyleng-1])); } +{WS} ; +\n { advance_line (); return '\n'; } +. return yytext[0]; +%% + +void +setsource (const char *filename, FILE *file) +{ + point.file = (char*) filename; + point.line = 1; + point.col = 0; + yyin = file; +} + +int +yywrap () +{ + return 1; +} + +static ssize_t +read_input (char *buf, size_t size) +{ + if (interactive) + { + if (YY_AT_BOL ()) + print_prompt (); + if (fgets (buf, size, yyin) == NULL) + return 0; + return strlen (buf); + } + return fread (buf, 1, size, yyin); +} + + +struct strseg +{ + struct strseg *next; + int len; + char ptr[1]; +}; + +static struct strseg *strseg_head, *strseg_tail; + +void +string_begin (void) +{ + strseg_head = strseg_tail = NULL; +} + +void +strseg_attach (struct strseg *seg) +{ + seg->next = NULL; + if (strseg_tail) + strseg_tail->next = seg; + else + strseg_head = seg; + strseg_tail = seg; +} + +void +string_add (const char *s, int l) +{ + struct strseg *seg = emalloc (sizeof (*seg) + l); + memcpy (seg->ptr, s, l); + seg->len = l; + strseg_attach (seg); +} + +void +string_addc (int c) +{ + struct strseg *seg = emalloc (sizeof (*seg)); + seg->ptr[0] = c; + seg->len = 1; + strseg_attach (seg); +} + +char * +string_end (void) +{ + int len = 1; + struct strseg *seg; + char *ret, *p; + + for (seg = strseg_head; seg; seg = seg->next) + len += seg->len; + + ret = emalloc (len); + p = ret; + for (seg = strseg_head; seg; ) + { + struct strseg *next = seg->next; + memcpy (p, seg->ptr, seg->len); + p += seg->len; + free (seg); + seg = next; + } + *p = 0; + + strseg_head = strseg_tail = NULL; + + return ret; +} + +int +unescape (int c) +{ + static char transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; + char *p; + + for (p = transtab; *p; p += 2) + { + if (*p == c) + return p[1]; + } + return c; +} + +void +vparse_error (struct locus *loc, const char *fmt, va_list ap) +{ + if (!interactive) + fprintf (stderr, "%s", progname); + if (loc) + YY_LOCATION_PRINT (stderr, *loc); + fprintf (stderr, ": "); + vfprintf (stderr, fmt, ap); + fputc ('\n', stderr); +} + +void +parse_error (struct locus *loc, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vparse_error (loc, fmt, ap); + va_end (ap); +} |