X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fq2c.c;h=6318edd395fe1a53a057d01aee289bc9b91b60a0;hb=fad826ff86720f76220b05e00dc7dfa46e418859;hp=87dcadb1044e4a6ef18624017e162d8a2b6932d9;hpb=cb4033020c8a24d573814e6ac9192046bffdccac;p=pspp-builds.git diff --git a/src/q2c.c b/src/q2c.c index 87dcadb1..6318edd3 100644 --- a/src/q2c.c +++ b/src/q2c.c @@ -30,6 +30,7 @@ #endif #include "str.h" + /* Brokenness. */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 @@ -43,8 +44,6 @@ #include "misc/strerror.c" #endif -#undef DEBUGGING -/*#define DEBUGGING 1*/ #include "debug-print.h" /* Max length of an input line. */ @@ -89,7 +88,7 @@ char *tokstr; char nullstr[] = ""; /* Close all open files and delete the output file, on failure. */ -void +static void finish_up (void) { if (!is_open) @@ -101,9 +100,7 @@ finish_up (void) 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 @@ -113,10 +110,8 @@ hcf (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 @@ -153,7 +148,7 @@ error (const char *format,...) /* Allocate a block of SIZE bytes and return a pointer to its beginning. */ -void * +static void * xmalloc (size_t size) { void *vp; @@ -168,34 +163,9 @@ xmalloc (size_t size) 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); - - 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; @@ -214,7 +184,7 @@ xstrdup (const char *s) /* 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]; @@ -228,7 +198,7 @@ get_buffer (void) /* 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; @@ -243,7 +213,7 @@ st_lower (const char *s) /* 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; @@ -258,7 +228,7 @@ st_upper (const char *s) /* 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)) @@ -268,7 +238,7 @@ skip_ws (const 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++; @@ -308,7 +278,7 @@ symbol *symtab; 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; @@ -354,7 +324,7 @@ add_symbol (const char *name, int unique, int value) /* 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; @@ -369,10 +339,10 @@ find_symbol (int x) return iter; } -#if DEBUGGING +#if DEBUGGING /* Writes a printable representation of the current token to stdout. */ -void +static void dump_token (void) { switch (token) @@ -390,7 +360,7 @@ dump_token (void) #endif /* DEBUGGING */ /* Reads a token from the input file. */ -int +static int lex_get (void) { /* Skip whitespace and check for end of file. */ @@ -404,15 +374,7 @@ lex_get (void) 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; @@ -434,6 +396,14 @@ lex_get (void) 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++; @@ -445,7 +415,7 @@ lex_get (void) } /* Force the current token to be an identifier token. */ -void +static void force_id (void) { if (token != T_ID) @@ -453,7 +423,7 @@ force_id (void) } /* Force the current token to be a string token. */ -void +static void force_string (void) { if (token != T_STRING) @@ -462,7 +432,7 @@ force_string (void) /* 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)) @@ -475,7 +445,7 @@ match_id (const char *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) @@ -487,7 +457,7 @@ match_token (int t) } /* Force the current token to be T, and skip it. */ -void +static void skip_token (int t) { if (token != t) @@ -562,6 +532,13 @@ typedef enum } 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 @@ -569,16 +546,27 @@ 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; @@ -596,7 +584,7 @@ subcommand *def; void parse_subcommands (void); /* Parse an entire specification. */ -void +static void parse (void) { /* Get the command name and prefix. */ @@ -619,7 +607,7 @@ parse (void) /* 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; @@ -690,7 +678,7 @@ parse_setting (setting *s, specifier *spec) /* Parse a single specifier into SPEC, given subcommand information SBC. */ -void +static void parse_specifier (specifier *spec, subcommand *sbc) { spec->index = 0; @@ -721,6 +709,15 @@ parse_specifier (specifier *spec, subcommand *sbc) } 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; @@ -739,7 +736,7 @@ parse_specifier (specifier *spec, subcommand *sbc) } /* Parse a list of specifiers for subcommand SBC. */ -void +static void parse_specifiers (subcommand *sbc) { specifier **spec = &sbc->spec; @@ -763,9 +760,11 @@ parse_specifiers (subcommand *sbc) } /* Parse a subcommand into SBC. */ -void +static void parse_subcommand (subcommand *sbc) { + sbc->arity = ARITY_MANY; + if (match_token ('*')) { if (def) @@ -773,7 +772,11 @@ parse_subcommand (subcommand *sbc) 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); @@ -782,6 +785,7 @@ parse_subcommand (subcommand *sbc) sbc->narray = 0; sbc->type = SBC_PLAIN; sbc->spec = NULL; + sbc->translatable = 0; if (match_token ('[')) { @@ -794,6 +798,7 @@ parse_subcommand (subcommand *sbc) sbc->type = SBC_ARRAY; parse_specifiers (sbc); + } else { @@ -827,11 +832,38 @@ parse_subcommand (subcommand *sbc) 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; @@ -886,9 +918,7 @@ parse_subcommands (void) /* 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 @@ -918,7 +948,7 @@ dump (int indention, const char *format, ...) /* 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) @@ -943,7 +973,7 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc) } /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */ -int +static int is_keyword (const char *t) { static const char *kw[] = @@ -962,7 +992,7 @@ is_keyword (const char *t) /* 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 (); @@ -979,7 +1009,7 @@ make_identifier (const char *name) } /* Writes the struct and enum declarations for the parser. */ -void +static void dump_declarations (void) { indent = 0; @@ -1029,6 +1059,12 @@ dump_declarations (void) } } + /* Write out some type definitions */ + { + dump (0, "#define MAXLISTS 10"); + } + + /* For every array subcommand, write out the associated enumerated values. */ { @@ -1046,7 +1082,6 @@ dump_declarations (void) 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); @@ -1092,8 +1127,12 @@ dump_declarations (void) 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; } } @@ -1121,9 +1160,24 @@ dump_declarations (void) 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; + + 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 */ } @@ -1169,7 +1223,7 @@ dump_declarations (void) /* 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) @@ -1203,72 +1257,97 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc) } /* 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); + } } } } @@ -1276,7 +1355,7 @@ dump_vars_init (void) /* 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; @@ -1304,7 +1383,7 @@ make_match (const char *t) /* 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; @@ -1334,6 +1413,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) 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, @@ -1344,9 +1424,18 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) 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) @@ -1369,7 +1458,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) 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.\"));", @@ -1381,7 +1470,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) } 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.\"));", @@ -1448,7 +1537,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc) } /* 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) @@ -1519,7 +1608,7 @@ dump_subcommand (const subcommand *sbc) } 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), @@ -1532,7 +1621,7 @@ dump_subcommand (const subcommand *sbc) { 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 (); @@ -1558,17 +1647,44 @@ dump_subcommand (const subcommand *sbc) 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) { @@ -1578,6 +1694,30 @@ dump_subcommand (const subcommand *sbc) 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))", @@ -1601,8 +1741,8 @@ dump_subcommand (const subcommand *sbc) } /* Write out entire parser. */ -void -dump_parser (void) +static void +dump_parser (int persistent) { int f; @@ -1613,7 +1753,7 @@ dump_parser (void) make_identifier (cmdname)); dump (1, "{"); - dump_vars_init (); + dump_vars_init (persistent); dump (1, "for (;;)"); dump (1, "{"); @@ -1622,17 +1762,19 @@ dump_parser (void) 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)); @@ -1673,7 +1815,7 @@ dump_parser (void) 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, "{"); @@ -1688,6 +1830,24 @@ dump_parser (void) 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;"); @@ -1700,6 +1860,29 @@ dump_parser (void) 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:"); @@ -1710,8 +1893,155 @@ dump_parser (void) 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; @@ -1723,17 +2053,16 @@ dump_header (void) 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; @@ -1741,25 +2070,57 @@ dump_free (void) 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]; @@ -1784,6 +2145,8 @@ recognize_directive (void) return directive; } +static void aux_parse (void); + int main (int argc, char *argv[]) { @@ -1807,6 +2170,7 @@ main (int argc, char *argv[]) dump_header (); + indent = 0; dump (0, "#line %d \"%s\"", ln + 1, ifn); while (get_line ()) @@ -1818,7 +2182,7 @@ main (int argc, char *argv[]) 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. */ @@ -1834,21 +2198,33 @@ main (int argc, char *argv[]) { indent = 0; - dump (0, "#include "); dump (0, "#include "); 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); @@ -1856,6 +2232,38 @@ main (int argc, char *argv[]) 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; +} + +