X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Flexer%2Fq2c.c;h=cf8e53ee5cb881529ead693e0328f66e520a300b;hb=774441e68b4d2e3a4b5c6975e9614dcd4369955e;hp=73788706748d3dbd91baf563578d4f62409e3b3c;hpb=dcf9b154cbcaa35c3d8459a201b77eec8bcb30bd;p=pspp diff --git a/src/language/lexer/q2c.c b/src/language/lexer/q2c.c index 7378870674..cf8e53ee5c 100644 --- a/src/language/lexer/q2c.c +++ b/src/language/lexer/q2c.c @@ -1,52 +1,48 @@ -/* q2c - parser generator for PSPP procedures. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2008, 2010 Free Software Foundation, Inc. - 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. + 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 of the License, 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. + 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ -#include #include #include #include #include #include -#include +#include +#include #include -#if HAVE_UNISTD_H #include -#endif -#include "str.h" - -/* Brokenness. */ -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 +/* GNU C allows the programmer to declare that certain functions take + printf-like arguments, never return, etc. Conditionalize these + declarations on whether gcc is in use. */ +#if __GNUC__ > 1 +#define ATTRIBUTE(X) __attribute__ (X) +#else +#define ATTRIBUTE(X) #endif -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif +/* Marks a function argument as possibly not used. */ +#define UNUSED ATTRIBUTE ((unused)) -/* -#if !HAVE_STRERROR -#include "misc/strerror.c" -#endif -*/ - -#include "debug-print.h" +/* Marks a function that will never return. */ +#define NO_RETURN ATTRIBUTE ((noreturn)) + +/* Mark a function as taking a printf- or scanf-like format + string as its FMT'th argument and that the FIRST'th argument + is the first one to be checked against the format string. */ +#define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (__printf__, FMT, FIRST))) /* Max length of an input line. */ #define MAX_LINE_LEN 1024 @@ -55,22 +51,22 @@ #define MAX_TOK_LEN 1024 /* argv[0]. */ -char *program_name; +static char *program_name; /* Have the input and output files been opened yet? */ -int is_open; +static bool is_open; /* Input, output files. */ -FILE *in, *out; +static FILE *in, *out; /* Input, output file names. */ -char *ifn, *ofn; +static char *ifn, *ofn; /* Input, output file line number. */ -int ln, oln = 1; +static int ln, oln = 1; /* Input line buffer, current position. */ -char *buf, *cp; +static char *buf, *cp; /* Token types. */ enum @@ -80,22 +76,20 @@ enum }; /* Current token: either one of the above, or a single character. */ -int token; +static int token; /* Token string value. */ -char *tokstr; +static char *tokstr; /* Utility functions. */ -char nullstr[] = ""; - /* Close all open files and delete the output file, on failure. */ static void finish_up (void) { if (!is_open) return; - is_open = 0; + is_open = false; fclose (in); fclose (out); if (remove (ofn) == -1) @@ -112,8 +106,8 @@ hcf (void) exit (EXIT_FAILURE); } -int fail (const char *, ...) PRINTF_FORMAT (1, 2); -int error (const char *, ...) PRINTF_FORMAT (1, 2); +int fail (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN; +int error (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN; /* Output an error message and terminate unsuccessfully. */ int @@ -154,14 +148,14 @@ static void * xmalloc (size_t size) { void *vp; - + if (size == 0) return NULL; - + vp = malloc (size); if (!vp) fail ("xmalloc(%lu): %s", (unsigned long) size, VME); - + return vp; } @@ -175,11 +169,11 @@ xstrdup (const char *s) assert (s != NULL); size = strlen (s) + 1; - + t = malloc (size); if (!t) fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME); - + memcpy (t, s, size); return t; } @@ -194,22 +188,22 @@ get_buffer (void) if (++cb >= 8) cb = 0; - + return b[cb]; } - + /* Copies a string to a static buffer, converting it to lowercase in the process, and returns a pointer to the static buffer. */ static char * st_lower (const char *s) { char *p, *cp; - + p = cp = get_buffer (); while (*s) *cp++ = tolower ((unsigned char) (*s++)); *cp++ = '\0'; - + return p; } @@ -224,23 +218,23 @@ st_upper (const char *s) while (*s) *cp++ = toupper ((unsigned char) (*s++)); *cp++ = '\0'; - + return p; } /* Returns the address of the first non-whitespace character in S, or the address of the null terminator if none. */ static char * -skip_ws (const char *s) +skip_ws (char *s) { while (isspace ((unsigned char) *s)) s++; - return (char *) s; + return s; } /* Read one line from the input file into buf. Lines having special formats are handled specially. */ -static int +static bool get_line (void) { ln++; @@ -248,7 +242,7 @@ get_line (void) { if (ferror (in)) fail ("%s: fgets: %s", ifn, strerror (errno)); - return 0; + return false; } cp = strchr (buf, '\n'); @@ -256,7 +250,7 @@ get_line (void) *cp = '\0'; cp = buf; - return 1; + return true; } /* Symbol table manager. */ @@ -341,7 +335,7 @@ find_symbol (int x) return iter; } -#if DEBUGGING +#if DUMP_TOKENS /* Writes a printable representation of the current token to stdout. */ static void @@ -359,7 +353,46 @@ dump_token (void) printf ("PUNCT\t%c\n", token); } } -#endif /* DEBUGGING */ +#endif /* DUMP_TOKENS */ + + +const char hyphen_proxy = '_'; + +static void +id_cpy (char **cp) +{ + char *dest = tokstr; + char *src = *cp; + + while (*src == '_' || *src == '-' || isalnum ((unsigned char) *src)) + { + *dest++ = *src == '-' ? hyphen_proxy :toupper ((unsigned char) (*src)); + src++; + } + + *cp = src; + *dest++ = '\0'; +} + +static char * +unmunge (const char *s) +{ + char *dest = xmalloc (strlen (s) + 1); + char *d = dest; + + while (*s) + { + if (*s == hyphen_proxy) + *d = '-'; + else + *d = *s; + s++; + d++; + } + *d = '\0'; + + return dest; +} /* Reads a token from the input file. */ static int @@ -371,11 +404,11 @@ lex_get (void) cp = skip_ws (cp); if (*cp != '\0') break; - + if (!get_line ()) fail ("%s: Unexpected end of file.", ifn); } - + if (*cp == '"') { char *dest = tokstr; @@ -402,17 +435,16 @@ lex_get (void) { char *dest = tokstr; token = T_ID; - while (*cp == '_' || isalnum ((unsigned char) *cp)) - *dest++ = toupper ((unsigned char) (*cp++)); - *dest++ = '\0'; + + id_cpy (&cp); } else token = *cp++; - -#if DEBUGGING + +#if DUMP_TOKENS dump_token (); #endif - + return token; } @@ -433,29 +465,29 @@ force_string (void) } /* Checks whether the current token is the identifier S; if so, skips - the token and returns 1; otherwise, returns 0. */ -static int + the token and returns true; otherwise, returns false. */ +static bool match_id (const char *s) { if (token == T_ID && !strcmp (tokstr, s)) { lex_get (); - return 1; + return true; } - return 0; + return false; } /* Checks whether the current token is T. If so, skips the token and - returns 1; otherwise, returns 0. */ -static int + returns true; otherwise, returns false. */ +static bool match_token (int t) { if (token == t) { lex_get (); - return 1; + return true; } - return 0; + return false; } /* Force the current token to be T, and skip it. */ @@ -474,7 +506,8 @@ enum { VAL_NONE, /* No value. */ VAL_INT, /* Integer value. */ - VAL_DBL /* Floating point value. */ + VAL_DBL, /* Floating point value. */ + VAL_STRING /* String value. */ }; /* For those specifiers with values, the syntax of those values. */ @@ -513,7 +546,7 @@ struct specifier setting *def; /* Default setting. */ setting *omit_kw; /* Setting for which the keyword can be omitted. */ - + int index; /* Next array index. */ }; @@ -552,7 +585,7 @@ struct subcommand int narray; /* Index of next array element. */ const char *prefix; /* Prefix for variable and constant names. */ specifier *spec; /* Array of specifiers. */ - + /* SBC_STRING and SBC_INT only. */ char *restriction; /* Expression restricting string length. */ char *message; /* Error message. */ @@ -603,7 +636,7 @@ static void parse_setting (setting *s, specifier *spec) { s->parent = spec; - + if (match_token ('*')) { if (spec->omit_kw) @@ -611,7 +644,7 @@ parse_setting (setting *s, specifier *spec) else spec->omit_kw = s; } - + if (match_token ('!')) { if (spec->def) @@ -619,7 +652,7 @@ parse_setting (setting *s, specifier *spec) else spec->def = s; } - + force_id (); s->specname = xstrdup (tokstr); s->con = add_symbol (s->specname, 0, 0); @@ -639,20 +672,22 @@ parse_setting (setting *s, specifier *spec) s->valtype = VT_PLAIN; s->optvalue = match_token ('*'); - + if (match_id ("N")) s->value = VAL_INT; else if (match_id ("D")) s->value = VAL_DBL; + else if (match_id ("S")) + s->value = VAL_STRING; else - error ("`n' or `d' expected."); - + error ("`n', `d', or `s' expected."); + skip_token (':'); - + force_id (); s->valname = xstrdup (tokstr); lex_get (); - + if (token == ',') { lex_get (); @@ -662,7 +697,7 @@ parse_setting (setting *s, specifier *spec) } else s->restriction = NULL; - + if (s->valtype == VT_PAREN) skip_token (')'); } @@ -684,7 +719,7 @@ parse_specifier (specifier *spec, subcommand *sbc) spec->varname = xstrdup (st_lower (tokstr)); lex_get (); } - + /* Handle array elements. */ if (token != ':') { @@ -700,20 +735,20 @@ parse_specifier (specifier *spec, subcommand *sbc) return; } skip_token (':'); - - if ( sbc->type == SBC_ARRAY && token == T_ID ) + + if ( sbc->type == SBC_ARRAY && token == T_ID ) { spec->varname = xstrdup (st_lower (tokstr)); spec->index = sbc->narray; sbc->narray++; } - - - + + + /* Parse all the settings. */ { setting **s = &spec->s; - + for (;;) { *s = xmalloc (sizeof **s); @@ -738,7 +773,7 @@ parse_specifiers (subcommand *sbc) *spec = NULL; return; } - + for (;;) { *spec = xmalloc (sizeof **spec); @@ -755,8 +790,6 @@ parse_specifiers (subcommand *sbc) static void parse_subcommand (subcommand *sbc) { - sbc->arity = ARITY_MANY; - if (match_token ('*')) { if (def) @@ -764,8 +797,9 @@ parse_subcommand (subcommand *sbc) def = sbc; } + sbc->arity = ARITY_ONCE_ONLY; if ( match_token('+')) - sbc->arity = ARITY_ONCE_ONLY ; + sbc->arity = ARITY_MANY; else if (match_token('^')) sbc->arity = ARITY_ONCE_EXACTLY ; @@ -773,7 +807,7 @@ parse_subcommand (subcommand *sbc) force_id (); sbc->name = xstrdup (tokstr); lex_get (); - + sbc->narray = 0; sbc->type = SBC_PLAIN; sbc->spec = NULL; @@ -784,10 +818,10 @@ parse_subcommand (subcommand *sbc) force_id (); sbc->prefix = xstrdup (st_lower (tokstr)); lex_get (); - + skip_token (']'); skip_token ('='); - + sbc->type = SBC_ARRAY; parse_specifiers (sbc); @@ -799,12 +833,12 @@ parse_subcommand (subcommand *sbc) force_id (); sbc->prefix = xstrdup (st_lower (tokstr)); lex_get (); - + skip_token (')'); } else sbc->prefix = ""; - + skip_token ('='); if (match_id ("VAR")) @@ -816,7 +850,7 @@ parse_subcommand (subcommand *sbc) force_string (); sbc->message = xstrdup (tokstr); lex_get(); - + skip_token (')'); } else sbc->message = NULL; @@ -826,7 +860,7 @@ parse_subcommand (subcommand *sbc) else if (match_id ("INTEGER")) { sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT; - if ( token == T_STRING) + if ( token == T_STRING) { sbc->restriction = xstrdup (tokstr); lex_get (); @@ -882,7 +916,7 @@ void parse_subcommands (void) { subcommand **sbc = &subcommands; - + for (;;) { *sbc = xmalloc (sizeof **sbc); @@ -925,7 +959,7 @@ dump (int indention, const char *format, ...) if (indention < 0) indent += BASE_INDENT * indention; - + oln++; va_start (args, format); for (i = 0; i < indent; i++) @@ -938,6 +972,19 @@ dump (int indention, const char *format, ...) indent += BASE_INDENT * indention; } +/* Writes a blank line to the output file and adjusts 'indent' by BASE_INDENT + * INDENTION characters. + + (This is only useful because GCC complains about using "" as a format + string, for whatever reason.) */ +static void +dump_blank_line (int indention) +{ + oln++; + indent += BASE_INDENT * indention; + putc ('\n', out); +} + /* Write the structure members for specifier SPEC to the output file. SBC is the including subcommand. */ static void @@ -945,7 +992,7 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc) { if (spec->varname) dump (0, "long %s%s;", sbc->prefix, spec->varname); - + { setting *s; @@ -955,8 +1002,11 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc) { const char *typename; - assert (s->value == VAL_INT || s->value == VAL_DBL); - typename = s->value == VAL_INT ? "long" : "double"; + assert (s->value == VAL_INT || s->value == VAL_DBL + || s->value == VAL_STRING); + typename = (s->value == VAL_INT ? "long" + : s->value == VAL_DBL ? "double" + : "char *"); dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname)); } @@ -964,8 +1014,8 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc) } } -/* Returns 1 if string T is a PSPP keyword, 0 otherwise. */ -static int +/* Returns true if string T is a PSPP keyword, false otherwise. */ +static bool is_keyword (const char *t) { static const char *kw[] = @@ -977,8 +1027,8 @@ is_keyword (const char *t) for (cp = kw; *cp; cp++) if (!strcmp (t, *cp)) - return 1; - return 0; + return true; + return false; } /* Transforms a string NAME into a valid C identifier: makes @@ -996,7 +1046,7 @@ make_identifier (const char *name) else *cp++ = '_'; *cp = '\0'; - + return p; } @@ -1006,6 +1056,8 @@ dump_declarations (void) { indent = 0; + dump (0, "struct dataset;"); + /* Write out enums for all the identifiers in the symbol table. */ { int f, k; @@ -1028,8 +1080,8 @@ dump_declarations (void) if (buf == NULL) buf = xmalloc (1024); else - dump (0, buf); - + dump (0, "%s", buf); + if (k) sprintf (buf, "%s%s,", st_upper (prefix), sym->name); else @@ -1041,13 +1093,13 @@ dump_declarations (void) if (buf) { buf[strlen (buf) - 1] = 0; - dump (0, buf); + dump (0, "%s", buf); free (buf); } if (f) { dump (-1, "};"); - dump (-1, nullstr); + dump_blank_line (-1); } } @@ -1066,7 +1118,7 @@ dump_declarations (void) if (sbc->type == SBC_ARRAY && sbc->narray) { dump (0, "/* Array indices for %s subcommand. */", sbc->name); - + dump (1, "enum"); dump (1, "{"); @@ -1081,7 +1133,7 @@ dump_declarations (void) dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix)); dump (-1, "};"); - dump (-1, nullstr); + dump_blank_line (-1); } } } @@ -1098,8 +1150,8 @@ dump_declarations (void) int f = 0; if (sbc != subcommands) - dump (0, nullstr); - + dump_blank_line (0); + dump (0, "/* %s subcommand. */", sbc->name); dump (0, "int sbc_%s;", st_lower (sbc->name)); @@ -1109,7 +1161,7 @@ dump_declarations (void) case SBC_PLAIN: { specifier *spec; - + for (spec = sbc->spec; spec; spec = spec->next) { if (spec->s == 0) @@ -1119,8 +1171,8 @@ dump_declarations (void) spec->varname); else if (f == 0) { - dump (0, "int a_%s[%s%scount];", - st_lower (sbc->name), + dump (0, "int a_%s[%s%scount];", + st_lower (sbc->name), st_upper (prefix), st_upper (sbc->prefix) ); @@ -1137,12 +1189,12 @@ dump_declarations (void) case SBC_VARLIST: dump (0, "size_t %sn_%s;", st_lower (sbc->prefix), st_lower (sbc->name)); - dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix), + dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix), st_lower (sbc->name)); break; case SBC_VAR: - dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix), + dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix), st_lower (sbc->name)); break; @@ -1176,12 +1228,12 @@ dump_declarations (void) } dump (-1, "};"); - dump (-1, nullstr); + dump_blank_line (-1); } /* Write out prototypes for custom_*() functions as necessary. */ { - int seen = 0; + bool seen = false; subcommand *sbc; for (sbc = subcommands; sbc; sbc = sbc->next) @@ -1189,27 +1241,27 @@ dump_declarations (void) { if (!seen) { - seen = 1; + seen = true; dump (0, "/* Prototype for custom subcommands of %s. */", cmdname); } - dump (0, "static int %scustom_%s (struct cmd_%s *);", + dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);", st_lower (prefix), st_lower (sbc->name), make_identifier (cmdname)); } if (seen) - dump (0, nullstr); + dump_blank_line (0); } /* Prototypes for parsing and freeing functions. */ { dump (0, "/* Command parsing functions. */"); - dump (0, "static int parse_%s (struct cmd_%s *);", + dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);", make_identifier (cmdname), make_identifier (cmdname)); dump (0, "static void free_%s (struct cmd_%s *);", make_identifier (cmdname), make_identifier (cmdname)); - dump (0, nullstr); + dump_blank_line (0); } } @@ -1229,7 +1281,7 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc) strcpy (s, "-1"); dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s); } - + { setting *s; @@ -1239,8 +1291,11 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc) { const char *init; - assert (s->value == VAL_INT || s->value == VAL_DBL); - init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS"; + assert (s->value == VAL_INT || s->value == VAL_DBL + || s->value == VAL_STRING); + init = (s->value == VAL_INT ? "LONG_MIN" + : s->value == VAL_DBL ? "SYSMIS" + : "NULL"); dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init); } @@ -1255,24 +1310,24 @@ dump_vars_init (int persistent) /* Loop through all the subcommands. */ { subcommand *sbc; - + for (sbc = subcommands; sbc; sbc = sbc->next) { int f = 0; - + dump (0, "p->sbc_%s = 0;", st_lower (sbc->name)); - if ( ! persistent ) + if ( ! persistent ) { switch (sbc->type) { case SBC_INT_LIST: - break; - case SBC_DBL_LIST: dump (1, "{"); dump (0, "int i;"); dump (1, "for (i = 0; i < MAXLISTS; ++i)"); - dump (0, "subc_list_double_create(&p->dl_%s[i]) ;", + dump (0, "subc_list_%s_create(&p->%cl_%s[i]) ;", + sbc->type == SBC_INT_LIST ? "int" : "double", + sbc->type == SBC_INT_LIST ? 'i' : 'd', st_lower (sbc->name) ); dump (-2, "}"); @@ -1289,12 +1344,12 @@ dump_vars_init (int persistent) case SBC_CUSTOM: /* nothing */ break; - + case SBC_PLAIN: case SBC_ARRAY: { specifier *spec; - + for (spec = sbc->spec; spec; spec = spec->next) if (spec->s == NULL) { @@ -1318,7 +1373,7 @@ dump_vars_init (int persistent) dump (0, "p->%sv_%s = NULL;", st_lower (sbc->prefix), st_lower (sbc->name)); break; - + case SBC_VAR: dump (0, "p->%sv_%s = NULL;", st_lower (sbc->prefix), st_lower (sbc->name)); @@ -1333,12 +1388,12 @@ dump_vars_init (int persistent) dump (1, "{"); dump (0, "int i;"); dump (1, "for (i = 0; i < MAXLISTS; ++i)"); - dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name)); + dump (0, "p->n_%s[i] = LONG_MIN;", st_lower (sbc->name)); dump (-2, "}"); break; default: - assert (0); + abort (); } } } @@ -1356,20 +1411,24 @@ make_match (const char *t) while (*t == '_') t++; - + if (is_keyword (t)) - sprintf (s, "lex_match (T_%s)", t); + sprintf (s, "lex_match (lexer, T_%s)", t); else if (!strcmp (t, "ON") || !strcmp (t, "YES")) - strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") " - "|| lex_match_id (\"TRUE\"))"); + strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") " + "|| lex_match_id (lexer, \"TRUE\"))"); else if (!strcmp (t, "OFF") || !strcmp (t, "NO")) - strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") " - "|| lex_match_id (\"FALSE\"))"); + strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") " + "|| lex_match_id (lexer, \"FALSE\"))"); else if (isdigit ((unsigned char) t[0])) - sprintf (s, "lex_match_int (%s)", t); + sprintf (s, "lex_match_int (lexer, %s)", t); else - sprintf (s, "lex_match_id (\"%s\")", t); - + { + char *c = unmunge (t); + sprintf (s, "lex_match_hyphenated_word (lexer, \"%s\")", c); + free (c); + } + return s; } @@ -1386,7 +1445,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) if (spec->omit_kw && spec->omit_kw->parent->next) error ("Default specifier is not in last specifier in `%s' " "subcommand.", sbc->name); - + for (s = spec->s; s; s = s->next) { int first = spec == sbc->spec && s == spec->s; @@ -1414,13 +1473,13 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) { if (spec->omit_kw != s) dump (1, "{"); - + if (spec->varname) { dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname, st_upper (prefix), find_symbol (s->con)->name); - if ( sbc->type == SBC_ARRAY ) + if ( sbc->type == SBC_ARRAY ) dump (0, "p->a_%s[%s%s%s] = 1;", st_lower (sbc->name), st_upper (prefix), st_upper (sbc->prefix), @@ -1432,12 +1491,12 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) { if (s->optvalue) { - dump (1, "if (lex_match ('('))"); + dump (1, "if (lex_match (lexer, '('))"); dump (1, "{"); } else { - dump (1, "if (!lex_match ('('))"); + dump (1, "if (!lex_match (lexer, '('))"); dump (1, "{"); dump (0, "msg (SE, _(\"`(' expected after %s " "specifier of %s subcommand.\"));", @@ -1450,29 +1509,45 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) if (s->value == VAL_INT) { - dump (1, "if (!lex_is_integer ())"); + dump (1, "if (!lex_is_integer (lexer))"); dump (1, "{"); dump (0, "msg (SE, _(\"%s specifier of %s subcommand " "requires an integer argument.\"));", s->specname, sbc->name); dump (0, "goto lossage;"); dump (-1, "}"); - dump (-1, "p->%s%s = lex_integer ();", + dump (-1, "p->%s%s = lex_integer (lexer);", sbc->prefix, st_lower (s->valname)); } - else + else if (s->value == VAL_DBL) { - dump (1, "if (!lex_is_number ())"); + dump (1, "if (!lex_is_number (lexer))"); dump (1, "{"); dump (0, "msg (SE, _(\"Number expected after %s " "specifier of %s subcommand.\"));", s->specname, sbc->name); dump (0, "goto lossage;"); dump (-1, "}"); - dump (-1, "p->%s%s = tokval;", sbc->prefix, + dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix, st_lower (s->valname)); } - + else if (s->value == VAL_STRING) + { + dump (1, "if (lex_token (lexer) != T_ID " + "&& !lex_is_string (lexer))"); + dump (1, "{"); + dump (0, "msg (SE, _(\"%s specifier of %s subcommand " + "requires a string argument.\"));", + s->specname, sbc->name); + dump (0, "goto lossage;"); + dump (-1, "}"); + dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname)); + dump (0, "p->%s%s = xstrdup (ds_cstr (lex_tokstr (lexer)));", + sbc->prefix, st_lower (s->valname)); + } + else + abort (); + if (s->restriction) { { @@ -1486,7 +1561,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) free (str); free (str2); } - + dump (1, "{"); dump (0, "msg (SE, _(\"Bad argument for %s " "specifier of %s subcommand.\"));", @@ -1495,12 +1570,12 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) dump (-1, "}"); outdent (); } - - dump (0, "lex_get ();"); - + + dump (0, "lex_get (lexer);"); + if (s->valtype == VT_PAREN) { - dump (1, "if (!lex_match (')'))"); + dump (1, "if (!lex_match (lexer, ')'))"); dump (1, "{"); dump (0, "msg (SE, _(\"`)' expected after argument for " "%s specifier of %s.\"));", @@ -1514,11 +1589,11 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) outdent (); } } - + if (s != spec->omit_kw) dump (-1, "}"); } - + if (s == spec->omit_kw) { dump (-1, "}"); @@ -1536,9 +1611,9 @@ dump_subcommand (const subcommand *sbc) { int count; - dump (1, "while (token != '/' && token != '.')"); + dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')"); dump (1, "{"); - + { specifier *spec; @@ -1563,7 +1638,7 @@ dump_subcommand (const subcommand *sbc) } } } - + { specifier *spec; setting *s; @@ -1587,20 +1662,20 @@ dump_subcommand (const subcommand *sbc) { dump (1, "else"); dump (1, "{"); - dump (0, "lex_error (NULL);"); + dump (0, "lex_error (lexer, NULL);"); dump (0, "goto lossage;"); dump (-1, "}"); outdent (); } } - dump (0, "lex_match (',');"); + dump (0, "lex_match (lexer, ',');"); dump (-1, "}"); outdent (); } else if (sbc->type == SBC_VARLIST) { - dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, " + dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, " "PV_APPEND%s%s))", st_lower (sbc->prefix), st_lower (sbc->name), st_lower (sbc->prefix), st_lower (sbc->name), @@ -1611,7 +1686,7 @@ dump_subcommand (const subcommand *sbc) } else if (sbc->type == SBC_VAR) { - dump (0, "p->%sv_%s = parse_variable ();", + dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));", st_lower (sbc->prefix), st_lower (sbc->name)); dump (1, "if (!p->%sv_%s)", st_lower (sbc->prefix), st_lower (sbc->name)); @@ -1625,12 +1700,12 @@ dump_subcommand (const subcommand *sbc) dump (1, "{"); dump (0, "int x;"); } - dump (1, "if (!lex_force_string ())"); - dump (0, "return 0;"); + dump (1, "if (!lex_force_string (lexer))"); + dump (0, "return false;"); outdent (); if (sbc->restriction) { - dump (0, "x = ds_length (&tokstr);"); + dump (0, "x = ds_length (lex_tokstr (lexer));"); dump (1, "if (!(%s))", sbc->restriction); dump (1, "{"); dump (0, "msg (SE, _(\"String for %s must be %s.\"));", @@ -1640,35 +1715,35 @@ dump_subcommand (const subcommand *sbc) outdent (); } dump (0, "free(p->s_%s);", st_lower(sbc->name) ); - dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));", + dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));", st_lower (sbc->name)); - dump (0, "lex_get ();"); + dump (0, "lex_get (lexer);"); if (sbc->restriction) dump (-1, "}"); } else if (sbc->type == SBC_DBL) { - dump (1, "if (!lex_force_num ())"); + dump (1, "if (!lex_force_num (lexer))"); dump (0, "goto lossage;"); - dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();", + dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);", st_lower (sbc->name), st_lower (sbc->name) ); - dump (0, "lex_get();"); + dump (0, "lex_get(lexer);"); } else if (sbc->type == SBC_INT) { dump(1, "{"); dump(0, "int x;"); - dump (1, "if (!lex_force_int ())"); + dump (1, "if (!lex_force_int (lexer))"); dump (0, "goto lossage;"); - dump (-1, "x = lex_integer ();"); - dump (0, "lex_get();"); + dump (-1, "x = lex_integer (lexer);"); + dump (0, "lex_get(lexer);"); if (sbc->restriction) { char buf[1024]; dump (1, "if (!(%s))", sbc->restriction); - dump (1, "{"); + dump (1, "{"); sprintf(buf,sbc->message,sbc->name); - if ( sbc->translatable ) + if ( sbc->translatable ) dump (0, "msg (SE, gettext(\"%s\"));",buf); else dump (0, "msg (SE, \"%s\");",buf); @@ -1680,13 +1755,13 @@ dump_subcommand (const subcommand *sbc) } else if (sbc->type == SBC_PINT) { - dump (0, "lex_match ('(');"); - dump (1, "if (!lex_force_int ())"); + dump (0, "lex_match (lexer, '(');"); + dump (1, "if (!lex_force_int (lexer))"); dump (0, "goto lossage;"); - dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name)); - dump (0, "lex_match (')');"); + dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name)); + dump (0, "lex_match (lexer, ')');"); } - else if (sbc->type == SBC_DBL_LIST) + else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST) { dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name)); dump (1, "{"); @@ -1694,25 +1769,26 @@ dump_subcommand (const subcommand *sbc) dump (0, "goto lossage;"); dump (-1,"}"); - dump (1, "while (token != '/' && token != '.')"); + dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')"); dump (1, "{"); - dump (0, "lex_match(',');"); - dump (0, "if (!lex_force_num ())"); + dump (0, "lex_match (lexer, ',');"); + dump (0, "if (!lex_force_num (lexer))"); dump (1, "{"); dump (0, "goto lossage;"); dump (-1,"}"); - dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());", - st_lower (sbc->name),st_lower (sbc->name) - ); + dump (0, "subc_list_%s_push (&p->%cl_%s[p->sbc_%s-1], lex_number (lexer));", + sbc->type == SBC_INT_LIST ? "int" : "double", + sbc->type == SBC_INT_LIST ? 'i' : 'd', + st_lower (sbc->name), st_lower (sbc->name)); - dump (0, "lex_get();"); + dump (0, "lex_get (lexer);"); dump (-1,"}"); } else if (sbc->type == SBC_CUSTOM) { - dump (1, "switch (%scustom_%s (p))", + dump (1, "switch (%scustom_%s (lexer, ds, p, aux))", st_lower (prefix), st_lower (sbc->name)); dump (0, "{"); dump (1, "case 0:"); @@ -1722,11 +1798,11 @@ dump_subcommand (const subcommand *sbc) dump (0, "break;"); dump (-1, "case 2:"); indent (); - dump (0, "lex_error (NULL);"); + dump (0, "lex_error (lexer, NULL);"); dump (0, "goto lossage;"); dump (-1, "default:"); indent (); - dump (0, "assert (0);"); + dump (0, "NOT_REACHED ();"); dump (-1, "}"); outdent (); } @@ -1741,7 +1817,9 @@ dump_parser (int persistent) indent = 0; dump (0, "static int"); - dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname), + dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)", + make_identifier (cmdname), + (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED", make_identifier (cmdname)); dump (1, "{"); @@ -1754,19 +1832,19 @@ dump_parser (int persistent) if (def && (def->type == SBC_VARLIST)) { if (def->type == SBC_VARLIST) - dump (1, "if (token == T_ID " - "&& dict_lookup_var (default_dict, tokid) != NULL " - "&& lex_look_ahead () != '=')"); + dump (1, "if (lex_token (lexer) == T_ID " + "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL " + "&& lex_look_ahead (lexer) != '=')"); else { - dump (0, "if ((token == T_ID " - "&& dict_lookup_var (default_dict, tokid) " + dump (0, "if ((lex_token (lexer) == T_ID " + "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) " "&& lex_look_ahead () != '=')"); dump (1, " || token == T_ALL)"); } dump (1, "{"); dump (0, "p->sbc_%s++;", st_lower (def->name)); - dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, " + dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, " "PV_APPEND))", st_lower (def->prefix), st_lower (def->name), st_lower (def->prefix), st_lower (def->name)); @@ -1777,7 +1855,7 @@ dump_parser (int persistent) } else if (def && def->type == SBC_CUSTOM) { - dump (1, "switch (%scustom_%s (p))", + dump (1, "switch (%scustom_%s (lexer, ds, p, aux))", st_lower (prefix), st_lower (def->name)); dump (0, "{"); dump (1, "case 0:"); @@ -1791,11 +1869,11 @@ dump_parser (int persistent) dump (0, "break;"); dump (-1, "default:"); indent (); - dump (0, "assert (0);"); + dump (0, "NOT_REACHED ();"); dump (-1, "}"); outdent (); } - + { subcommand *sbc; @@ -1805,7 +1883,7 @@ dump_parser (int persistent) f = 1; dump (1, "{"); - dump (0, "lex_match ('=');"); + dump (0, "lex_match (lexer, '=');"); dump (0, "p->sbc_%s++;", st_lower (sbc->name)); if (sbc->arity != ARITY_MANY) { @@ -1825,33 +1903,33 @@ dump_parser (int persistent) /* Now deal with the /ALGORITHM subcommand implicit to all commands */ - dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))"); + dump(1,"else if ( settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))"); dump(1,"{"); - dump (0, "lex_match ('=');"); + dump (0, "lex_match (lexer, '=');"); - dump(1,"if (lex_match_id(\"COMPATIBLE\"))"); - dump(0,"set_cmd_algorithm(COMPATIBLE);"); + dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))"); + dump(0,"settings_set_cmd_algorithm (COMPATIBLE);"); outdent(); - dump(1,"else if (lex_match_id(\"ENHANCED\"))"); - dump(0,"set_cmd_algorithm(ENHANCED);"); + dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))"); + dump(0,"settings_set_cmd_algorithm (ENHANCED);"); dump (-1, "}"); outdent (); - - dump (1, "if (!lex_match ('/'))"); + + dump (1, "if (!lex_match (lexer, '/'))"); dump (0, "break;"); dump (-2, "}"); outdent (); - dump (0, nullstr); - dump (1, "if (token != '.')"); + dump_blank_line (0); + dump (1, "if (lex_token (lexer) != '.')"); dump (1, "{"); - dump (0, "lex_error (_(\"expecting end of command\"));"); + dump (0, "lex_error (lexer, _(\"expecting end of command\"));"); dump (0, "goto lossage;"); dump (-1, "}"); - dump (0, nullstr); + dump_blank_line (0); outdent (); @@ -1862,7 +1940,7 @@ dump_parser (int persistent) for (sbc = subcommands; sbc; sbc = sbc->next) { - if ( sbc->arity == ARITY_ONCE_EXACTLY ) + if ( sbc->arity == ARITY_ONCE_EXACTLY ) { dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name)); dump (1, "{"); @@ -1870,19 +1948,19 @@ dump_parser (int persistent) sbc->name); dump (0, "goto lossage;"); dump (-1, "}"); - dump (0, nullstr); + dump_blank_line (0); } } } - dump (-1, "return 1;"); - dump (0, nullstr); + dump (-1, "return true;"); + dump_blank_line (0); dump (-1, "lossage:"); indent (); dump (0, "free_%s (p);", make_identifier (cmdname)); - dump (0, "return 0;"); + dump (0, "return false;"); dump (-1, "}"); - dump (0, nullstr); + dump_blank_line (0); } @@ -1890,18 +1968,10 @@ dump_parser (int persistent) static void dump_header (void) { - time_t curtime; - struct tm *loctime; - char *timep; - indent = 0; - curtime = time (NULL); - loctime = localtime (&curtime); - timep = asctime (loctime); - timep[strlen (timep) - 1] = 0; dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn); - dump (0, nullstr); - dump (0, " Generated by q2c from %s on %s.", ifn, timep); + dump_blank_line (0); + dump (0, " Generated by q2c from %s.", ifn); dump (0, " Do not modify!"); dump (0, " */"); } @@ -1916,16 +1986,12 @@ dump_free (int persistent) indent = 0; used = 0; - if ( ! persistent ) + if ( ! persistent ) { for (sbc = subcommands; sbc; sbc = sbc->next) - { - if (sbc->type == SBC_STRING) - used = 1; - if (sbc->type == SBC_DBL_LIST) - used = 1; - } - + used = (sbc->type == SBC_STRING + || sbc->type == SBC_DBL_LIST + || sbc->type == SBC_INT_LIST); } dump (0, "static void"); @@ -1933,25 +1999,42 @@ dump_free (int persistent) make_identifier (cmdname), used ? "" : " UNUSED"); dump (1, "{"); - if ( ! persistent ) + if ( ! persistent ) { for (sbc = subcommands; sbc; sbc = sbc->next) { - switch (sbc->type) + switch (sbc->type) { case SBC_VARLIST: - dump (0, "free (p->v_variables);"); + dump (0, "free (p->v_%s);", st_lower (sbc->name)); break; case SBC_STRING: dump (0, "free (p->s_%s);", st_lower (sbc->name)); break; case SBC_DBL_LIST: - dump (0, "int i;"); - dump (1, "for(i = 0; i < MAXLISTS ; ++i)"); - dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name)); + case SBC_INT_LIST: + dump (0, "{"); + dump (1, "int i;"); + dump (2, "for(i = 0; i < MAXLISTS ; ++i)"); + dump (1, "subc_list_%s_destroy(&p->%cl_%s[i]);", + sbc->type == SBC_INT_LIST ? "int" : "double", + sbc->type == SBC_INT_LIST ? 'i' : 'd', + st_lower (sbc->name)); + dump (0, "}"); outdent(); break; + case SBC_PLAIN: + { + specifier *spec; + setting *s; + + for (spec = sbc->spec; spec; spec = spec->next) + for (s = spec->s; s; s = s->next) + if (s->value == VAL_STRING) + dump (0, "free (p->%s%s);", + sbc->prefix, st_lower (s->valname)); + } default: break; } @@ -1971,7 +2054,7 @@ recognize_directive (void) { static char directive[16]; char *sp, *ep; - + sp = skip_ws (buf); if (strncmp (sp, "/*", 2)) return NULL; @@ -1990,7 +2073,7 @@ recognize_directive (void) directive[ep - sp] = '\0'; return directive; } - + int main (int argc, char *argv[]) { @@ -2008,7 +2091,7 @@ main (int argc, char *argv[]) if (!out) fail ("%s: open: %s.", ofn, strerror (errno)); - is_open = 1; + is_open = true; buf = xmalloc (MAX_LINE_LEN); tokstr = xmalloc (MAX_TOK_LEN); @@ -2025,7 +2108,7 @@ main (int argc, char *argv[]) dump (0, "%s", buf); continue; } - + dump (0, "#line %d \"%s\"", oln + 1, ofn); if (!strcmp (directive, "specification")) { @@ -2043,30 +2126,34 @@ main (int argc, char *argv[]) indent = 0; dump (0, "#include "); - dump (0, "#include \"alloc.h\""); - dump (0, "#include \"message.h\""); - dump (0, "#include \"lexer.h\""); - dump (0, "#include \"settings.h\""); - dump (0, "#include \"str.h\""); - dump (0, "#include \"subcommand-list.h\""); - dump (0, "#include \"variable.h\""); - dump (0, nullstr); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump (0, "#include "); + dump_blank_line (0); + + dump (0, "#include \"xalloc.h\""); + dump_blank_line (0); dump (0, "#include \"gettext.h\""); dump (0, "#define _(msgid) gettext (msgid)"); - dump (0, nullstr); + dump_blank_line (0); } else if (!strcmp (directive, "declarations")) dump_declarations (); else if (!strcmp (directive, "functions")) { dump_parser (0); - dump_free (0); + dump_free (0); } else if (!strcmp (directive, "_functions")) { dump_parser (1); - dump_free (1); + dump_free (1); } else error ("unknown directive `%s'", directive); @@ -2074,7 +2161,5 @@ main (int argc, char *argv[]) dump (0, "#line %d \"%s\"", ln + 1, ifn); } - - return EXIT_SUCCESS; }