1 /* q2c - parser generator for PSPP procedures.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
35 #define EXIT_SUCCESS 0
39 #define EXIT_FAILURE 1
43 #include "misc/strerror.c"
46 #include "debug-print.h"
48 /* Max length of an input line. */
49 #define MAX_LINE_LEN 1024
51 /* Max token length. */
52 #define MAX_TOK_LEN 1024
57 /* Have the input and output files been opened yet? */
60 /* Input, output files. */
63 /* Input, output file names. */
66 /* Input, output file line number. */
69 /* Input line buffer, current position. */
75 T_STRING = 256, /* String literal. */
76 T_ID = 257 /* Identifier. */
79 /* Current token: either one of the above, or a single character. */
82 /* Token string value. */
85 /* Utility functions. */
89 /* Close all open files and delete the output file, on failure. */
98 if (remove (ofn) == -1)
99 fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
102 void hcf (void) NO_RETURN;
104 /* Terminate unsuccessfully. */
112 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
113 int error (const char *, ...) PRINTF_FORMAT (1, 2);
115 /* Output an error message and terminate unsuccessfully. */
117 fail (const char *format, ...)
121 va_start (args, format);
122 fprintf (stderr, "%s: ", pgmname);
123 vfprintf (stderr, format, args);
124 fprintf (stderr, "\n");
130 /* Output a context-dependent error message and terminate
133 error (const char *format,...)
137 va_start (args, format);
138 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
139 vfprintf (stderr, format, args);
140 fprintf (stderr, "\n");
146 #define VME "virtual memory exhausted"
148 /* Allocate a block of SIZE bytes and return a pointer to its
151 xmalloc (size_t size)
160 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
165 /* Make a dynamically allocated copy of string S and return a pointer
166 to the first character. */
168 xstrdup (const char *s)
174 size = strlen (s) + 1;
178 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
184 /* Returns a pointer to one of 8 static buffers. The buffers are used
189 static char b[8][256];
198 /* Copies a string to a static buffer, converting it to lowercase in
199 the process, and returns a pointer to the static buffer. */
201 st_lower (const char *s)
205 p = cp = get_buffer ();
207 *cp++ = tolower ((unsigned char) (*s++));
213 /* Copies a string to a static buffer, converting it to uppercase in
214 the process, and returns a pointer to the static buffer. */
216 st_upper (const char *s)
220 p = cp = get_buffer ();
222 *cp++ = toupper ((unsigned char) (*s++));
228 /* Returns the address of the first non-whitespace character in S, or
229 the address of the null terminator if none. */
231 skip_ws (const char *s)
233 while (isspace ((unsigned char) *s))
238 /* Read one line from the input file into buf. Lines having special
239 formats are handled specially. */
244 if (0 == fgets (buf, MAX_LINE_LEN, in))
247 fail ("%s: fgets: %s", ifn, strerror (errno));
251 cp = strchr (buf, '\n');
259 /* Symbol table manager. */
261 /* Symbol table entry. */
262 typedef struct symbol symbol;
265 symbol *next; /* Next symbol in symbol table. */
266 char *name; /* Symbol name. */
267 int unique; /* 1=Name must be unique in this file. */
268 int ln; /* Line number of definition. */
269 int value; /* Symbol value. */
275 /* Add a symbol to the symbol table having name NAME, uniqueness
276 UNIQUE, and value VALUE. If a symbol having the same name is found
277 in the symbol table, its sequence number is returned and the symbol
278 table is not modified. Otherwise, the symbol is added and the next
279 available sequence number is returned. */
281 add_symbol (const char *name, int unique, int value)
286 sym = xmalloc (sizeof (symbol));
287 sym->name = xstrdup (name);
288 sym->unique = unique;
301 if (!strcmp (iter->name, name))
305 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
307 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
324 /* Finds the symbol having given sequence number X within the symbol
325 table, and returns the associated symbol structure. */
332 while (x > 1 && iter)
342 /* Writes a printable representation of the current token to
350 printf ("TR_STRING\t\"%s\"\n", tokstr);
353 printf ("STRING\t\"%s\"\n", tokstr);
356 printf ("ID\t%s\n", tokstr);
359 printf ("PUNCT\t%c\n", token);
362 #endif /* DEBUGGING */
364 /* Reads a token from the input file. */
368 /* Skip whitespace and check for end of file. */
376 fail ("%s: Unexpected end of file.", ifn);
384 while (*cp != '"' && *cp)
390 error ("Unterminated string literal.");
398 error ("Unterminated string literal.");
401 else if (*cp == '_' || isalnum ((unsigned char) *cp))
405 while (*cp == '_' || isalnum ((unsigned char) *cp))
406 *dest++ = toupper ((unsigned char) (*cp++));
419 /* Force the current token to be an identifier token. */
424 error ("Identifier expected.");
427 /* Force the current token to be a string token. */
431 if (token != T_STRING)
432 error ("String expected.");
435 /* Checks whether the current token is the identifier S; if so, skips
436 the token and returns 1; otherwise, returns 0. */
438 match_id (const char *s)
440 if (token == T_ID && !strcmp (tokstr, s))
448 /* Checks whether the current token is T. If so, skips the token and
449 returns 1; otherwise, returns 0. */
461 /* Force the current token to be T, and skip it. */
466 error ("`%c' expected.", t);
472 /* Some specifiers have associated values. */
475 VAL_NONE, /* No value. */
476 VAL_INT, /* Integer value. */
477 VAL_DBL /* Floating point value. */
480 /* For those specifiers with values, the syntax of those values. */
483 VT_PLAIN, /* Unadorned value. */
484 VT_PAREN /* Value must be enclosed in parentheses. */
487 /* Forward definition. */
488 typedef struct specifier specifier;
490 /* A single setting. */
491 typedef struct setting setting;
494 specifier *parent; /* Owning specifier. */
495 setting *next; /* Next in the chain. */
496 char *specname; /* Name of the setting. */
497 int con; /* Sequence number. */
500 int valtype; /* One of VT_*. */
501 int value; /* One of VAL_*. */
502 int optvalue; /* 1=value is optional, 0=value is required. */
503 char *valname; /* Variable name for the value. */
504 char *restriction; /* !=NULL: expression specifying valid values. */
507 /* A single specifier. */
510 specifier *next; /* Next in the chain. */
511 char *varname; /* Variable name. */
512 setting *s; /* Associated settings. */
514 setting *def; /* Default setting. */
515 setting *omit_kw; /* Setting for which the keyword can be omitted. */
517 int index; /* Next array index. */
520 /* Subcommand types. */
523 SBC_PLAIN, /* The usual case. */
524 SBC_VARLIST, /* Variable list. */
525 SBC_INT, /* Integer value. */
526 SBC_PINT, /* Integer inside parentheses. */
527 SBC_DBL, /* Floating point value. */
528 SBC_INT_LIST, /* List of integers (?). */
529 SBC_DBL_LIST, /* List of floating points (?). */
530 SBC_CUSTOM, /* Custom. */
531 SBC_ARRAY, /* Array of boolean values. */
532 SBC_STRING, /* String value. */
533 SBC_VAR /* Single variable name. */
537 /* A single subcommand. */
538 typedef struct subcommand subcommand;
541 subcommand *next; /* Next in the chain. */
542 char *name; /* Subcommand name. */
543 subcommand_type type; /* One of SBC_*. */
544 int once; /* 1=Subcommand may appear only once. */
545 int narray; /* Index of next array element. */
546 const char *prefix; /* Prefix for variable and constant names. */
547 specifier *spec; /* Array of specifiers. */
549 /* SBC_STRING and SBC_INT only. */
550 char *restriction; /* Expression restricting string length. */
551 char *message; /* Error message. */
552 int translatable; /* Error message is translatable */
555 typedef struct aux_subcommand aux_subcommand;
556 struct aux_subcommand
558 aux_subcommand *next; /* Next in the chain. */
559 char *name; /* Subcommand name. */
560 char *value; /* Subcommand value */
563 static aux_subcommand *aux_subcommands ;
565 /* Name of the command; i.e., DESCRIPTIVES. */
568 /* Short prefix for the command; i.e., `dsc_'. */
571 /* List of subcommands. */
572 subcommand *subcommands;
574 /* Default subcommand if any, or NULL. */
579 void parse_subcommands (void);
581 /* Parse an entire specification. */
585 /* Get the command name and prefix. */
586 if (token != T_STRING && token != T_ID)
587 error ("Command name expected.");
588 cmdname = xstrdup (tokstr);
592 prefix = xstrdup (tokstr);
597 /* Read all the subcommands. */
600 parse_subcommands ();
603 /* Parses a single setting into S, given subcommand information SBC
604 and specifier information SPEC. */
606 parse_setting (setting *s, specifier *spec)
610 if (match_token ('*'))
613 error ("Cannot have two settings with omittable keywords.");
618 if (match_token ('!'))
621 error ("Cannot have two default settings.");
627 s->specname = xstrdup (tokstr);
628 s->con = add_symbol (s->specname, 0, 0);
633 /* Parse setting value info if necessary. */
634 if (token != '/' && token != ';' && token != '.' && token != ',')
638 s->valtype = VT_PAREN;
642 s->valtype = VT_PLAIN;
644 s->optvalue = match_token ('*');
648 else if (match_id ("D"))
651 error ("`n' or `d' expected.");
656 s->valname = xstrdup (tokstr);
663 s->restriction = xstrdup (tokstr);
667 s->restriction = NULL;
669 if (s->valtype == VT_PAREN)
674 /* Parse a single specifier into SPEC, given subcommand information
677 parse_specifier (specifier *spec, subcommand *sbc)
682 spec->omit_kw = NULL;
683 spec->varname = NULL;
687 spec->varname = xstrdup (st_lower (tokstr));
691 /* Handle array elements. */
694 spec->index = sbc->narray;
695 if (sbc->type == SBC_ARRAY)
707 /* Parse all the settings. */
709 setting **s = &spec->s;
713 *s = xmalloc (sizeof (setting));
714 parse_setting (*s, spec);
715 if (token == ',' || token == ';' || token == '.')
724 /* Parse a list of specifiers for subcommand SBC. */
726 parse_specifiers (subcommand *sbc)
728 specifier **spec = &sbc->spec;
730 if (token == ';' || token == '.')
738 *spec = xmalloc (sizeof (specifier));
739 parse_specifier (*spec, sbc);
740 if (token == ';' || token == '.')
743 spec = &(*spec)->next;
745 (*spec)->next = NULL;
748 /* Parse a subcommand into SBC. */
750 parse_subcommand (subcommand *sbc)
752 if (match_token ('*'))
755 error ("Multiple default subcommands.");
759 sbc->once = match_token ('+');
762 sbc->name = xstrdup (tokstr);
766 sbc->type = SBC_PLAIN;
768 sbc->translatable = 0;
770 if (match_token ('['))
773 sbc->prefix = xstrdup (st_lower (tokstr));
779 sbc->type = SBC_ARRAY;
780 parse_specifiers (sbc);
784 if (match_token ('('))
787 sbc->prefix = xstrdup (st_lower (tokstr));
797 if (match_id ("VAR"))
799 if (match_id ("VARLIST"))
801 if (match_token ('('))
804 sbc->message = xstrdup (tokstr);
809 else sbc->message = NULL;
811 sbc->type = SBC_VARLIST;
813 else if (match_id ("INTEGER"))
815 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
816 if ( token == T_STRING)
818 sbc->restriction = xstrdup (tokstr);
820 if ( match_id("N_") )
826 sbc->translatable = 1;
832 sbc->message = xstrdup (tokstr);
835 sbc->restriction = NULL;
837 else if (match_id ("PINT"))
838 sbc->type = SBC_PINT;
839 else if (match_id ("DOUBLE"))
840 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
841 else if (match_id ("STRING"))
843 sbc->type = SBC_STRING;
844 if (token == T_STRING)
846 sbc->restriction = xstrdup (tokstr);
849 sbc->message = xstrdup (tokstr);
853 sbc->restriction = NULL;
855 else if (match_id ("CUSTOM"))
856 sbc->type = SBC_CUSTOM;
858 parse_specifiers (sbc);
862 /* Parse all the subcommands. */
864 parse_subcommands (void)
866 subcommand **sbc = &subcommands;
870 *sbc = xmalloc (sizeof (subcommand));
873 parse_subcommand (*sbc);
885 #define BASE_INDENT 2 /* Starting indent. */
886 #define INC_INDENT 2 /* Indent increment. */
888 /* Increment the indent. */
889 #define indent() indent += INC_INDENT
890 #define outdent() indent -= INC_INDENT
892 /* Size of the indent from the left margin. */
895 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
897 /* Write line FORMAT to the output file, formatted as with printf,
898 indented `indent' characters from the left margin. If INDENTION is
899 greater than 0, indents BASE_INDENT * INDENTION characters after
900 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
901 * INDENTION characters _before_ writing the line. */
903 dump (int indention, const char *format, ...)
909 indent += BASE_INDENT * indention;
912 va_start (args, format);
913 for (i = 0; i < indent; i++)
915 vfprintf (out, format, args);
920 indent += BASE_INDENT * indention;
923 /* Write the structure members for specifier SPEC to the output file.
924 SBC is the including subcommand. */
926 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
929 dump (0, "long %s%s;", sbc->prefix, spec->varname);
934 for (s = spec->s; s; s = s->next)
936 if (s->value != VAL_NONE)
938 const char *typename;
940 assert (s->value == VAL_INT || s->value == VAL_DBL);
941 typename = s->value == VAL_INT ? "long" : "double";
943 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
949 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
951 is_keyword (const char *t)
953 static const char *kw[] =
955 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
956 "NE", "ALL", "BY", "TO", "WITH", 0,
960 for (cp = kw; *cp; cp++)
961 if (!strcmp (t, *cp))
966 /* Transforms a string NAME into a valid C identifier: makes
967 everything lowercase and maps nonalphabetic characters to
968 underscores. Returns a pointer to a static buffer. */
970 make_identifier (const char *name)
972 char *p = get_buffer ();
975 for (cp = p; *name; name++)
976 if (isalpha ((unsigned char) *name))
977 *cp++ = tolower ((unsigned char) (*name));
985 /* Writes the struct and enum declarations for the parser. */
987 dump_declarations (void)
991 /* Write out enums for all the identifiers in the symbol table. */
997 /* Note the squirmings necessary to make sure that the last enum
998 is not followed by a comma, as mandated by ANSI C89. */
999 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1000 if (!sym->unique && !is_keyword (sym->name))
1004 dump (0, "/* Settings for subcommand specifiers. */");
1011 buf = xmalloc (1024);
1016 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1020 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1025 buf[strlen (buf) - 1] = 0;
1036 /* For every array subcommand, write out the associated enumerated
1041 for (sbc = subcommands; sbc; sbc = sbc->next)
1042 if (sbc->type == SBC_ARRAY && sbc->narray)
1044 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1052 for (spec = sbc->spec; spec; spec = spec->next)
1054 dump (0, "%s%s%s = %d,",
1055 st_upper (prefix), st_upper (sbc->prefix),
1056 st_upper (spec->varname), spec->index);
1058 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1066 /* Write out structure declaration. */
1070 dump (0, "/* %s structure. */", cmdname);
1071 dump (1, "struct cmd_%s", make_identifier (cmdname));
1073 for (sbc = subcommands; sbc; sbc = sbc->next)
1077 if (sbc != subcommands)
1080 dump (0, "/* %s subcommand. */", sbc->name);
1081 dump (0, "int sbc_%s;", st_lower (sbc->name));
1090 for (spec = sbc->spec; spec; spec = spec->next)
1094 if (sbc->type == SBC_PLAIN)
1095 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1099 dump (0, "int a_%s[%d];",
1100 st_lower (sbc->name), sbc->narray);
1105 dump_specifier_vars (spec, sbc);
1111 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1112 st_lower (sbc->name));
1113 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1114 st_lower (sbc->name));
1118 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1119 st_lower (sbc->name));
1123 dump (0, "char *s_%s;", st_lower (sbc->name));
1128 dump (0, "long n_%s;", st_lower (sbc->name));
1132 dump (0, "double n_%s;", st_lower (sbc->name));
1144 /* Write out prototypes for custom_*() functions as necessary. */
1149 for (sbc = subcommands; sbc; sbc = sbc->next)
1150 if (sbc->type == SBC_CUSTOM)
1155 dump (0, "/* Prototype for custom subcommands of %s. */",
1158 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1159 st_lower (prefix), st_lower (sbc->name),
1160 make_identifier (cmdname));
1167 /* Prototypes for parsing and freeing functions. */
1169 dump (0, "/* Command parsing functions. */");
1170 dump (0, "static int parse_%s (struct cmd_%s *);",
1171 make_identifier (cmdname), make_identifier (cmdname));
1172 dump (0, "static void free_%s (struct cmd_%s *);",
1173 make_identifier (cmdname), make_identifier (cmdname));
1178 /* Writes out code to initialize all the variables that need
1179 initialization for particular specifier SPEC inside subcommand SBC. */
1181 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1189 st_upper (prefix), find_symbol (spec->def->con)->name);
1192 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1198 for (s = spec->s; s; s = s->next)
1200 if (s->value != VAL_NONE)
1204 assert (s->value == VAL_INT || s->value == VAL_DBL);
1205 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1207 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1213 /* Write code to initialize all variables. */
1215 dump_vars_init (int persistent)
1217 /* Loop through all the subcommands. */
1221 for (sbc = subcommands; sbc; sbc = sbc->next)
1225 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1242 for (spec = sbc->spec; spec; spec = spec->next)
1243 if (spec->s == NULL)
1245 if (sbc->type == SBC_PLAIN)
1246 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1249 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1250 st_lower (sbc->name), st_lower (sbc->name));
1255 dump_specifier_init (spec, sbc);
1260 dump (0, "p->%sn_%s = 0;",
1261 st_lower (sbc->prefix), st_lower (sbc->name));
1262 dump (0, "p->%sv_%s = NULL;",
1263 st_lower (sbc->prefix), st_lower (sbc->name));
1267 dump (0, "p->%sv_%s = NULL;",
1268 st_lower (sbc->prefix), st_lower (sbc->name));
1272 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1277 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1288 /* Return a pointer to a static buffer containing an expression that
1289 will match token T. */
1291 make_match (const char *t)
1301 sprintf (s, "lex_match (T_%s)", t);
1302 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1303 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1304 "|| lex_match_id (\"TRUE\"))");
1305 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1306 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1307 "|| lex_match_id (\"FALSE\"))");
1308 else if (isdigit ((unsigned char) t[0]))
1309 sprintf (s, "lex_match_int (%s)", t);
1311 sprintf (s, "lex_match_id (\"%s\")", t);
1316 /* Write out the parsing code for specifier SPEC within subcommand
1319 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1323 if (spec->omit_kw && spec->omit_kw->next)
1324 error ("Omittable setting is not last setting in `%s' specifier.",
1326 if (spec->omit_kw && spec->omit_kw->parent->next)
1327 error ("Default specifier is not in last specifier in `%s' "
1328 "subcommand.", sbc->name);
1330 for (s = spec->s; s; s = s->next)
1332 int first = spec == sbc->spec && s == spec->s;
1334 /* Match the setting's keyword. */
1335 if (spec->omit_kw == s)
1342 dump (1, "%s;", make_match (s->specname));
1345 dump (1, "%sif (%s)", first ? "" : "else ",
1346 make_match (s->specname));
1348 /* Handle values. */
1349 if (s->value == VAL_NONE)
1350 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1351 st_upper (prefix), find_symbol (s->con)->name);
1354 if (spec->omit_kw != s)
1358 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1359 st_upper (prefix), find_symbol (s->con)->name);
1361 if (s->valtype == VT_PAREN)
1365 dump (1, "if (lex_match ('('))");
1370 dump (1, "if (!lex_match ('('))");
1372 dump (0, "msg (SE, _(\"`(' expected after %s "
1373 "specifier of %s subcommand.\"));",
1374 s->specname, sbc->name);
1375 dump (0, "goto lossage;");
1381 if (s->value == VAL_INT)
1383 dump (1, "if (!lex_integer_p ())");
1385 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1386 "requires an integer argument.\"));",
1387 s->specname, sbc->name);
1388 dump (0, "goto lossage;");
1390 dump (-1, "p->%s%s = lex_integer ();",
1391 sbc->prefix, st_lower (s->valname));
1395 dump (1, "if (token != T_NUM)");
1397 dump (0, "msg (SE, _(\"Number expected after %s "
1398 "specifier of %s subcommand.\"));",
1399 s->specname, sbc->name);
1400 dump (0, "goto lossage;");
1402 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1403 st_lower (s->valname));
1410 str = xmalloc (MAX_TOK_LEN);
1411 str2 = xmalloc (MAX_TOK_LEN);
1412 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1413 sprintf (str, s->restriction, str2, str2, str2, str2,
1414 str2, str2, str2, str2);
1415 dump (1, "if (!(%s))", str);
1421 dump (0, "msg (SE, _(\"Bad argument for %s "
1422 "specifier of %s subcommand.\"));",
1423 s->specname, sbc->name);
1424 dump (0, "goto lossage;");
1429 dump (0, "lex_get ();");
1431 if (s->valtype == VT_PAREN)
1433 dump (1, "if (!lex_match (')'))");
1435 dump (0, "msg (SE, _(\"`)' expected after argument for "
1436 "%s specifier of %s.\"));",
1437 s->specname, sbc->name);
1438 dump (0, "goto lossage;");
1448 if (s != spec->omit_kw)
1452 if (s == spec->omit_kw)
1461 /* Write out the code to parse subcommand SBC. */
1463 dump_subcommand (const subcommand *sbc)
1465 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1469 dump (1, "while (token != '/' && token != '.')");
1475 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1478 dump_specifier_parse (spec, sbc);
1482 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1483 make_match (st_upper (spec->varname)));
1484 if (sbc->type == SBC_PLAIN)
1485 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1488 dump (0, "p->a_%s[%s%s%s] = 1;",
1489 st_lower (sbc->name),
1490 st_upper (prefix), st_upper (sbc->prefix),
1491 st_upper (spec->varname));
1501 /* This code first finds the last specifier in sbc. Then it
1502 finds the last setting within that last specifier. Either
1503 or both might be NULL. */
1516 if (spec && (!spec->s || !spec->omit_kw))
1520 dump (0, "lex_error (NULL);");
1521 dump (0, "goto lossage;");
1527 dump (0, "lex_match (',');");
1531 else if (sbc->type == SBC_VARLIST)
1533 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1535 st_lower (sbc->prefix), st_lower (sbc->name),
1536 st_lower (sbc->prefix), st_lower (sbc->name),
1537 sbc->message ? " |" : "",
1538 sbc->message ? sbc->message : "");
1539 dump (0, "goto lossage;");
1542 else if (sbc->type == SBC_VAR)
1544 dump (0, "p->%sv_%s = parse_variable ();",
1545 st_lower (sbc->prefix), st_lower (sbc->name));
1546 dump (1, "if (p->%sv_%s)",
1547 st_lower (sbc->prefix), st_lower (sbc->name));
1548 dump (0, "goto lossage;");
1551 else if (sbc->type == SBC_STRING)
1553 if (sbc->restriction)
1558 dump (1, "if (!lex_force_string ())");
1559 dump (0, "return 0;");
1561 if (sbc->restriction)
1563 dump (0, "x = ds_length (&tokstr);");
1564 dump (1, "if (!(%s))", sbc->restriction);
1566 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1567 sbc->name, sbc->message);
1568 dump (0, "goto lossage;");
1572 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1573 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1574 st_lower (sbc->name));
1575 dump (0, "lex_get ();");
1576 if (sbc->restriction)
1579 else if (sbc->type == SBC_DBL)
1581 dump (1, "if (!lex_force_num ())");
1582 dump (0, "goto lossage;");
1583 dump (-1, "p->n_%s = lex_double ();", st_lower (sbc->name));
1584 dump (0, "lex_get();");
1586 else if (sbc->type == SBC_INT)
1590 dump (1, "if (!lex_force_int ())");
1591 dump (0, "goto lossage;");
1592 dump (-1, "x = lex_integer ();");
1593 dump (0, "lex_get();");
1594 if (sbc->restriction)
1597 dump (1, "if (!(%s))", sbc->restriction);
1599 sprintf(buf,sbc->message,sbc->name);
1600 if ( sbc->translatable )
1601 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1603 dump (0, "msg (SE, \"%s\");",buf);
1604 dump (0, "goto lossage;");
1607 dump (-1, "p->n_%s = x;", st_lower (sbc->name));
1610 else if (sbc->type == SBC_PINT)
1612 dump (0, "lex_match ('(');");
1613 dump (1, "if (!lex_force_int ())");
1614 dump (0, "goto lossage;");
1615 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1616 dump (0, "lex_match (')');");
1618 else if (sbc->type == SBC_CUSTOM)
1620 dump (1, "switch (%scustom_%s (p))",
1621 st_lower (prefix), st_lower (sbc->name));
1623 dump (1, "case 0:");
1624 dump (0, "goto lossage;");
1625 dump (-1, "case 1:");
1628 dump (-1, "case 2:");
1630 dump (0, "lex_error (NULL);");
1631 dump (0, "goto lossage;");
1632 dump (-1, "default:");
1634 dump (0, "assert (0);");
1640 /* Write out entire parser. */
1642 dump_parser (int persistent)
1648 dump (0, "static int");
1649 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1650 make_identifier (cmdname));
1653 dump_vars_init (persistent);
1655 dump (1, "for (;;)");
1659 if (def && (def->type == SBC_VARLIST))
1661 if (def->type == SBC_VARLIST)
1662 dump (1, "if (token == T_ID "
1663 "&& dict_lookup_var (default_dict, tokid) != NULL "
1664 "&& lex_look_ahead () != '=')");
1667 dump (0, "if ((token == T_ID "
1668 "&& dict_lookup_var (default_dict, tokid) "
1669 "&& lex_look_ahead () != '=')");
1670 dump (1, " || token == T_ALL)");
1673 dump (0, "p->sbc_%s++;", st_lower (def->name));
1674 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1676 st_lower (def->prefix), st_lower (def->name),
1677 st_lower (def->prefix), st_lower (def->name));
1678 dump (0, "goto lossage;");
1683 else if (def && def->type == SBC_CUSTOM)
1685 dump (1, "switch (%scustom_%s (p))",
1686 st_lower (prefix), st_lower (def->name));
1688 dump (1, "case 0:");
1689 dump (0, "goto lossage;");
1690 dump (-1, "case 1:");
1692 dump (0, "p->sbc_%s++;", st_lower (def->name));
1693 dump (0, "continue;");
1694 dump (-1, "case 2:");
1697 dump (-1, "default:");
1699 dump (0, "assert (0);");
1707 for (sbc = subcommands; sbc; sbc = sbc->next)
1709 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1713 dump (0, "lex_match ('=');");
1714 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1717 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1719 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1721 dump (0, "goto lossage;");
1725 dump_subcommand (sbc);
1730 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1731 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1734 dump (0, "lex_match ('=');");
1736 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1737 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1739 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1740 dump(0,"set_cmd_algorithm(ENHANCED);");
1746 dump (1, "if (!lex_match ('/'))");
1751 dump (1, "if (token != '.')");
1753 dump (0, "lex_error (_(\"expecting end of command\"));");
1754 dump (0, "goto lossage;");
1757 dump (-1, "return 1;");
1759 dump (-1, "lossage:");
1761 dump (0, "free_%s (p);", make_identifier (cmdname));
1762 dump (0, "return 0;");
1768 /* Write out the code to parse aux subcommand SBC. */
1770 dump_aux_subcommand (const subcommand *sbc)
1772 if (sbc->type == SBC_PLAIN )
1776 for (spec = sbc->spec; spec; spec = spec->next)
1779 sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1781 dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1782 dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1787 else if (sbc->type == SBC_STRING)
1789 dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1791 else if (sbc->type == SBC_INT)
1793 dump (0, "msg(MM,\"%s is %%ld\",p->n_%s);", sbc->name,st_lower(sbc->name) );
1795 else if (sbc->type == SBC_CUSTOM)
1797 dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1805 /* Write out auxilliary parser. */
1807 dump_aux_parser (void)
1811 aux_subcommand *asbc;
1813 /* Write out English strings for all the identifiers in the symbol table. */
1819 /* Note the squirmings necessary to make sure that the last string
1820 is not followed by a comma (is it necessary to do that ?? ) */
1821 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1822 if (!sym->unique && !is_keyword (sym->name))
1826 dump (0, "/* Strings for subcommand specifiers. */");
1827 dump (1, "static const char *settings[]=");
1833 buf = xmalloc (1024);
1837 sprintf (buf, "\"%s\",",sym->name);
1841 buf[strlen (buf) - 1] = 0;
1855 dump (0, "static int");
1856 dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1857 make_identifier (cmdname));
1860 dump (1, "for (;;)");
1864 for (sbc = subcommands; sbc; sbc = sbc->next)
1866 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1870 dump_aux_subcommand (sbc);
1876 for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
1878 dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
1881 dump(0,"aux_%s();",make_identifier(asbc->value));
1886 dump (1, "if (!lex_match ('/'))");
1891 dump (1, "if (token != '.')");
1893 dump (0, "lex_error (_(\"expecting end of command\"));");
1894 dump (0, "goto lossage;");
1897 dump (-1, "return 1;");
1899 dump (-1, "lossage:");
1901 dump (0, "free_%s (p);", make_identifier (cmdname));
1902 dump (0, "return 0;");
1903 dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
1904 make_identifier (cmdname), make_identifier (cmdname));
1909 /* Write the output file header. */
1918 curtime = time (NULL);
1919 loctime = localtime (&curtime);
1920 timep = asctime (loctime);
1921 timep[strlen (timep) - 1] = 0;
1922 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1924 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1925 dump (0, " Do not modify!");
1929 dump (0, "#include \"settings.h\"");
1933 /* Write out commands to free variable state. */
1935 dump_free (int persistent)
1945 for (sbc = subcommands; sbc; sbc = sbc->next)
1946 if (sbc->type == SBC_STRING)
1950 dump (0, "static void");
1951 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1952 make_identifier (cmdname), used ? "" : " UNUSED");
1958 for (sbc = subcommands; sbc; sbc = sbc->next)
1959 if (sbc->type == SBC_STRING)
1960 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1969 /* Returns the name of a directive found on the current input line, if
1970 any, or a null pointer if none found. */
1972 recognize_directive (void)
1974 static char directive[16];
1978 if (strncmp (sp, "/*", 2))
1980 sp = skip_ws (sp + 2);
1985 ep = strchr (sp, ')');
1991 memcpy (directive, sp, ep - sp);
1992 directive[ep - sp] = '\0';
1996 static void aux_parse (void);
1999 main (int argc, char *argv[])
2003 fail ("Syntax: q2c input.q output.c");
2006 in = fopen (ifn, "r");
2008 fail ("%s: open: %s.", ifn, strerror (errno));
2011 out = fopen (ofn, "w");
2013 fail ("%s: open: %s.", ofn, strerror (errno));
2016 buf = xmalloc (MAX_LINE_LEN);
2017 tokstr = xmalloc (MAX_TOK_LEN);
2023 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2026 const char *directive = recognize_directive ();
2027 if (directive == NULL)
2029 dump (0, "%s", buf);
2033 dump (0, "#line %d \"%s\"", oln - 1, ofn);
2034 if (!strcmp (directive, "specification"))
2036 /* Skip leading slash-star line. */
2042 /* Skip trailing star-slash line. */
2045 else if (!strcmp (directive, "headers"))
2049 dump (0, "#include <stdlib.h>");
2050 dump (0, "#include \"alloc.h\"");
2051 dump (0, "#include \"error.h\"");
2052 dump (0, "#include \"lexer.h\"");
2053 dump (0, "#include \"str.h\"");
2054 dump (0, "#include \"var.h\"");
2058 else if (!strcmp (directive, "declarations"))
2059 dump_declarations ();
2060 else if (!strcmp (directive, "functions"))
2065 else if (!strcmp (directive, "_functions"))
2070 else if (!strcmp (directive, "aux_functions"))
2076 error ("unknown directive `%s'", directive);
2078 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2083 return EXIT_SUCCESS;
2086 /* Parse an entire auxilliary specification. */
2090 aux_subcommand *sbc;
2091 aux_subcommand *prevsbc = 0 ;
2097 sbc = xmalloc(sizeof(aux_subcommand));
2098 sbc->next = prevsbc;
2099 sbc->name = xstrdup (tokstr);
2102 sbc->value = xstrdup (tokstr);
2110 /* Skip trailing star-slash line. */
2112 aux_subcommands = sbc;