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
36 #define EXIT_SUCCESS 0
40 #define EXIT_FAILURE 1
44 #include "misc/strerror.c"
47 #include "debug-print.h"
49 /* Max length of an input line. */
50 #define MAX_LINE_LEN 1024
52 /* Max token length. */
53 #define MAX_TOK_LEN 1024
58 /* Have the input and output files been opened yet? */
61 /* Input, output files. */
64 /* Input, output file names. */
67 /* Input, output file line number. */
70 /* Input line buffer, current position. */
76 T_STRING = 256, /* String literal. */
77 T_ID = 257 /* Identifier. */
80 /* Current token: either one of the above, or a single character. */
83 /* Token string value. */
86 /* Utility functions. */
90 /* Close all open files and delete the output file, on failure. */
99 if (remove (ofn) == -1)
100 fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
103 void hcf (void) NO_RETURN;
105 /* Terminate unsuccessfully. */
113 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
114 int error (const char *, ...) PRINTF_FORMAT (1, 2);
116 /* Output an error message and terminate unsuccessfully. */
118 fail (const char *format, ...)
122 va_start (args, format);
123 fprintf (stderr, "%s: ", pgmname);
124 vfprintf (stderr, format, args);
125 fprintf (stderr, "\n");
131 /* Output a context-dependent error message and terminate
134 error (const char *format,...)
138 va_start (args, format);
139 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
140 vfprintf (stderr, format, args);
141 fprintf (stderr, "\n");
147 #define VME "virtual memory exhausted"
149 /* Allocate a block of SIZE bytes and return a pointer to its
152 xmalloc (size_t size)
161 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
166 /* Make a dynamically allocated copy of string S and return a pointer
167 to the first character. */
169 xstrdup (const char *s)
175 size = strlen (s) + 1;
179 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
185 /* Returns a pointer to one of 8 static buffers. The buffers are used
190 static char b[8][256];
199 /* Copies a string to a static buffer, converting it to lowercase in
200 the process, and returns a pointer to the static buffer. */
202 st_lower (const char *s)
206 p = cp = get_buffer ();
208 *cp++ = tolower ((unsigned char) (*s++));
214 /* Copies a string to a static buffer, converting it to uppercase in
215 the process, and returns a pointer to the static buffer. */
217 st_upper (const char *s)
221 p = cp = get_buffer ();
223 *cp++ = toupper ((unsigned char) (*s++));
229 /* Returns the address of the first non-whitespace character in S, or
230 the address of the null terminator if none. */
232 skip_ws (const char *s)
234 while (isspace ((unsigned char) *s))
239 /* Read one line from the input file into buf. Lines having special
240 formats are handled specially. */
245 if (0 == fgets (buf, MAX_LINE_LEN, in))
248 fail ("%s: fgets: %s", ifn, strerror (errno));
252 cp = strchr (buf, '\n');
260 /* Symbol table manager. */
262 /* Symbol table entry. */
263 typedef struct symbol symbol;
266 symbol *next; /* Next symbol in symbol table. */
267 char *name; /* Symbol name. */
268 int unique; /* 1=Name must be unique in this file. */
269 int ln; /* Line number of definition. */
270 int value; /* Symbol value. */
276 /* Add a symbol to the symbol table having name NAME, uniqueness
277 UNIQUE, and value VALUE. If a symbol having the same name is found
278 in the symbol table, its sequence number is returned and the symbol
279 table is not modified. Otherwise, the symbol is added and the next
280 available sequence number is returned. */
282 add_symbol (const char *name, int unique, int value)
287 sym = xmalloc (sizeof (symbol));
288 sym->name = xstrdup (name);
289 sym->unique = unique;
302 if (!strcmp (iter->name, name))
306 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
308 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
325 /* Finds the symbol having given sequence number X within the symbol
326 table, and returns the associated symbol structure. */
333 while (x > 1 && iter)
343 /* Writes a printable representation of the current token to
351 printf ("TR_STRING\t\"%s\"\n", tokstr);
354 printf ("STRING\t\"%s\"\n", tokstr);
357 printf ("ID\t%s\n", tokstr);
360 printf ("PUNCT\t%c\n", token);
363 #endif /* DEBUGGING */
365 /* Reads a token from the input file. */
369 /* Skip whitespace and check for end of file. */
377 fail ("%s: Unexpected end of file.", ifn);
385 while (*cp != '"' && *cp)
391 error ("Unterminated string literal.");
399 error ("Unterminated string literal.");
402 else if (*cp == '_' || isalnum ((unsigned char) *cp))
406 while (*cp == '_' || isalnum ((unsigned char) *cp))
407 *dest++ = toupper ((unsigned char) (*cp++));
420 /* Force the current token to be an identifier token. */
425 error ("Identifier expected.");
428 /* Force the current token to be a string token. */
432 if (token != T_STRING)
433 error ("String expected.");
436 /* Checks whether the current token is the identifier S; if so, skips
437 the token and returns 1; otherwise, returns 0. */
439 match_id (const char *s)
441 if (token == T_ID && !strcmp (tokstr, s))
449 /* Checks whether the current token is T. If so, skips the token and
450 returns 1; otherwise, returns 0. */
462 /* Force the current token to be T, and skip it. */
467 error ("`%c' expected.", t);
473 /* Some specifiers have associated values. */
476 VAL_NONE, /* No value. */
477 VAL_INT, /* Integer value. */
478 VAL_DBL /* Floating point value. */
481 /* For those specifiers with values, the syntax of those values. */
484 VT_PLAIN, /* Unadorned value. */
485 VT_PAREN /* Value must be enclosed in parentheses. */
488 /* Forward definition. */
489 typedef struct specifier specifier;
491 /* A single setting. */
492 typedef struct setting setting;
495 specifier *parent; /* Owning specifier. */
496 setting *next; /* Next in the chain. */
497 char *specname; /* Name of the setting. */
498 int con; /* Sequence number. */
501 int valtype; /* One of VT_*. */
502 int value; /* One of VAL_*. */
503 int optvalue; /* 1=value is optional, 0=value is required. */
504 char *valname; /* Variable name for the value. */
505 char *restriction; /* !=NULL: expression specifying valid values. */
508 /* A single specifier. */
511 specifier *next; /* Next in the chain. */
512 char *varname; /* Variable name. */
513 setting *s; /* Associated settings. */
515 setting *def; /* Default setting. */
516 setting *omit_kw; /* Setting for which the keyword can be omitted. */
518 int index; /* Next array index. */
521 /* Subcommand types. */
524 SBC_PLAIN, /* The usual case. */
525 SBC_VARLIST, /* Variable list. */
526 SBC_INT, /* Integer value. */
527 SBC_PINT, /* Integer inside parentheses. */
528 SBC_DBL, /* Floating point value. */
529 SBC_INT_LIST, /* List of integers (?). */
530 SBC_DBL_LIST, /* List of floating points (?). */
531 SBC_CUSTOM, /* Custom. */
532 SBC_ARRAY, /* Array of boolean values. */
533 SBC_STRING, /* String value. */
534 SBC_VAR /* Single variable name. */
538 /* A single subcommand. */
539 typedef struct subcommand subcommand;
542 subcommand *next; /* Next in the chain. */
543 char *name; /* Subcommand name. */
544 subcommand_type type; /* One of SBC_*. */
545 int once; /* 1=Subcommand may appear only once. */
546 int narray; /* Index of next array element. */
547 const char *prefix; /* Prefix for variable and constant names. */
548 specifier *spec; /* Array of specifiers. */
550 /* SBC_STRING and SBC_INT only. */
551 char *restriction; /* Expression restricting string length. */
552 char *message; /* Error message. */
553 int translatable; /* Error message is translatable */
556 typedef struct aux_subcommand aux_subcommand;
557 struct aux_subcommand
559 aux_subcommand *next; /* Next in the chain. */
560 char *name; /* Subcommand name. */
561 char *value; /* Subcommand value */
564 static aux_subcommand *aux_subcommands ;
566 /* Name of the command; i.e., DESCRIPTIVES. */
569 /* Short prefix for the command; i.e., `dsc_'. */
572 /* List of subcommands. */
573 subcommand *subcommands;
575 /* Default subcommand if any, or NULL. */
580 void parse_subcommands (void);
582 /* Parse an entire specification. */
586 /* Get the command name and prefix. */
587 if (token != T_STRING && token != T_ID)
588 error ("Command name expected.");
589 cmdname = xstrdup (tokstr);
593 prefix = xstrdup (tokstr);
598 /* Read all the subcommands. */
601 parse_subcommands ();
604 /* Parses a single setting into S, given subcommand information SBC
605 and specifier information SPEC. */
607 parse_setting (setting *s, specifier *spec)
611 if (match_token ('*'))
614 error ("Cannot have two settings with omittable keywords.");
619 if (match_token ('!'))
622 error ("Cannot have two default settings.");
628 s->specname = xstrdup (tokstr);
629 s->con = add_symbol (s->specname, 0, 0);
634 /* Parse setting value info if necessary. */
635 if (token != '/' && token != ';' && token != '.' && token != ',')
639 s->valtype = VT_PAREN;
643 s->valtype = VT_PLAIN;
645 s->optvalue = match_token ('*');
649 else if (match_id ("D"))
652 error ("`n' or `d' expected.");
657 s->valname = xstrdup (tokstr);
664 s->restriction = xstrdup (tokstr);
668 s->restriction = NULL;
670 if (s->valtype == VT_PAREN)
675 /* Parse a single specifier into SPEC, given subcommand information
678 parse_specifier (specifier *spec, subcommand *sbc)
683 spec->omit_kw = NULL;
684 spec->varname = NULL;
688 spec->varname = xstrdup (st_lower (tokstr));
692 /* Handle array elements. */
695 spec->index = sbc->narray;
696 if (sbc->type == SBC_ARRAY)
708 /* Parse all the settings. */
710 setting **s = &spec->s;
714 *s = xmalloc (sizeof (setting));
715 parse_setting (*s, spec);
716 if (token == ',' || token == ';' || token == '.')
725 /* Parse a list of specifiers for subcommand SBC. */
727 parse_specifiers (subcommand *sbc)
729 specifier **spec = &sbc->spec;
731 if (token == ';' || token == '.')
739 *spec = xmalloc (sizeof (specifier));
740 parse_specifier (*spec, sbc);
741 if (token == ';' || token == '.')
744 spec = &(*spec)->next;
746 (*spec)->next = NULL;
749 /* Parse a subcommand into SBC. */
751 parse_subcommand (subcommand *sbc)
753 if (match_token ('*'))
756 error ("Multiple default subcommands.");
760 sbc->once = match_token ('+');
763 sbc->name = xstrdup (tokstr);
767 sbc->type = SBC_PLAIN;
769 sbc->translatable = 0;
771 if (match_token ('['))
774 sbc->prefix = xstrdup (st_lower (tokstr));
780 sbc->type = SBC_ARRAY;
781 parse_specifiers (sbc);
785 if (match_token ('('))
788 sbc->prefix = xstrdup (st_lower (tokstr));
798 if (match_id ("VAR"))
800 if (match_id ("VARLIST"))
802 if (match_token ('('))
805 sbc->message = xstrdup (tokstr);
810 else sbc->message = NULL;
812 sbc->type = SBC_VARLIST;
814 else if (match_id ("INTEGER"))
816 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
817 if ( token == T_STRING)
819 sbc->restriction = xstrdup (tokstr);
821 if ( match_id("N_") )
827 sbc->translatable = 1;
833 sbc->message = xstrdup (tokstr);
836 sbc->restriction = NULL;
838 else if (match_id ("PINT"))
839 sbc->type = SBC_PINT;
840 else if (match_id ("DOUBLE"))
842 if ( match_id ("LIST") )
843 sbc->type = SBC_DBL_LIST;
847 else if (match_id ("STRING"))
849 sbc->type = SBC_STRING;
850 if (token == T_STRING)
852 sbc->restriction = xstrdup (tokstr);
855 sbc->message = xstrdup (tokstr);
859 sbc->restriction = NULL;
861 else if (match_id ("CUSTOM"))
862 sbc->type = SBC_CUSTOM;
864 parse_specifiers (sbc);
868 /* Parse all the subcommands. */
870 parse_subcommands (void)
872 subcommand **sbc = &subcommands;
876 *sbc = xmalloc (sizeof (subcommand));
879 parse_subcommand (*sbc);
891 #define BASE_INDENT 2 /* Starting indent. */
892 #define INC_INDENT 2 /* Indent increment. */
894 /* Increment the indent. */
895 #define indent() indent += INC_INDENT
896 #define outdent() indent -= INC_INDENT
898 /* Size of the indent from the left margin. */
901 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
903 /* Write line FORMAT to the output file, formatted as with printf,
904 indented `indent' characters from the left margin. If INDENTION is
905 greater than 0, indents BASE_INDENT * INDENTION characters after
906 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
907 * INDENTION characters _before_ writing the line. */
909 dump (int indention, const char *format, ...)
915 indent += BASE_INDENT * indention;
918 va_start (args, format);
919 for (i = 0; i < indent; i++)
921 vfprintf (out, format, args);
926 indent += BASE_INDENT * indention;
929 /* Write the structure members for specifier SPEC to the output file.
930 SBC is the including subcommand. */
932 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
935 dump (0, "long %s%s;", sbc->prefix, spec->varname);
940 for (s = spec->s; s; s = s->next)
942 if (s->value != VAL_NONE)
944 const char *typename;
946 assert (s->value == VAL_INT || s->value == VAL_DBL);
947 typename = s->value == VAL_INT ? "long" : "double";
949 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
955 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
957 is_keyword (const char *t)
959 static const char *kw[] =
961 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
962 "NE", "ALL", "BY", "TO", "WITH", 0,
966 for (cp = kw; *cp; cp++)
967 if (!strcmp (t, *cp))
972 /* Transforms a string NAME into a valid C identifier: makes
973 everything lowercase and maps nonalphabetic characters to
974 underscores. Returns a pointer to a static buffer. */
976 make_identifier (const char *name)
978 char *p = get_buffer ();
981 for (cp = p; *name; name++)
982 if (isalpha ((unsigned char) *name))
983 *cp++ = tolower ((unsigned char) (*name));
991 /* Writes the struct and enum declarations for the parser. */
993 dump_declarations (void)
997 /* Write out enums for all the identifiers in the symbol table. */
1003 /* Note the squirmings necessary to make sure that the last enum
1004 is not followed by a comma, as mandated by ANSI C89. */
1005 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1006 if (!sym->unique && !is_keyword (sym->name))
1010 dump (0, "/* Settings for subcommand specifiers. */");
1017 buf = xmalloc (1024);
1022 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1026 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1031 buf[strlen (buf) - 1] = 0;
1042 /* Write out some type definitions */
1044 dump (0, "#define MAXLISTS 10");
1048 /* For every array subcommand, write out the associated enumerated
1053 for (sbc = subcommands; sbc; sbc = sbc->next)
1054 if (sbc->type == SBC_ARRAY && sbc->narray)
1056 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1064 for (spec = sbc->spec; spec; spec = spec->next)
1066 dump (0, "%s%s%s = %d,",
1067 st_upper (prefix), st_upper (sbc->prefix),
1068 st_upper (spec->varname), spec->index);
1070 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1078 /* Write out structure declaration. */
1082 dump (0, "/* %s structure. */", cmdname);
1083 dump (1, "struct cmd_%s", make_identifier (cmdname));
1085 for (sbc = subcommands; sbc; sbc = sbc->next)
1089 if (sbc != subcommands)
1092 dump (0, "/* %s subcommand. */", sbc->name);
1093 dump (0, "int sbc_%s;", st_lower (sbc->name));
1102 for (spec = sbc->spec; spec; spec = spec->next)
1106 if (sbc->type == SBC_PLAIN)
1107 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1111 dump (0, "int a_%s[%d];",
1112 st_lower (sbc->name), sbc->narray);
1117 dump_specifier_vars (spec, sbc);
1123 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1124 st_lower (sbc->name));
1125 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1126 st_lower (sbc->name));
1130 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1131 st_lower (sbc->name));
1135 dump (0, "char *s_%s;", st_lower (sbc->name));
1140 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1144 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1148 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1149 st_lower(sbc->name));
1153 dump (0, "subc_list_int il_%s[MAXLISTS];",
1154 st_lower(sbc->name));
1167 /* Write out prototypes for custom_*() functions as necessary. */
1172 for (sbc = subcommands; sbc; sbc = sbc->next)
1173 if (sbc->type == SBC_CUSTOM)
1178 dump (0, "/* Prototype for custom subcommands of %s. */",
1181 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1182 st_lower (prefix), st_lower (sbc->name),
1183 make_identifier (cmdname));
1190 /* Prototypes for parsing and freeing functions. */
1192 dump (0, "/* Command parsing functions. */");
1193 dump (0, "static int parse_%s (struct cmd_%s *);",
1194 make_identifier (cmdname), make_identifier (cmdname));
1195 dump (0, "static void free_%s (struct cmd_%s *);",
1196 make_identifier (cmdname), make_identifier (cmdname));
1201 /* Writes out code to initialize all the variables that need
1202 initialization for particular specifier SPEC inside subcommand SBC. */
1204 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1212 st_upper (prefix), find_symbol (spec->def->con)->name);
1215 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1221 for (s = spec->s; s; s = s->next)
1223 if (s->value != VAL_NONE)
1227 assert (s->value == VAL_INT || s->value == VAL_DBL);
1228 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1230 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1236 /* Write code to initialize all variables. */
1238 dump_vars_init (int persistent)
1240 /* Loop through all the subcommands. */
1244 for (sbc = subcommands; sbc; sbc = sbc->next)
1248 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1259 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1260 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1261 st_lower (sbc->name)
1269 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1270 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1283 for (spec = sbc->spec; spec; spec = spec->next)
1284 if (spec->s == NULL)
1286 if (sbc->type == SBC_PLAIN)
1287 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1290 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1291 st_lower (sbc->name), st_lower (sbc->name));
1296 dump_specifier_init (spec, sbc);
1301 dump (0, "p->%sn_%s = 0;",
1302 st_lower (sbc->prefix), st_lower (sbc->name));
1303 dump (0, "p->%sv_%s = NULL;",
1304 st_lower (sbc->prefix), st_lower (sbc->name));
1308 dump (0, "p->%sv_%s = NULL;",
1309 st_lower (sbc->prefix), st_lower (sbc->name));
1313 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1320 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1321 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1333 /* Return a pointer to a static buffer containing an expression that
1334 will match token T. */
1336 make_match (const char *t)
1346 sprintf (s, "lex_match (T_%s)", t);
1347 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1348 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1349 "|| lex_match_id (\"TRUE\"))");
1350 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1351 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1352 "|| lex_match_id (\"FALSE\"))");
1353 else if (isdigit ((unsigned char) t[0]))
1354 sprintf (s, "lex_match_int (%s)", t);
1356 sprintf (s, "lex_match_id (\"%s\")", t);
1361 /* Write out the parsing code for specifier SPEC within subcommand
1364 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1368 if (spec->omit_kw && spec->omit_kw->next)
1369 error ("Omittable setting is not last setting in `%s' specifier.",
1371 if (spec->omit_kw && spec->omit_kw->parent->next)
1372 error ("Default specifier is not in last specifier in `%s' "
1373 "subcommand.", sbc->name);
1375 for (s = spec->s; s; s = s->next)
1377 int first = spec == sbc->spec && s == spec->s;
1379 /* Match the setting's keyword. */
1380 if (spec->omit_kw == s)
1387 dump (1, "%s;", make_match (s->specname));
1390 dump (1, "%sif (%s)", first ? "" : "else ",
1391 make_match (s->specname));
1393 /* Handle values. */
1394 if (s->value == VAL_NONE)
1395 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1396 st_upper (prefix), find_symbol (s->con)->name);
1399 if (spec->omit_kw != s)
1403 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1404 st_upper (prefix), find_symbol (s->con)->name);
1406 if (s->valtype == VT_PAREN)
1410 dump (1, "if (lex_match ('('))");
1415 dump (1, "if (!lex_match ('('))");
1417 dump (0, "msg (SE, _(\"`(' expected after %s "
1418 "specifier of %s subcommand.\"));",
1419 s->specname, sbc->name);
1420 dump (0, "goto lossage;");
1426 if (s->value == VAL_INT)
1428 dump (1, "if (!lex_integer_p ())");
1430 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1431 "requires an integer argument.\"));",
1432 s->specname, sbc->name);
1433 dump (0, "goto lossage;");
1435 dump (-1, "p->%s%s = lex_integer ();",
1436 sbc->prefix, st_lower (s->valname));
1440 dump (1, "if (token != T_NUM)");
1442 dump (0, "msg (SE, _(\"Number expected after %s "
1443 "specifier of %s subcommand.\"));",
1444 s->specname, sbc->name);
1445 dump (0, "goto lossage;");
1447 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1448 st_lower (s->valname));
1455 str = xmalloc (MAX_TOK_LEN);
1456 str2 = xmalloc (MAX_TOK_LEN);
1457 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1458 sprintf (str, s->restriction, str2, str2, str2, str2,
1459 str2, str2, str2, str2);
1460 dump (1, "if (!(%s))", str);
1466 dump (0, "msg (SE, _(\"Bad argument for %s "
1467 "specifier of %s subcommand.\"));",
1468 s->specname, sbc->name);
1469 dump (0, "goto lossage;");
1474 dump (0, "lex_get ();");
1476 if (s->valtype == VT_PAREN)
1478 dump (1, "if (!lex_match (')'))");
1480 dump (0, "msg (SE, _(\"`)' expected after argument for "
1481 "%s specifier of %s.\"));",
1482 s->specname, sbc->name);
1483 dump (0, "goto lossage;");
1493 if (s != spec->omit_kw)
1497 if (s == spec->omit_kw)
1506 /* Write out the code to parse subcommand SBC. */
1508 dump_subcommand (const subcommand *sbc)
1510 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1514 dump (1, "while (token != '/' && token != '.')");
1520 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1523 dump_specifier_parse (spec, sbc);
1527 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1528 make_match (st_upper (spec->varname)));
1529 if (sbc->type == SBC_PLAIN)
1530 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1533 dump (0, "p->a_%s[%s%s%s] = 1;",
1534 st_lower (sbc->name),
1535 st_upper (prefix), st_upper (sbc->prefix),
1536 st_upper (spec->varname));
1546 /* This code first finds the last specifier in sbc. Then it
1547 finds the last setting within that last specifier. Either
1548 or both might be NULL. */
1561 if (spec && (!spec->s || !spec->omit_kw))
1565 dump (0, "lex_error (NULL);");
1566 dump (0, "goto lossage;");
1572 dump (0, "lex_match (',');");
1576 else if (sbc->type == SBC_VARLIST)
1578 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1580 st_lower (sbc->prefix), st_lower (sbc->name),
1581 st_lower (sbc->prefix), st_lower (sbc->name),
1582 sbc->message ? " |" : "",
1583 sbc->message ? sbc->message : "");
1584 dump (0, "goto lossage;");
1587 else if (sbc->type == SBC_VAR)
1589 dump (0, "p->%sv_%s = parse_variable ();",
1590 st_lower (sbc->prefix), st_lower (sbc->name));
1591 dump (1, "if (p->%sv_%s)",
1592 st_lower (sbc->prefix), st_lower (sbc->name));
1593 dump (0, "goto lossage;");
1596 else if (sbc->type == SBC_STRING)
1598 if (sbc->restriction)
1603 dump (1, "if (!lex_force_string ())");
1604 dump (0, "return 0;");
1606 if (sbc->restriction)
1608 dump (0, "x = ds_length (&tokstr);");
1609 dump (1, "if (!(%s))", sbc->restriction);
1611 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1612 sbc->name, sbc->message);
1613 dump (0, "goto lossage;");
1617 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1618 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1619 st_lower (sbc->name));
1620 dump (0, "lex_get ();");
1621 if (sbc->restriction)
1624 else if (sbc->type == SBC_DBL)
1626 dump (1, "if (!lex_force_num ())");
1627 dump (0, "goto lossage;");
1628 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_double ();",
1629 st_lower (sbc->name), st_lower (sbc->name) );
1630 dump (0, "lex_get();");
1632 else if (sbc->type == SBC_INT)
1636 dump (1, "if (!lex_force_int ())");
1637 dump (0, "goto lossage;");
1638 dump (-1, "x = lex_integer ();");
1639 dump (0, "lex_get();");
1640 if (sbc->restriction)
1643 dump (1, "if (!(%s))", sbc->restriction);
1645 sprintf(buf,sbc->message,sbc->name);
1646 if ( sbc->translatable )
1647 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1649 dump (0, "msg (SE, \"%s\");",buf);
1650 dump (0, "goto lossage;");
1653 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1656 else if (sbc->type == SBC_PINT)
1658 dump (0, "lex_match ('(');");
1659 dump (1, "if (!lex_force_int ())");
1660 dump (0, "goto lossage;");
1661 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1662 dump (0, "lex_match (')');");
1664 else if (sbc->type == SBC_DBL_LIST)
1666 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1668 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1669 dump (0, "goto lossage;");
1672 dump (1, "while (token != '/' && token != '.')");
1674 dump (0, "lex_match(',');");
1675 dump (0, "if (!lex_force_num ())");
1677 dump (0, "goto lossage;");
1680 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_double ());",
1681 st_lower (sbc->name),st_lower (sbc->name)
1684 dump (0, "lex_get();");
1688 else if (sbc->type == SBC_CUSTOM)
1690 dump (1, "switch (%scustom_%s (p))",
1691 st_lower (prefix), st_lower (sbc->name));
1693 dump (1, "case 0:");
1694 dump (0, "goto lossage;");
1695 dump (-1, "case 1:");
1698 dump (-1, "case 2:");
1700 dump (0, "lex_error (NULL);");
1701 dump (0, "goto lossage;");
1702 dump (-1, "default:");
1704 dump (0, "assert (0);");
1710 /* Write out entire parser. */
1712 dump_parser (int persistent)
1718 dump (0, "static int");
1719 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1720 make_identifier (cmdname));
1723 dump_vars_init (persistent);
1725 dump (1, "for (;;)");
1729 if (def && (def->type == SBC_VARLIST))
1731 if (def->type == SBC_VARLIST)
1732 dump (1, "if (token == T_ID "
1733 "&& dict_lookup_var (default_dict, tokid) != NULL "
1734 "&& lex_look_ahead () != '=')");
1737 dump (0, "if ((token == T_ID "
1738 "&& dict_lookup_var (default_dict, tokid) "
1739 "&& lex_look_ahead () != '=')");
1740 dump (1, " || token == T_ALL)");
1743 dump (0, "p->sbc_%s++;", st_lower (def->name));
1744 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1746 st_lower (def->prefix), st_lower (def->name),
1747 st_lower (def->prefix), st_lower (def->name));
1748 dump (0, "goto lossage;");
1753 else if (def && def->type == SBC_CUSTOM)
1755 dump (1, "switch (%scustom_%s (p))",
1756 st_lower (prefix), st_lower (def->name));
1758 dump (1, "case 0:");
1759 dump (0, "goto lossage;");
1760 dump (-1, "case 1:");
1762 dump (0, "p->sbc_%s++;", st_lower (def->name));
1763 dump (0, "continue;");
1764 dump (-1, "case 2:");
1767 dump (-1, "default:");
1769 dump (0, "assert (0);");
1777 for (sbc = subcommands; sbc; sbc = sbc->next)
1779 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1783 dump (0, "lex_match ('=');");
1784 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1787 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1789 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1791 dump (0, "goto lossage;");
1795 dump_subcommand (sbc);
1800 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1801 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1804 dump (0, "lex_match ('=');");
1806 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1807 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1809 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1810 dump(0,"set_cmd_algorithm(ENHANCED);");
1816 dump (1, "if (!lex_match ('/'))");
1821 dump (1, "if (token != '.')");
1823 dump (0, "lex_error (_(\"expecting end of command\"));");
1824 dump (0, "goto lossage;");
1827 dump (-1, "return 1;");
1829 dump (-1, "lossage:");
1831 dump (0, "free_%s (p);", make_identifier (cmdname));
1832 dump (0, "return 0;");
1838 /* Write out the code to parse aux subcommand SBC. */
1840 dump_aux_subcommand (const subcommand *sbc)
1842 if (sbc->type == SBC_PLAIN )
1846 for (spec = sbc->spec; spec; spec = spec->next)
1849 sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1851 dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1852 dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1857 else if (sbc->type == SBC_STRING)
1859 dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1861 else if (sbc->type == SBC_INT)
1865 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1866 dump (0, "msg(MM,\"%s is %%ld\",p->n_%s[i]);", sbc->name,st_lower(sbc->name) );
1870 else if (sbc->type == SBC_CUSTOM)
1872 dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1880 /* Write out auxilliary parser. */
1882 dump_aux_parser (void)
1886 aux_subcommand *asbc;
1888 /* Write out English strings for all the identifiers in the symbol table. */
1894 /* Note the squirmings necessary to make sure that the last string
1895 is not followed by a comma (is it necessary to do that ?? ) */
1896 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1897 if (!sym->unique && !is_keyword (sym->name))
1901 dump (0, "/* Strings for subcommand specifiers. */");
1902 dump (1, "static const char *settings[]=");
1908 buf = xmalloc (1024);
1912 sprintf (buf, "\"%s\",",sym->name);
1916 buf[strlen (buf) - 1] = 0;
1930 dump (0, "static int");
1931 dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1932 make_identifier (cmdname));
1935 dump (1, "for (;;)");
1939 for (sbc = subcommands; sbc; sbc = sbc->next)
1941 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1945 dump_aux_subcommand (sbc);
1951 for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
1953 dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
1956 dump(0,"aux_%s();",make_identifier(asbc->value));
1961 dump (1, "if (!lex_match ('/'))");
1966 dump (1, "if (token != '.')");
1968 dump (0, "lex_error (_(\"expecting end of command\"));");
1969 dump (0, "goto lossage;");
1972 dump (-1, "return 1;");
1974 dump (-1, "lossage:");
1976 dump (0, "free_%s (p);", make_identifier (cmdname));
1977 dump (0, "return 0;");
1978 dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
1979 make_identifier (cmdname), make_identifier (cmdname));
1984 /* Write the output file header. */
1993 curtime = time (NULL);
1994 loctime = localtime (&curtime);
1995 timep = asctime (loctime);
1996 timep[strlen (timep) - 1] = 0;
1997 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1999 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
2000 dump (0, " Do not modify!");
2004 dump (0, "#include \"settings.h\"");
2005 dump (0, "#include \"subclist.h\"");
2009 /* Write out commands to free variable state. */
2011 dump_free (int persistent)
2021 for (sbc = subcommands; sbc; sbc = sbc->next)
2023 if (sbc->type == SBC_STRING)
2025 if (sbc->type == SBC_DBL_LIST)
2031 dump (0, "static void");
2032 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
2033 make_identifier (cmdname), used ? "" : " UNUSED");
2039 for (sbc = subcommands; sbc; sbc = sbc->next)
2044 dump (0, "free (p->s_%s);", st_lower (sbc->name));
2047 dump (0, "subc_list_double_destroy(p->dl_%s);", st_lower (sbc->name));
2061 /* Returns the name of a directive found on the current input line, if
2062 any, or a null pointer if none found. */
2064 recognize_directive (void)
2066 static char directive[16];
2070 if (strncmp (sp, "/*", 2))
2072 sp = skip_ws (sp + 2);
2077 ep = strchr (sp, ')');
2083 memcpy (directive, sp, ep - sp);
2084 directive[ep - sp] = '\0';
2088 static void aux_parse (void);
2091 main (int argc, char *argv[])
2095 fail ("Syntax: q2c input.q output.c");
2098 in = fopen (ifn, "r");
2100 fail ("%s: open: %s.", ifn, strerror (errno));
2103 out = fopen (ofn, "w");
2105 fail ("%s: open: %s.", ofn, strerror (errno));
2108 buf = xmalloc (MAX_LINE_LEN);
2109 tokstr = xmalloc (MAX_TOK_LEN);
2115 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2118 const char *directive = recognize_directive ();
2119 if (directive == NULL)
2121 dump (0, "%s", buf);
2125 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2126 if (!strcmp (directive, "specification"))
2128 /* Skip leading slash-star line. */
2134 /* Skip trailing star-slash line. */
2137 else if (!strcmp (directive, "headers"))
2141 dump (0, "#include <stdlib.h>");
2142 dump (0, "#include \"alloc.h\"");
2143 dump (0, "#include \"error.h\"");
2144 dump (0, "#include \"lexer.h\"");
2145 dump (0, "#include \"str.h\"");
2146 dump (0, "#include \"var.h\"");
2150 else if (!strcmp (directive, "declarations"))
2151 dump_declarations ();
2152 else if (!strcmp (directive, "functions"))
2157 else if (!strcmp (directive, "_functions"))
2162 else if (!strcmp (directive, "aux_functions"))
2168 error ("unknown directive `%s'", directive);
2170 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2175 return EXIT_SUCCESS;
2178 /* Parse an entire auxilliary specification. */
2182 aux_subcommand *sbc;
2183 aux_subcommand *prevsbc = 0 ;
2189 sbc = xmalloc(sizeof(aux_subcommand));
2190 sbc->next = prevsbc;
2191 sbc->name = xstrdup (tokstr);
2194 sbc->value = xstrdup (tokstr);
2202 /* Skip trailing star-slash line. */
2204 aux_subcommands = sbc;