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., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include <config.h>
#include <assert.h>
#endif
#include "str.h"
+
/* Brokenness. */
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#include "misc/strerror.c"
#endif
-#undef DEBUGGING
-/*#define DEBUGGING 1*/
#include "debug-print.h"
/* Max length of an input line. */
\f
/* Utility functions. */
-#if !(__GNUC__ >= 2)
-#define nullstr ""
-#else
-const char nullstr[] = "";
-#endif
+char nullstr[] = "";
/* Close all open files and delete the output file, on failure. */
-void
+static void
finish_up (void)
{
if (!is_open)
fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
}
-#if __GNUC__ >= 2
-void hcf (void) __attribute__ ((noreturn));
-#endif
+void hcf (void) NO_RETURN;
/* Terminate unsuccessfully. */
void
exit (EXIT_FAILURE);
}
-#if __GNUC__ >= 2
-int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
-int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
-#endif
+int fail (const char *, ...) PRINTF_FORMAT (1, 2);
+int error (const char *, ...) PRINTF_FORMAT (1, 2);
/* Output an error message and terminate unsuccessfully. */
int
/* Allocate a block of SIZE bytes and return a pointer to its
beginning. */
-void *
+static void *
xmalloc (size_t size)
{
void *vp;
vp = malloc (size);
if (!vp)
- {
-#if DEBUGGING && __CHECKER__
- error ("xmalloc(%lu): Inducing segfault.", (unsigned long) size);
- *((int *) 0) = 0;
-#endif
- fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
- }
-
- return vp;
-}
-
-/* Resize the block at PTR to size SIZE and return a pointer to the
- beginning of the new block. */
-void *
-xrealloc (void *ptr, size_t size)
-{
- void *vp;
-
- if (!size)
- {
- if (ptr)
- free (ptr);
- return NULL;
- }
-
- if (ptr)
- vp = realloc (ptr, size);
- else
- vp = malloc (size);
-
- if (!vp)
- fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
+ fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
return vp;
}
/* Make a dynamically allocated copy of string S and return a pointer
to the first character. */
-char *
+static char *
xstrdup (const char *s)
{
size_t size;
/* Returns a pointer to one of 8 static buffers. The buffers are used
in rotation. */
-char *
+static char *
get_buffer (void)
{
static char b[8][256];
/* Copies a string to a static buffer, converting it to lowercase in
the process, and returns a pointer to the static buffer. */
-char *
+static char *
st_lower (const char *s)
{
char *p, *cp;
/* Copies a string to a static buffer, converting it to uppercase in
the process, and returns a pointer to the static buffer. */
-char *
+static char *
st_upper (const char *s)
{
char *p, *cp;
/* Returns the address of the first non-whitespace character in S, or
the address of the null terminator if none. */
-char *
+static char *
skip_ws (const char *s)
{
while (isspace ((unsigned char) *s))
/* Read one line from the input file into buf. Lines having special
formats are handled specially. */
-int
+static int
get_line (void)
{
ln++;
in the symbol table, its sequence number is returned and the symbol
table is not modified. Otherwise, the symbol is added and the next
available sequence number is returned. */
-int
+static int
add_symbol (const char *name, int unique, int value)
{
symbol *iter, *sym;
/* Finds the symbol having given sequence number X within the symbol
table, and returns the associated symbol structure. */
-symbol *
+static symbol *
find_symbol (int x)
{
symbol *iter;
return iter;
}
-#if DEBUGGING
+#if DEBUGGING
/* Writes a printable representation of the current token to
stdout. */
-void
+static void
dump_token (void)
{
switch (token)
#endif /* DEBUGGING */
/* Reads a token from the input file. */
-int
+static int
lex_get (void)
{
/* Skip whitespace and check for end of file. */
fail ("%s: Unexpected end of file.", ifn);
}
- if (*cp == '_' || isalnum ((unsigned char) *cp))
- {
- char *dest = tokstr;
- token = T_ID;
- while (*cp == '_' || isalnum ((unsigned char) *cp))
- *dest++ = toupper ((unsigned char) (*cp++));
- *dest++ = '\0';
- }
- else if (*cp == '"')
+ if (*cp == '"')
{
char *dest = tokstr;
token = T_STRING;
error ("Unterminated string literal.");
cp++;
}
+ else if (*cp == '_' || isalnum ((unsigned char) *cp))
+ {
+ char *dest = tokstr;
+ token = T_ID;
+ while (*cp == '_' || isalnum ((unsigned char) *cp))
+ *dest++ = toupper ((unsigned char) (*cp++));
+ *dest++ = '\0';
+ }
else
token = *cp++;
}
/* Force the current token to be an identifier token. */
-void
+static void
force_id (void)
{
if (token != T_ID)
}
/* Force the current token to be a string token. */
-void
+static void
force_string (void)
{
if (token != T_STRING)
/* Checks whether the current token is the identifier S; if so, skips
the token and returns 1; otherwise, returns 0. */
-int
+static int
match_id (const char *s)
{
if (token == T_ID && !strcmp (tokstr, s))
/* Checks whether the current token is T. If so, skips the token and
returns 1; otherwise, returns 0. */
-int
+static int
match_token (int t)
{
if (token == t)
}
/* Force the current token to be T, and skip it. */
-void
+static void
skip_token (int t)
{
if (token != t)
}
subcommand_type;
+typedef enum
+ {
+ ARITY_ONCE_EXACTLY, /* must occur exactly once */
+ ARITY_ONCE_ONLY, /* zero or once */
+ ARITY_MANY /* 0, 1, ... , inf */
+ }subcommand_arity;
+
/* A single subcommand. */
typedef struct subcommand subcommand;
struct subcommand
subcommand *next; /* Next in the chain. */
char *name; /* Subcommand name. */
subcommand_type type; /* One of SBC_*. */
- int once; /* 1=Subcommand may appear only once. */
+ subcommand_arity arity; /* How many times should the subcommand occur*/
int narray; /* Index of next array element. */
const char *prefix; /* Prefix for variable and constant names. */
specifier *spec; /* Array of specifiers. */
- /* SBC_STRING only. */
+ /* SBC_STRING and SBC_INT only. */
char *restriction; /* Expression restricting string length. */
char *message; /* Error message. */
+ int translatable; /* Error message is translatable */
};
+typedef struct aux_subcommand aux_subcommand;
+struct aux_subcommand
+ {
+ aux_subcommand *next; /* Next in the chain. */
+ char *name; /* Subcommand name. */
+ char *value; /* Subcommand value */
+ };
+
+static aux_subcommand *aux_subcommands ;
+
/* Name of the command; i.e., DESCRIPTIVES. */
char *cmdname;
void parse_subcommands (void);
/* Parse an entire specification. */
-void
+static void
parse (void)
{
/* Get the command name and prefix. */
/* Parses a single setting into S, given subcommand information SBC
and specifier information SPEC. */
-void
+static void
parse_setting (setting *s, specifier *spec)
{
s->parent = spec;
/* Parse a single specifier into SPEC, given subcommand information
SBC. */
-void
+static void
parse_specifier (specifier *spec, subcommand *sbc)
{
spec->index = 0;
}
skip_token (':');
+ 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;
}
/* Parse a list of specifiers for subcommand SBC. */
-void
+static void
parse_specifiers (subcommand *sbc)
{
specifier **spec = &sbc->spec;
}
/* Parse a subcommand into SBC. */
-void
+static void
parse_subcommand (subcommand *sbc)
{
+ sbc->arity = ARITY_MANY;
+
if (match_token ('*'))
{
if (def)
def = sbc;
}
- sbc->once = match_token ('+');
+ if ( match_token('+'))
+ sbc->arity = ARITY_ONCE_ONLY ;
+ else if (match_token('^'))
+ sbc->arity = ARITY_ONCE_EXACTLY ;
+
force_id ();
sbc->name = xstrdup (tokstr);
sbc->narray = 0;
sbc->type = SBC_PLAIN;
sbc->spec = NULL;
+ sbc->translatable = 0;
if (match_token ('['))
{
sbc->type = SBC_ARRAY;
parse_specifiers (sbc);
+
}
else
{
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 = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
+ {
+ if ( match_id ("LIST") )
+ sbc->type = SBC_DBL_LIST;
+ else
+ sbc->type = SBC_DBL;
+ }
else if (match_id ("STRING"))
{
sbc->type = SBC_STRING;
/* Size of the indent from the left margin. */
int indent;
-#if __GNUC__ >= 2
-void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
-#endif
+void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
/* Write line FORMAT to the output file, formatted as with printf,
indented `indent' characters from the left margin. If INDENTION is
/* Write the structure members for specifier SPEC to the output file.
SBC is the including subcommand. */
-void
+static void
dump_specifier_vars (const specifier *spec, const subcommand *sbc)
{
if (spec->varname)
}
/* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
-int
+static int
is_keyword (const char *t)
{
static const char *kw[] =
/* Transforms a string NAME into a valid C identifier: makes
everything lowercase and maps nonalphabetic characters to
underscores. Returns a pointer to a static buffer. */
-char *
+static char *
make_identifier (const char *name)
{
char *p = get_buffer ();
}
/* Writes the struct and enum declarations for the parser. */
-void
+static void
dump_declarations (void)
{
indent = 0;
}
}
+ /* Write out some type definitions */
+ {
+ dump (0, "#define MAXLISTS 10");
+ }
+
+
/* For every array subcommand, write out the associated enumerated
values. */
{
specifier *spec;
for (spec = sbc->spec; spec; spec = spec->next)
- if (!spec->s)
dump (0, "%s%s%s = %d,",
st_upper (prefix), st_upper (sbc->prefix),
st_upper (spec->varname), spec->index);
spec->varname);
else if (f == 0)
{
- dump (0, "int a_%s[%d];",
- st_lower (sbc->name), sbc->narray);
+ dump (0, "int a_%s[%s%scount];",
+ st_lower (sbc->name),
+ st_upper (prefix),
+ st_upper (sbc->prefix)
+ );
+
f = 1;
}
}
case SBC_INT:
case SBC_PINT:
- dump (0, "long n_%s;", st_lower (sbc->name));
+ dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
+ break;
+
+ case SBC_DBL:
+ dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
break;
- default:
+ case SBC_DBL_LIST:
+ dump (0, "subc_list_double dl_%s[MAXLISTS];",
+ st_lower(sbc->name));
+ break;
+
+ case SBC_INT_LIST:
+ dump (0, "subc_list_int il_%s[MAXLISTS];",
+ st_lower(sbc->name));
+ break;
+
+
+ default:;
/* nothing */
}
}
/* Writes out code to initialize all the variables that need
initialization for particular specifier SPEC inside subcommand SBC. */
-void
+static void
dump_specifier_init (const specifier *spec, const subcommand *sbc)
{
if (spec->varname)
}
/* Write code to initialize all variables. */
-void
-dump_vars_init (void)
+static void
+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));
- switch (sbc->type)
+ if ( ! persistent )
{
- case SBC_DBL:
- case SBC_INT_LIST:
- case SBC_DBL_LIST:
- case SBC_CUSTOM:
- /* nothing */
- break;
+ 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]) ;",
+ st_lower (sbc->name)
+ );
+ dump (-2, "}");
+ break;
+
+ case SBC_DBL:
+ dump (1, "{");
+ dump (0, "int i;");
+ dump (1, "for (i = 0; i < MAXLISTS; ++i)");
+ dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
+ dump (-2, "}");
+ break;
+
+ case SBC_CUSTOM:
+ /* nothing */
+ break;
- case SBC_PLAIN:
- case SBC_ARRAY:
- {
- specifier *spec;
+ case SBC_PLAIN:
+ case SBC_ARRAY:
+ {
+ specifier *spec;
- for (spec = sbc->spec; spec; spec = spec->next)
- if (spec->s == NULL)
- {
- if (sbc->type == SBC_PLAIN)
- dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
- else if (f == 0)
+ for (spec = sbc->spec; spec; spec = spec->next)
+ if (spec->s == NULL)
{
- dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
- st_lower (sbc->name), st_lower (sbc->name));
- f = 1;
+ if (sbc->type == SBC_PLAIN)
+ dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
+ else if (f == 0)
+ {
+ dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
+ st_lower (sbc->name), st_lower (sbc->name));
+ f = 1;
+ }
}
- }
- else
- dump_specifier_init (spec, sbc);
- }
- break;
-
- case SBC_VARLIST:
- dump (0, "p->%sn_%s = 0;",
- st_lower (sbc->prefix), st_lower (sbc->name));
- dump (0, "p->%sv_%s = NULL;",
- st_lower (sbc->prefix), st_lower (sbc->name));
- break;
+ else
+ dump_specifier_init (spec, sbc);
+ }
+ break;
+
+ case SBC_VARLIST:
+ dump (0, "p->%sn_%s = 0;",
+ st_lower (sbc->prefix), st_lower (sbc->name));
+ 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));
- break;
-
- case SBC_STRING:
- dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
- break;
-
- case SBC_INT:
- case SBC_PINT:
- dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
- break;
-
- default:
- assert (0);
+ case SBC_VAR:
+ dump (0, "p->%sv_%s = NULL;",
+ st_lower (sbc->prefix), st_lower (sbc->name));
+ break;
+
+ case SBC_STRING:
+ dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
+ break;
+
+ case SBC_INT:
+ case SBC_PINT:
+ 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 (-2, "}");
+ break;
+
+ default:
+ assert (0);
+ }
}
}
}
/* Return a pointer to a static buffer containing an expression that
will match token T. */
-char *
+static char *
make_match (const char *t)
{
char *s;
/* Write out the parsing code for specifier SPEC within subcommand
SBC. */
-void
+static void
dump_specifier_parse (const specifier *spec, const subcommand *sbc)
{
setting *s;
dump (1, "%sif (%s)", first ? "" : "else ",
make_match (s->specname));
+
/* Handle values. */
if (s->value == VAL_NONE)
dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
dump (1, "{");
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->%s%s = %s%s;", sbc->prefix, spec->varname,
+ st_upper (prefix), find_symbol (s->con)->name);
+
+ 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),
+ st_upper (spec->varname));
+ }
+
+
if (s->valtype == VT_PAREN)
{
if (s->optvalue)
if (s->value == VAL_INT)
{
- dump (1, "if (!lex_integer_p ())");
+ dump (1, "if (!lex_is_integer ())");
dump (1, "{");
dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
"requires an integer argument.\"));",
}
else
{
- dump (1, "if (token != T_NUM)");
+ dump (1, "if (!lex_is_number ())");
dump (1, "{");
dump (0, "msg (SE, _(\"Number expected after %s "
"specifier of %s subcommand.\"));",
}
/* Write out the code to parse subcommand SBC. */
-void
+static void
dump_subcommand (const subcommand *sbc)
{
if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
}
else if (sbc->type == SBC_VARLIST)
{
- dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
+ dump (1, "if (!parse_variables (default_dict, &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),
{
dump (0, "p->%sv_%s = parse_variable ();",
st_lower (sbc->prefix), st_lower (sbc->name));
- dump (1, "if (p->%sv_%s)",
+ dump (1, "if (!p->%sv_%s)",
st_lower (sbc->prefix), st_lower (sbc->name));
dump (0, "goto lossage;");
outdent ();
dump (-1, "}");
outdent ();
}
- dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
+ dump (0, "free(p->s_%s);", st_lower(sbc->name) );
+ dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
st_lower (sbc->name));
dump (0, "lex_get ();");
if (sbc->restriction)
dump (-1, "}");
}
+ else if (sbc->type == SBC_DBL)
+ {
+ dump (1, "if (!lex_force_num ())");
+ dump (0, "goto lossage;");
+ dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
+ st_lower (sbc->name), st_lower (sbc->name) );
+ dump (0, "lex_get();");
+ }
else if (sbc->type == SBC_INT)
{
+ dump(1, "{");
+ dump(0, "int x;");
dump (1, "if (!lex_force_int ())");
dump (0, "goto lossage;");
- dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
+ dump (-1, "x = lex_integer ();");
+ dump (0, "lex_get();");
+ 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 (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
dump (0, "lex_match (')');");
}
+ else if (sbc->type == SBC_DBL_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, "goto lossage;");
+ dump (-1,"}");
+
+ dump (1, "while (token != '/' && token != '.')");
+ dump (1, "{");
+ dump (0, "lex_match(',');");
+ dump (0, "if (!lex_force_num ())");
+ 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, "lex_get();");
+ dump (-1,"}");
+
+ }
else if (sbc->type == SBC_CUSTOM)
{
dump (1, "switch (%scustom_%s (p))",
}
/* Write out entire parser. */
-void
-dump_parser (void)
+static void
+dump_parser (int persistent)
{
int f;
make_identifier (cmdname));
dump (1, "{");
- dump_vars_init ();
+ dump_vars_init (persistent);
dump (1, "for (;;)");
dump (1, "{");
if (def && (def->type == SBC_VARLIST))
{
if (def->type == SBC_VARLIST)
- dump (1, "if (token == T_ID && is_varname (tokid) && "
- "lex_look_ahead () != '=')");
+ dump (1, "if (token == T_ID "
+ "&& dict_lookup_var (default_dict, tokid) != NULL "
+ "&& lex_look_ahead () != '=')");
else
{
- dump (0, "if ((token == T_ID && is_varname (tokid) && "
- "lex_look_ahead () != '=')");
+ dump (0, "if ((token == T_ID "
+ "&& dict_lookup_var (default_dict, tokid) "
+ "&& lex_look_ahead () != '=')");
dump (1, " || token == T_ALL)");
}
dump (1, "{");
dump (0, "p->sbc_%s++;", st_lower (def->name));
- dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
+ dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
"PV_APPEND))",
st_lower (def->prefix), st_lower (def->name),
st_lower (def->prefix), st_lower (def->name));
dump (0, "lex_match ('=');");
dump (0, "p->sbc_%s++;", st_lower (sbc->name));
- if (sbc->once)
+ if (sbc->arity != ARITY_MANY)
{
dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
dump (1, "{");
outdent ();
}
}
+
+
+ /* Now deal with the /ALGORITHM subcommand implicit to all commands */
+ dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
+ dump(1,"{");
+
+ dump (0, "lex_match ('=');");
+
+ dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
+ dump(0,"set_cmd_algorithm(COMPATIBLE);");
+ outdent();
+ dump(1,"else if (lex_match_id(\"ENHANCED\"))");
+ dump(0,"set_cmd_algorithm(ENHANCED);");
+
+ dump (-1, "}");
+ outdent ();
+
+
dump (1, "if (!lex_match ('/'))");
dump (0, "break;");
dump (0, "goto lossage;");
dump (-1, "}");
dump (0, nullstr);
+
+ outdent ();
+
+ {
+ /* Check that mandatory subcommands have been specified */
+ subcommand *sbc;
+
+ for (sbc = subcommands; sbc; sbc = sbc->next)
+ {
+
+ if ( sbc->arity == ARITY_ONCE_EXACTLY )
+ {
+ 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, "goto lossage;");
+ dump (-1, "}");
+ dump (0, nullstr);
+ }
+ }
+ }
+
dump (-1, "return 1;");
dump (0, nullstr);
dump (-1, "lossage:");
dump (0, nullstr);
}
+
+/* Write out the code to parse aux subcommand SBC. */
+static void
+dump_aux_subcommand (const subcommand *sbc)
+{
+ if (sbc->type == SBC_PLAIN )
+ {
+ specifier *spec;
+
+ for (spec = sbc->spec; spec; spec = spec->next)
+ {
+ char buf[80];
+ sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
+
+ dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
+ dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
+
+ dump (0, ");");
+ }
+ }
+ else if (sbc->type == SBC_STRING)
+ {
+ dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
+ }
+ else if (sbc->type == SBC_INT)
+ {
+ dump (1, "{");
+ dump (0, "int i;");
+ dump (1, "for (i = 0; i < MAXLISTS; ++i)");
+ dump (0, "msg(MM,\"%s is %%ld\",p->n_%s[i]);", sbc->name,st_lower(sbc->name) );
+ outdent();
+ dump (-1, "}");
+ }
+ else if (sbc->type == SBC_CUSTOM)
+ {
+ dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
+ }
+ else
+ assert(0);
+}
+
+
+
+/* Write out auxilliary parser. */
+static void
+dump_aux_parser (void)
+{
+ int f=0;
+ subcommand *sbc;
+ aux_subcommand *asbc;
+
+ /* Write out English strings for all the identifiers in the symbol table. */
+ {
+ int f, k;
+ symbol *sym;
+ char *buf = NULL;
+
+ /* Note the squirmings necessary to make sure that the last string
+ is not followed by a comma (is it necessary to do that ?? ) */
+ for (sym = symtab, f = k = 0; sym; sym = sym->next)
+ if (!sym->unique && !is_keyword (sym->name))
+ {
+ if (!f)
+ {
+ dump (0, "/* Strings for subcommand specifiers. */");
+ dump (1, "static const char *settings[]=");
+ dump (1, "{");
+ f = 1;
+ }
+
+ if (buf == NULL)
+ buf = xmalloc (1024);
+ else
+ dump (0, buf);
+
+ sprintf (buf, "\"%s\",",sym->name);
+ }
+ if (buf)
+ {
+ buf[strlen (buf) - 1] = 0;
+ dump (0, buf);
+ free (buf);
+ }
+ if (f)
+ {
+ dump (-1, "};");
+ dump (-1, nullstr);
+ }
+ }
+
+
+ indent = 0;
+
+ dump (0, "static int");
+ dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
+ make_identifier (cmdname));
+ dump (1, "{");
+
+ dump (1, "for (;;)");
+ dump (1, "{");
+
+
+ for (sbc = subcommands; sbc; sbc = sbc->next)
+ {
+ dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
+ f = 1;
+ dump (1, "{");
+
+ dump_aux_subcommand (sbc);
+
+ dump (-1, "}");
+ outdent ();
+ }
+
+ for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
+ {
+ dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
+ f = 1;
+ dump (1, "{");
+ dump(0,"aux_%s();",make_identifier(asbc->value));
+ dump (-1, "}");
+ outdent ();
+ }
+
+ dump (1, "if (!lex_match ('/'))");
+ dump (0, "break;");
+ dump (-2, "}");
+ outdent ();
+ dump (0, nullstr);
+ dump (1, "if (token != '.')");
+ dump (1, "{");
+ dump (0, "lex_error (_(\"expecting end of command\"));");
+ dump (0, "goto lossage;");
+ dump (-1, "}");
+ dump (0, nullstr);
+ dump (-1, "return 1;");
+ dump (0, nullstr);
+ dump (-1, "lossage:");
+ indent ();
+ dump (0, "free_%s (p);", make_identifier (cmdname));
+ dump (0, "return 0;");
+ dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
+ make_identifier (cmdname), make_identifier (cmdname));
+ dump (0, nullstr);
+}
+
+
/* Write the output file header. */
-void
+static void
dump_header (void)
{
time_t curtime;
loctime = localtime (&curtime);
timep = asctime (loctime);
timep[strlen (timep) - 1] = 0;
- dump (0, "/* %s", ofn);
+ 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 (0, " Do not modify!");
dump (0, " */");
- dump (0, nullstr);
}
/* Write out commands to free variable state. */
-void
-dump_free (void)
+static void
+dump_free (int persistent)
{
subcommand *sbc;
int used;
indent = 0;
used = 0;
- for (sbc = subcommands; sbc; sbc = sbc->next)
- if (sbc->type == SBC_STRING)
- used = 1;
+ if ( ! persistent )
+ {
+ for (sbc = subcommands; sbc; sbc = sbc->next)
+ {
+ if (sbc->type == SBC_STRING)
+ used = 1;
+ if (sbc->type == SBC_DBL_LIST)
+ used = 1;
+ }
+
+ }
dump (0, "static void");
dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
- make_identifier (cmdname), used ? "" : " unused");
+ make_identifier (cmdname), used ? "" : " UNUSED");
dump (1, "{");
- for (sbc = subcommands; sbc; sbc = sbc->next)
- if (sbc->type == SBC_STRING)
- dump (0, "free (p->s_%s);", st_lower (sbc->name));
+ if ( ! persistent )
+ {
+
+ for (sbc = subcommands; sbc; sbc = sbc->next)
+ {
+ switch (sbc->type)
+ {
+ case SBC_VARLIST:
+ dump (0, "free (p->v_variables);");
+ 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));
+ outdent();
+ break;
+ default:
+ break;
+ }
+ }
+ }
dump (-1, "}");
+
}
+
+
/* Returns the name of a directive found on the current input line, if
any, or a null pointer if none found. */
-const char *
+static const char *
recognize_directive (void)
{
static char directive[16];
return directive;
}
+static void aux_parse (void);
+
int
main (int argc, char *argv[])
{
dump_header ();
+
indent = 0;
dump (0, "#line %d \"%s\"", ln + 1, ifn);
while (get_line ())
continue;
}
- dump (0, "#line %d \"%s\"", oln - 1, ofn);
+ dump (0, "#line %d \"%s\"", oln + 1, ofn);
if (!strcmp (directive, "specification"))
{
/* Skip leading slash-star line. */
{
indent = 0;
- dump (0, "#include <assert.h>");
dump (0, "#include <stdlib.h>");
dump (0, "#include \"alloc.h\"");
dump (0, "#include \"error.h\"");
dump (0, "#include \"lexer.h\"");
+ dump (0, "#include \"settings.h\"");
dump (0, "#include \"str.h\"");
+ dump (0, "#include \"subclist.h\"");
dump (0, "#include \"var.h\"");
+
dump (0, nullstr);
}
else if (!strcmp (directive, "declarations"))
dump_declarations ();
else if (!strcmp (directive, "functions"))
{
- dump_parser ();
- dump_free ();
+ dump_parser (0);
+ dump_free (0);
+ }
+ else if (!strcmp (directive, "_functions"))
+ {
+ dump_parser (1);
+ dump_free (1);
+ }
+ else if (!strcmp (directive, "aux_functions"))
+ {
+ aux_parse();
+ dump_aux_parser ();
}
else
error ("unknown directive `%s'", directive);
dump (0, "#line %d \"%s\"", ln + 1, ifn);
}
+
+
return EXIT_SUCCESS;
}
+/* Parse an entire auxilliary specification. */
+static void
+aux_parse (void)
+{
+ aux_subcommand *sbc;
+ aux_subcommand *prevsbc = 0 ;
+ get_line();
+ lex_get();
+
+ for (;;)
+ {
+ sbc = xmalloc(sizeof(aux_subcommand));
+ sbc->next = prevsbc;
+ sbc->name = xstrdup (tokstr);
+ lex_get();
+ skip_token('=');
+ sbc->value = xstrdup (tokstr);
+ lex_get();
+ if (token == '.')
+ break;
+ skip_token(';');
+ prevsbc = sbc;
+
+ }
+ /* Skip trailing star-slash line. */
+ get_line ();
+ aux_subcommands = sbc;
+}
+
+