-/* q2c - parser generator for PSPP procedures.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
- Written by Ben Pfaff <blp@gnu.org>.
+/* 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. */
-
-#include <config.h>
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <time.h>
+#include <stdbool.h>
+#include <string.h>
#include <errno.h>
#include <unistd.h>
-#include <libpspp/compiler.h>
-#include <libpspp/str.h>
-#include "exit.h"
-
+/* 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
+
+/* Marks a function argument as possibly not used. */
+#define UNUSED ATTRIBUTE ((unused))
+
+/* 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
#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
};
/* Current token: either one of the above, or a single character. */
-int token;
+static int token;
/* Token string value. */
-char *tokstr;
+static char *tokstr;
\f
/* 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)
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
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;
}
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;
}
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;
}
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++;
{
if (ferror (in))
fail ("%s: fgets: %s", ifn, strerror (errno));
- return 0;
+ return false;
}
cp = strchr (buf, '\n');
*cp = '\0';
cp = buf;
- return 1;
+ return true;
}
\f
/* Symbol table manager. */
return iter;
}
-#if DUMP_TOKENS
+#if DUMP_TOKENS
/* Writes a printable representation of the current token to
stdout. */
static void
}
#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
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;
{
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 DUMP_TOKENS
dump_token ();
#endif
-
+
return token;
}
}
/* 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. */
{
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. */
setting *def; /* Default setting. */
setting *omit_kw; /* Setting for which the keyword can be omitted. */
-
+
int index; /* Next array index. */
};
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. */
parse_setting (setting *s, specifier *spec)
{
s->parent = spec;
-
+
if (match_token ('*'))
{
if (spec->omit_kw)
else
spec->omit_kw = s;
}
-
+
if (match_token ('!'))
{
if (spec->def)
else
spec->def = s;
}
-
+
force_id ();
s->specname = xstrdup (tokstr);
s->con = add_symbol (s->specname, 0, 0);
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 ();
}
else
s->restriction = NULL;
-
+
if (s->valtype == VT_PAREN)
skip_token (')');
}
spec->varname = xstrdup (st_lower (tokstr));
lex_get ();
}
-
+
/* Handle array elements. */
if (token != ':')
{
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);
*spec = NULL;
return;
}
-
+
for (;;)
{
*spec = xmalloc (sizeof **spec);
static void
parse_subcommand (subcommand *sbc)
{
- sbc->arity = ARITY_MANY;
-
if (match_token ('*'))
{
if (def)
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 ;
force_id ();
sbc->name = xstrdup (tokstr);
lex_get ();
-
+
sbc->narray = 0;
sbc->type = SBC_PLAIN;
sbc->spec = NULL;
force_id ();
sbc->prefix = xstrdup (st_lower (tokstr));
lex_get ();
-
+
skip_token (']');
skip_token ('=');
-
+
sbc->type = SBC_ARRAY;
parse_specifiers (sbc);
force_id ();
sbc->prefix = xstrdup (st_lower (tokstr));
lex_get ();
-
+
skip_token (')');
}
else
sbc->prefix = "";
-
+
skip_token ('=');
if (match_id ("VAR"))
force_string ();
sbc->message = xstrdup (tokstr);
lex_get();
-
+
skip_token (')');
}
else sbc->message = NULL;
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 ();
parse_subcommands (void)
{
subcommand **sbc = &subcommands;
-
+
for (;;)
{
*sbc = xmalloc (sizeof **sbc);
if (indention < 0)
indent += BASE_INDENT * indention;
-
+
oln++;
va_start (args, format);
for (i = 0; i < indent; i++)
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
{
if (spec->varname)
dump (0, "long %s%s;", sbc->prefix, spec->varname);
-
+
{
setting *s;
{
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));
}
}
}
-/* 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[] =
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
else
*cp++ = '_';
*cp = '\0';
-
+
return p;
}
{
indent = 0;
+ dump (0, "struct dataset;");
+
/* Write out enums for all the identifiers in the symbol table. */
{
int f, k;
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
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);
}
}
if (sbc->type == SBC_ARRAY && sbc->narray)
{
dump (0, "/* Array indices for %s subcommand. */", sbc->name);
-
+
dump (1, "enum");
dump (1, "{");
dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
dump (-1, "};");
- dump (-1, nullstr);
+ dump_blank_line (-1);
}
}
}
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));
case SBC_PLAIN:
{
specifier *spec;
-
+
for (spec = sbc->spec; spec; spec = spec->next)
{
if (spec->s == 0)
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)
);
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;
}
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)
{
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);
}
}
strcpy (s, "-1");
dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
}
-
+
{
setting *s;
{
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);
}
/* 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, "}");
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)
{
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));
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 ();
}
}
}
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 if (strchr (t, hyphen_proxy))
+ {
+ char *c = unmunge (t);
+ sprintf (s, "lex_match_hyphenated_word (lexer, \"%s\")", c);
+ free (c);
+ }
else
- sprintf (s, "lex_match_id (\"%s\")", t);
-
+ sprintf (s, "lex_match_id (lexer, \"%s\")", t);
+
return s;
}
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;
{
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),
{
if (s->optvalue)
{
- dump (1, "if (lex_match ('('))");
+ dump (1, "if (lex_match (lexer, T_LPAREN))");
dump (1, "{");
}
else
{
- dump (1, "if (!lex_match ('('))");
+ dump (1, "if (!lex_match (lexer, T_RPAREN))");
dump (1, "{");
dump (0, "msg (SE, _(\"`(' expected after %s "
"specifier of %s subcommand.\"));",
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 = ss_xstrdup (ss_tokss (lexer));",
+ sbc->prefix, st_lower (s->valname));
+ }
+ else
+ abort ();
+
if (s->restriction)
{
{
free (str);
free (str2);
}
-
+
dump (1, "{");
dump (0, "msg (SE, _(\"Bad argument for %s "
"specifier of %s subcommand.\"));",
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, T_RPAREN))");
dump (1, "{");
dump (0, "msg (SE, _(\"`)' expected after argument for "
"%s specifier of %s.\"));",
outdent ();
}
}
-
+
if (s != spec->omit_kw)
dump (-1, "}");
}
-
+
if (s == spec->omit_kw)
{
dump (-1, "}");
{
int count;
- dump (1, "while (token != '/' && token != '.')");
+ dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
dump (1, "{");
-
+
{
specifier *spec;
}
}
}
-
+
{
specifier *spec;
setting *s;
{
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, T_COMMA);");
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),
}
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));
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 = ss_length (lex_tokss (lexer));");
dump (1, "if (!(%s))", sbc->restriction);
dump (1, "{");
dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
outdent ();
}
dump (0, "free(p->s_%s);", st_lower(sbc->name) );
- dump (0, "p->s_%s = ds_xstrdup (&tokstr);",
+ dump (0, "p->s_%s = ss_xstrdup (lex_tokss (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);
}
else if (sbc->type == SBC_PINT)
{
- dump (0, "lex_match ('(');");
- dump (1, "if (!lex_force_int ())");
+ dump (0, "lex_match (lexer, T_LPAREN);");
+ 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, T_RPAREN);");
}
- 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, "{");
dump (0, "goto lossage;");
dump (-1,"}");
- dump (1, "while (token != '/' && token != '.')");
+ dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
dump (1, "{");
- dump (0, "lex_match(',');");
- dump (0, "if (!lex_force_num ())");
+ dump (0, "lex_match (lexer, T_COMMA);");
+ 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:");
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 ();
}
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, "{");
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_tokcstr (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_tokcstr (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));
}
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:");
dump (0, "break;");
dump (-1, "default:");
indent ();
- dump (0, "assert (0);");
+ dump (0, "NOT_REACHED ();");
dump (-1, "}");
outdent ();
}
-
+
{
subcommand *sbc;
f = 1;
dump (1, "{");
- dump (0, "lex_match ('=');");
+ dump (0, "lex_match (lexer, T_EQUALS);");
dump (0, "p->sbc_%s++;", st_lower (sbc->name));
if (sbc->arity != ARITY_MANY)
{
/* 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, T_EQUALS);");
- 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, T_SLASH))");
dump (0, "break;");
dump (-2, "}");
outdent ();
- dump (0, nullstr);
- dump (1, "if (token != '.')");
+ dump_blank_line (0);
+ dump (1, "if (lex_token (lexer) != T_ENDCMD)");
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 ();
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, "{");
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);
}
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, " */");
}
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");
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_%s);", st_lower (sbc->name));
dump (0, "free (p->s_%s);", st_lower (sbc->name));
break;
case SBC_DBL_LIST:
+ case SBC_INT_LIST:
dump (0, "{");
dump (1, "int i;");
dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
- dump (1, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
+ 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;
}
{
static char directive[16];
char *sp, *ep;
-
+
sp = skip_ws (buf);
if (strncmp (sp, "/*", 2))
return NULL;
directive[ep - sp] = '\0';
return directive;
}
-
+
int
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);
dump (0, "%s", buf);
continue;
}
-
+
dump (0, "#line %d \"%s\"", oln + 1, ofn);
if (!strcmp (directive, "specification"))
{
indent = 0;
dump (0, "#include <stdlib.h>");
- dump (0, "#include <libpspp/alloc.h>");
+ dump (0, "#include <libpspp/assertion.h>");
dump (0, "#include <libpspp/message.h>");
dump (0, "#include <language/lexer/lexer.h>");
dump (0, "#include <language/lexer/variable-parser.h>");
dump (0, "#include <libpspp/str.h>");
dump (0, "#include <language/lexer/subcommand-list.h>");
dump (0, "#include <data/variable.h>");
- dump (0, nullstr);
+ 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);
dump (0, "#line %d \"%s\"", ln + 1, ifn);
}
-
-
return EXIT_SUCCESS;
}