/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ 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
\f
/* Utility functions. */
-static char nullstr[] = "";
-
/* Close all open files and delete the output file, on failure. */
static void
finish_up (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
/* 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
}
#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)
{
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++;
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. */
- int translatable; /* Error message is translatable */
+ char *pv_options; /* PV_* options for SBC_VARLIST. */
};
/* Name of the command; i.e., DESCRIPTIVES. */
sbc->narray = 0;
sbc->type = SBC_PLAIN;
sbc->spec = NULL;
- sbc->translatable = 0;
if (match_token ('['))
{
if (match_token ('('))
{
force_string ();
- sbc->message = xstrdup (tokstr);
+ sbc->pv_options = xstrdup (tokstr);
lex_get();
skip_token (')');
}
- else sbc->message = NULL;
+ else
+ sbc->pv_options = NULL;
sbc->type = SBC_VARLIST;
}
else if (match_id ("INTEGER"))
- {
sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
- if ( token == T_STRING)
- {
- sbc->restriction = xstrdup (tokstr);
- lex_get ();
- if ( match_id("N_") )
- {
- skip_token('(');
- force_string ();
- lex_get();
- skip_token(')');
- sbc->translatable = 1;
- }
- else {
- force_string ();
- lex_get ();
- }
- sbc->message = xstrdup (tokstr);
- }
- else
- sbc->restriction = NULL;
- }
else if (match_id ("PINT"))
sbc->type = SBC_PINT;
else if (match_id ("DOUBLE"))
sbc->type = SBC_DBL;
}
else if (match_id ("STRING"))
- {
- sbc->type = SBC_STRING;
- if (token == T_STRING)
- {
- sbc->restriction = xstrdup (tokstr);
- lex_get ();
- force_string ();
- sbc->message = xstrdup (tokstr);
- lex_get ();
- }
- else
- sbc->restriction = NULL;
- }
+ sbc->type = SBC_STRING;
else if (match_id ("CUSTOM"))
sbc->type = SBC_CUSTOM;
else
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 (buf == NULL)
buf = xmalloc (1024);
else
- dump (0, buf);
+ dump (0, "%s", buf);
if (k)
sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
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);
}
}
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));
}
dump (-1, "};");
- dump (-1, nullstr);
+ dump_blank_line (-1);
}
/* Write out prototypes for custom_*() functions as necessary. */
}
if (seen)
- dump (0, nullstr);
+ dump_blank_line (0);
}
/* Prototypes for parsing and freeing functions. */
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);
}
}
"|| lex_match_id (lexer, \"FALSE\"))");
else if (isdigit ((unsigned char) t[0]))
sprintf (s, "lex_match_int (lexer, %s)", t);
+ else if (strchr (t, hyphen_proxy))
+ {
+ char *c = unmunge (t);
+ sprintf (s, "lex_match_phrase (lexer, \"%s\")", c);
+ free (c);
+ }
else
sprintf (s, "lex_match_id (lexer, \"%s\")", t);
{
if (s->optvalue)
{
- dump (1, "if (lex_match (lexer, '('))");
+ dump (1, "if (lex_match (lexer, T_LPAREN))");
dump (1, "{");
}
else
{
- dump (1, "if (!lex_match (lexer, '('))");
+ dump (1, "if (!lex_match (lexer, T_LPAREN))");
dump (1, "{");
- dump (0, "msg (SE, _(\"`(' expected after %s "
- "specifier of %s subcommand.\"));",
- s->specname, sbc->name);
- dump (0, "goto lossage;");
+ dump (0, "lex_error_expecting (lexer, \"`('\");");
+ dump (0, "goto lossage;");
dump (-1, "}");
outdent ();
}
if (s->value == VAL_INT)
{
- 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 (1, "if (!lex_force_int (lexer))");
dump (0, "goto lossage;");
- dump (-1, "}");
dump (-1, "p->%s%s = lex_integer (lexer);",
sbc->prefix, st_lower (s->valname));
}
else if (s->value == VAL_DBL)
{
- 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 (1, "if (!lex_force_num (lexer))");
dump (0, "goto lossage;");
- dump (-1, "}");
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_token (lexer) != T_STRING)");
- dump (1, "{");
- dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
- "requires a string argument.\"));",
- s->specname, sbc->name);
+ dump (1, "if (!lex_force_string_or_id (lexer))");
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)));",
+ dump (0, "p->%s%s = ss_xstrdup (ss_tokss (lexer));",
sbc->prefix, st_lower (s->valname));
}
else
}
dump (1, "{");
- dump (0, "msg (SE, _(\"Bad argument for %s "
- "specifier of %s subcommand.\"));",
- s->specname, sbc->name);
+ dump (0, "lex_error (lexer, NULL);");
dump (0, "goto lossage;");
dump (-1, "}");
outdent ();
if (s->valtype == VT_PAREN)
{
- dump (1, "if (!lex_match (lexer, ')'))");
- dump (1, "{");
- dump (0, "msg (SE, _(\"`)' expected after argument for "
- "%s specifier of %s.\"));",
- s->specname, sbc->name);
+ dump (1, "if (!lex_force_match (lexer, T_RPAREN))");
dump (0, "goto lossage;");
- dump (-1, "}");
outdent ();
if (s->optvalue)
{
{
int count;
- dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
+ dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
dump (1, "{");
{
}
}
- dump (0, "lex_match (lexer, ',');");
+ dump (0, "lex_match (lexer, T_COMMA);");
dump (-1, "}");
outdent ();
}
"PV_APPEND%s%s))",
st_lower (sbc->prefix), st_lower (sbc->name),
st_lower (sbc->prefix), st_lower (sbc->name),
- sbc->message ? " |" : "",
- sbc->message ? sbc->message : "");
+ sbc->pv_options ? " |" : "",
+ sbc->pv_options ? sbc->pv_options : "");
dump (0, "goto lossage;");
outdent ();
}
}
else if (sbc->type == SBC_STRING)
{
- if (sbc->restriction)
- {
- dump (1, "{");
- dump (0, "int x;");
- }
dump (1, "if (!lex_force_string (lexer))");
dump (0, "return false;");
outdent ();
- if (sbc->restriction)
- {
- 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.\"));",
- sbc->name, sbc->message);
- dump (0, "goto lossage;");
- dump (-1, "}");
- outdent ();
- }
dump (0, "free(p->s_%s);", st_lower(sbc->name) );
- dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));",
+ dump (0, "p->s_%s = ss_xstrdup (lex_tokss (lexer));",
st_lower (sbc->name));
dump (0, "lex_get (lexer);");
- if (sbc->restriction)
- dump (-1, "}");
}
else if (sbc->type == SBC_DBL)
{
dump (0, "goto lossage;");
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, "{");
- sprintf(buf,sbc->message,sbc->name);
- if ( sbc->translatable )
- dump (0, "msg (SE, gettext(\"%s\"));",buf);
- else
- dump (0, "msg (SE, \"%s\");",buf);
- dump (0, "goto lossage;");
- dump (-1, "}");
- }
dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
dump (-1,"}");
}
else if (sbc->type == SBC_PINT)
{
- dump (0, "lex_match (lexer, '(');");
+ 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 (lexer);", st_lower (sbc->name));
- dump (0, "lex_match (lexer, ')');");
+ dump (0, "lex_match (lexer, T_RPAREN);");
}
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, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
+ dump (0, "subc_list_error (lexer, \"%s\", MAXLISTS);",
+ st_lower(sbc->name));
dump (0, "goto lossage;");
dump (-1,"}");
- dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
+ dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
dump (1, "{");
- dump (0, "lex_match (lexer, ',');");
+ dump (0, "lex_match (lexer, T_COMMA);");
dump (0, "if (!lex_force_num (lexer))");
dump (1, "{");
dump (0, "goto lossage;");
dump (0, "static int");
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",
+ (def && ( def->type == SBC_VARLIST || def->type == SBC_CUSTOM))?"":" UNUSED",
make_identifier (cmdname));
dump (1, "{");
{
if (def->type == SBC_VARLIST)
dump (1, "if (lex_token (lexer) == T_ID "
- "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL "
- "&& lex_look_ahead (lexer) != '=')");
+ "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) != NULL "
+ "&& lex_next_token (lexer, 1) != T_EQUALS)");
else
{
dump (0, "if ((lex_token (lexer) == T_ID "
- "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) "
- "&& lex_look_ahead () != '=')");
+ "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) "
+ "&& lex_next_token (lexer, 1) != T_EQUALS)");
dump (1, " || token == T_ALL)");
}
dump (1, "{");
f = 1;
dump (1, "{");
- dump (0, "lex_match (lexer, '=');");
+ dump (0, "lex_match (lexer, T_EQUALS);");
dump (0, "p->sbc_%s++;", st_lower (sbc->name));
if (sbc->arity != ARITY_MANY)
{
dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
dump (1, "{");
- dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
- sbc->name);
+ dump (0, "lex_sbc_only_once (\"%s\");", sbc->name);
dump (0, "goto lossage;");
dump (-1, "}");
outdent ();
dump(1,"else if ( settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
dump(1,"{");
- dump (0, "lex_match (lexer, '=');");
+ dump (0, "lex_match (lexer, T_EQUALS);");
dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
dump(0,"settings_set_cmd_algorithm (COMPATIBLE);");
- dump (1, "if (!lex_match (lexer, '/'))");
+ dump (1, "if (!lex_match (lexer, T_SLASH))");
dump (0, "break;");
dump (-2, "}");
outdent ();
- dump (0, nullstr);
- dump (1, "if (lex_token (lexer) != '.')");
+ dump_blank_line (0);
+ dump (1, "if (lex_token (lexer) != T_ENDCMD)");
dump (1, "{");
dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
dump (0, "goto lossage;");
dump (-1, "}");
- dump (0, nullstr);
+ dump_blank_line (0);
outdent ();
{
dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
dump (1, "{");
- dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
- sbc->name);
+ dump (0, "lex_sbc_missing (\"%s\");", sbc->name);
dump (0, "goto lossage;");
dump (-1, "}");
- dump (0, nullstr);
+ dump_blank_line (0);
}
}
}
dump (-1, "return true;");
- dump (0, nullstr);
+ dump_blank_line (0);
dump (-1, "lossage:");
indent ();
dump (0, "free_%s (p);", make_identifier (cmdname));
dump (0, "return false;");
dump (-1, "}");
- dump (0, nullstr);
+ dump_blank_line (0);
}
{
indent = 0;
dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
- dump (0, nullstr);
+ dump_blank_line (0);
dump (0, " Generated by q2c from %s.", ifn);
dump (0, " Do not modify!");
dump (0, " */");
indent = 0;
dump (0, "#include <stdlib.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, nullstr);
-
- dump (0, "#include \"xalloc.h\"");
- dump (0, nullstr);
-
- dump (0, "#include \"gettext.h\"");
- dump (0, "#define _(msgid) gettext (msgid)");
- dump (0, nullstr);
+ dump_blank_line (0);
+
+ dump (0, "#include \"data/settings.h\"");
+ dump (0, "#include \"data/variable.h\"");
+ dump (0, "#include \"language/lexer/lexer.h\"");
+ dump (0, "#include \"language/lexer/subcommand-list.h\"");
+ dump (0, "#include \"language/lexer/variable-parser.h\"");
+ dump (0, "#include \"libpspp/assertion.h\"");
+ dump (0, "#include \"libpspp/cast.h\"");
+ dump (0, "#include \"libpspp/message.h\"");
+ dump (0, "#include \"libpspp/str.h\"");
+ dump_blank_line (0);
+
+ dump (0, "#include \"gl/xalloc.h\"");
+ dump_blank_line (0);
}
else if (!strcmp (directive, "declarations"))
dump_declarations ();