-/* q2c - parser generator for PSPP procedures.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 1997-9, 2000, 2008, 2010, 2011 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.
- 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 <http://www.gnu.org/licenses/>. */
-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;
/* 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;
/* 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;
return p;
}
/* Returns the address of the first non-whitespace character in S, or
the address of the null terminator if none. */
static char *
return p;
}
/* Returns the address of the first non-whitespace character in S, or
the address of the null terminator if none. */
static char *
+
+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;
+}
+
setting *def; /* Default setting. */
setting *omit_kw; /* Setting for which the keyword can be omitted. */
setting *def; /* Default setting. */
setting *omit_kw; /* Setting for which the keyword can be omitted. */
int narray; /* Index of next array element. */
const char *prefix; /* Prefix for variable and constant names. */
specifier *spec; /* Array of specifiers. */
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. */
/* SBC_STRING and SBC_INT only. */
char *restriction; /* Expression restricting string length. */
char *message; /* Error message. */
force_id ();
s->specname = xstrdup (tokstr);
s->con = add_symbol (s->specname, 0, 0);
force_id ();
s->specname = xstrdup (tokstr);
s->con = add_symbol (s->specname, 0, 0);
+/* 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
/* 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);
{
if (spec->varname)
dump (0, "long %s%s;", sbc->prefix, spec->varname);
if (k)
sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
else
if (k)
sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
else
if (sbc->type == SBC_ARRAY && sbc->narray)
{
dump (0, "/* Array indices for %s subcommand. */", sbc->name);
if (sbc->type == SBC_ARRAY && sbc->narray)
{
dump (0, "/* Array indices for %s subcommand. */", sbc->name);
dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
dump (-1, "};");
dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
dump (-1, "};");
dump (0, "/* %s subcommand. */", sbc->name);
dump (0, "int sbc_%s;", st_lower (sbc->name));
dump (0, "/* %s subcommand. */", sbc->name);
dump (0, "int sbc_%s;", st_lower (sbc->name));
make_identifier (cmdname), make_identifier (cmdname));
dump (0, "static void free_%s (struct cmd_%s *);",
make_identifier (cmdname), make_identifier (cmdname));
make_identifier (cmdname), make_identifier (cmdname));
dump (0, "static void free_%s (struct cmd_%s *);",
make_identifier (cmdname), make_identifier (cmdname));
strcpy (s, "-1");
dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
}
strcpy (s, "-1");
dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
}
dump (0, "p->%sv_%s = NULL;",
st_lower (sbc->prefix), st_lower (sbc->name));
break;
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));
case SBC_VAR:
dump (0, "p->%sv_%s = NULL;",
st_lower (sbc->prefix), st_lower (sbc->name));
if (is_keyword (t))
sprintf (s, "lex_match (lexer, T_%s)", t);
else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
if (is_keyword (t))
sprintf (s, "lex_match (lexer, T_%s)", t);
else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
"|| lex_match_id (lexer, \"FALSE\"))");
else if (isdigit ((unsigned char) t[0]))
sprintf (s, "lex_match_int (lexer, %s)", t);
"|| lex_match_id (lexer, \"FALSE\"))");
else if (isdigit ((unsigned char) t[0]))
sprintf (s, "lex_match_int (lexer, %s)", t);
else
sprintf (s, "lex_match_id (lexer, \"%s\")", t);
else
sprintf (s, "lex_match_id (lexer, \"%s\")", t);
if (spec->omit_kw && spec->omit_kw->parent->next)
error ("Default specifier is not in last specifier in `%s' "
"subcommand.", sbc->name);
if (spec->omit_kw && spec->omit_kw->parent->next)
error ("Default specifier is not in last specifier in `%s' "
"subcommand.", sbc->name);
if (spec->varname)
{
dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
st_upper (prefix), find_symbol (s->con)->name);
if (spec->varname)
{
dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
st_upper (prefix), find_symbol (s->con)->name);
dump (0, "p->a_%s[%s%s%s] = 1;",
st_lower (sbc->name),
st_upper (prefix), st_upper (sbc->prefix),
dump (0, "p->a_%s[%s%s%s] = 1;",
st_lower (sbc->name),
st_upper (prefix), st_upper (sbc->prefix),
dump (1, "{");
dump (0, "msg (SE, _(\"`(' expected after %s "
"specifier of %s subcommand.\"));",
dump (1, "{");
dump (0, "msg (SE, _(\"`(' expected after %s "
"specifier of %s subcommand.\"));",
dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
st_lower (s->valname));
}
dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
st_lower (s->valname));
}
dump (1, "{");
dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
"requires a string argument.\"));",
dump (1, "{");
dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
"requires a string argument.\"));",
dump (0, "goto lossage;");
dump (-1, "}");
dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
dump (0, "goto lossage;");
dump (-1, "}");
dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
dump (1, "{");
dump (0, "msg (SE, _(\"Bad argument for %s "
"specifier of %s subcommand.\"));",
dump (1, "{");
dump (0, "msg (SE, _(\"Bad argument for %s "
"specifier of %s subcommand.\"));",
dump (1, "{");
dump (0, "msg (SE, _(\"`)' expected after argument for "
"%s specifier of %s.\"));",
dump (1, "{");
dump (0, "msg (SE, _(\"`)' expected after argument for "
"%s specifier of %s.\"));",
dump (1, "if (!(%s))", sbc->restriction);
dump (1, "{");
dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
dump (1, "if (!(%s))", sbc->restriction);
dump (1, "{");
dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
{
dump (1, "if (!lex_force_num (lexer))");
dump (0, "goto lossage;");
{
dump (1, "if (!lex_force_num (lexer))");
dump (0, "goto lossage;");
st_lower (sbc->name), st_lower (sbc->name) );
dump (0, "lex_get(lexer);");
}
st_lower (sbc->name), st_lower (sbc->name) );
dump (0, "lex_get(lexer);");
}
dump (0, "msg (SE, gettext(\"%s\"));",buf);
else
dump (0, "msg (SE, \"%s\");",buf);
dump (0, "msg (SE, gettext(\"%s\"));",buf);
else
dump (0, "msg (SE, \"%s\");",buf);
dump (1, "if (!lex_force_int (lexer))");
dump (0, "goto lossage;");
dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
dump (1, "if (!lex_force_int (lexer))");
dump (0, "goto lossage;");
dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
dump (0, "if (!lex_force_num (lexer))");
dump (1, "{");
dump (0, "goto lossage;");
dump (0, "if (!lex_force_num (lexer))");
dump (1, "{");
dump (0, "goto lossage;");
{
if (def->type == SBC_VARLIST)
dump (1, "if (lex_token (lexer) == T_ID "
{
if (def->type == SBC_VARLIST)
dump (1, "if (lex_token (lexer) == T_ID "
"&& lex_look_ahead (lexer) != '=')");
else
{
dump (0, "if ((lex_token (lexer) == T_ID "
"&& lex_look_ahead (lexer) != '=')");
else
{
dump (0, "if ((lex_token (lexer) == T_ID "
"&& lex_look_ahead () != '=')");
dump (1, " || token == T_ALL)");
}
"&& lex_look_ahead () != '=')");
dump (1, " || token == T_ALL)");
}
dump (0, "p->sbc_%s++;", st_lower (sbc->name));
if (sbc->arity != ARITY_MANY)
{
dump (0, "p->sbc_%s++;", st_lower (sbc->name));
if (sbc->arity != ARITY_MANY)
{
dump (1, "{");
dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
dump (0, "goto lossage;");
dump (-1, "}");
dump (1, "{");
dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
dump (0, "goto lossage;");
dump (-1, "}");
dump (-1, "lossage:");
indent ();
dump (0, "free_%s (p);", make_identifier (cmdname));
dump (0, "return false;");
dump (-1, "}");
dump (-1, "lossage:");
indent ();
dump (0, "free_%s (p);", make_identifier (cmdname));
dump (0, "return false;");
dump (-1, "}");
dump (0, " Generated by q2c from %s.", ifn);
dump (0, " Do not modify!");
dump (0, " */");
dump (0, " Generated by q2c from %s.", ifn);
dump (0, " Do not modify!");
dump (0, " */");
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));
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));
dump (0, "#line %d \"%s\"", oln + 1, ofn);
if (!strcmp (directive, "specification"))
{
dump (0, "#line %d \"%s\"", oln + 1, ofn);
if (!strcmp (directive, "specification"))
{
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 <data/settings.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 <data/settings.h>");
dump (0, "#include <libpspp/str.h>");
dump (0, "#include <language/lexer/subcommand-list.h>");
dump (0, "#include <data/variable.h>");
dump (0, "#include <libpspp/str.h>");
dump (0, "#include <language/lexer/subcommand-list.h>");
dump (0, "#include <data/variable.h>");
dump (0, "#include \"gettext.h\"");
dump (0, "#define _(msgid) gettext (msgid)");
dump (0, "#include \"gettext.h\"");
dump (0, "#define _(msgid) gettext (msgid)");
}
else if (!strcmp (directive, "declarations"))
dump_declarations ();
else if (!strcmp (directive, "functions"))
{
dump_parser (0);
}
else if (!strcmp (directive, "declarations"))
dump_declarations ();
else if (!strcmp (directive, "functions"))
{
dump_parser (0);