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));
103 void hcf (void) __attribute__ ((noreturn));
106 /* Terminate unsuccessfully. */
115 int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
116 int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
119 /* Output an error message and terminate unsuccessfully. */
121 fail (const char *format, ...)
125 va_start (args, format);
126 fprintf (stderr, "%s: ", pgmname);
127 vfprintf (stderr, format, args);
128 fprintf (stderr, "\n");
134 /* Output a context-dependent error message and terminate
137 error (const char *format,...)
141 va_start (args, format);
142 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
143 vfprintf (stderr, format, args);
144 fprintf (stderr, "\n");
150 #define VME "virtual memory exhausted"
152 /* Allocate a block of SIZE bytes and return a pointer to its
155 xmalloc (size_t size)
164 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
169 /* Make a dynamically allocated copy of string S and return a pointer
170 to the first character. */
172 xstrdup (const char *s)
178 size = strlen (s) + 1;
182 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
188 /* Returns a pointer to one of 8 static buffers. The buffers are used
193 static char b[8][256];
202 /* Copies a string to a static buffer, converting it to lowercase in
203 the process, and returns a pointer to the static buffer. */
205 st_lower (const char *s)
209 p = cp = get_buffer ();
211 *cp++ = tolower ((unsigned char) (*s++));
217 /* Copies a string to a static buffer, converting it to uppercase in
218 the process, and returns a pointer to the static buffer. */
220 st_upper (const char *s)
224 p = cp = get_buffer ();
226 *cp++ = toupper ((unsigned char) (*s++));
232 /* Returns the address of the first non-whitespace character in S, or
233 the address of the null terminator if none. */
235 skip_ws (const char *s)
237 while (isspace ((unsigned char) *s))
242 /* Read one line from the input file into buf. Lines having special
243 formats are handled specially. */
248 if (0 == fgets (buf, MAX_LINE_LEN, in))
251 fail ("%s: fgets: %s", ifn, strerror (errno));
255 cp = strchr (buf, '\n');
263 /* Symbol table manager. */
265 /* Symbol table entry. */
266 typedef struct symbol symbol;
269 symbol *next; /* Next symbol in symbol table. */
270 char *name; /* Symbol name. */
271 int unique; /* 1=Name must be unique in this file. */
272 int ln; /* Line number of definition. */
273 int value; /* Symbol value. */
279 /* Add a symbol to the symbol table having name NAME, uniqueness
280 UNIQUE, and value VALUE. If a symbol having the same name is found
281 in the symbol table, its sequence number is returned and the symbol
282 table is not modified. Otherwise, the symbol is added and the next
283 available sequence number is returned. */
285 add_symbol (const char *name, int unique, int value)
290 sym = xmalloc (sizeof (symbol));
291 sym->name = xstrdup (name);
292 sym->unique = unique;
305 if (!strcmp (iter->name, name))
309 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
311 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
328 /* Finds the symbol having given sequence number X within the symbol
329 table, and returns the associated symbol structure. */
336 while (x > 1 && iter)
346 /* Writes a printable representation of the current token to
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);
380 if (*cp == '_' || isalnum ((unsigned char) *cp))
384 while (*cp == '_' || isalnum ((unsigned char) *cp))
385 *dest++ = toupper ((unsigned char) (*cp++));
393 while (*cp != '"' && *cp)
399 error ("Unterminated string literal.");
407 error ("Unterminated string literal.");
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 only. */
551 char *restriction; /* Expression restricting string length. */
552 char *message; /* Error message. */
555 /* Name of the command; i.e., DESCRIPTIVES. */
558 /* Short prefix for the command; i.e., `dsc_'. */
561 /* List of subcommands. */
562 subcommand *subcommands;
564 /* Default subcommand if any, or NULL. */
569 void parse_subcommands (void);
571 /* Parse an entire specification. */
575 /* Get the command name and prefix. */
576 if (token != T_STRING && token != T_ID)
577 error ("Command name expected.");
578 cmdname = xstrdup (tokstr);
582 prefix = xstrdup (tokstr);
587 /* Read all the subcommands. */
590 parse_subcommands ();
593 /* Parses a single setting into S, given subcommand information SBC
594 and specifier information SPEC. */
596 parse_setting (setting *s, specifier *spec)
600 if (match_token ('*'))
603 error ("Cannot have two settings with omittable keywords.");
608 if (match_token ('!'))
611 error ("Cannot have two default settings.");
617 s->specname = xstrdup (tokstr);
618 s->con = add_symbol (s->specname, 0, 0);
623 /* Parse setting value info if necessary. */
624 if (token != '/' && token != ';' && token != '.' && token != ',')
628 s->valtype = VT_PAREN;
632 s->valtype = VT_PLAIN;
634 s->optvalue = match_token ('*');
638 else if (match_id ("D"))
641 error ("`n' or `d' expected.");
646 s->valname = xstrdup (tokstr);
653 s->restriction = xstrdup (tokstr);
657 s->restriction = NULL;
659 if (s->valtype == VT_PAREN)
664 /* Parse a single specifier into SPEC, given subcommand information
667 parse_specifier (specifier *spec, subcommand *sbc)
672 spec->omit_kw = NULL;
673 spec->varname = NULL;
677 spec->varname = xstrdup (st_lower (tokstr));
681 /* Handle array elements. */
684 spec->index = sbc->narray;
685 if (sbc->type == SBC_ARRAY)
697 /* Parse all the settings. */
699 setting **s = &spec->s;
703 *s = xmalloc (sizeof (setting));
704 parse_setting (*s, spec);
705 if (token == ',' || token == ';' || token == '.')
714 /* Parse a list of specifiers for subcommand SBC. */
716 parse_specifiers (subcommand *sbc)
718 specifier **spec = &sbc->spec;
720 if (token == ';' || token == '.')
728 *spec = xmalloc (sizeof (specifier));
729 parse_specifier (*spec, sbc);
730 if (token == ';' || token == '.')
733 spec = &(*spec)->next;
735 (*spec)->next = NULL;
738 /* Parse a subcommand into SBC. */
740 parse_subcommand (subcommand *sbc)
742 if (match_token ('*'))
745 error ("Multiple default subcommands.");
749 sbc->once = match_token ('+');
752 sbc->name = xstrdup (tokstr);
756 sbc->type = SBC_PLAIN;
759 if (match_token ('['))
762 sbc->prefix = xstrdup (st_lower (tokstr));
768 sbc->type = SBC_ARRAY;
769 parse_specifiers (sbc);
773 if (match_token ('('))
776 sbc->prefix = xstrdup (st_lower (tokstr));
786 if (match_id ("VAR"))
788 if (match_id ("VARLIST"))
790 if (match_token ('('))
793 sbc->message = xstrdup (tokstr);
798 else sbc->message = NULL;
800 sbc->type = SBC_VARLIST;
802 else if (match_id ("INTEGER"))
803 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
804 else if (match_id ("PINT"))
805 sbc->type = SBC_PINT;
806 else if (match_id ("DOUBLE"))
807 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
808 else if (match_id ("STRING"))
810 sbc->type = SBC_STRING;
811 if (token == T_STRING)
813 sbc->restriction = xstrdup (tokstr);
816 sbc->message = xstrdup (tokstr);
820 sbc->restriction = NULL;
822 else if (match_id ("CUSTOM"))
823 sbc->type = SBC_CUSTOM;
825 parse_specifiers (sbc);
829 /* Parse all the subcommands. */
831 parse_subcommands (void)
833 subcommand **sbc = &subcommands;
837 *sbc = xmalloc (sizeof (subcommand));
840 parse_subcommand (*sbc);
852 #define BASE_INDENT 2 /* Starting indent. */
853 #define INC_INDENT 2 /* Indent increment. */
855 /* Increment the indent. */
856 #define indent() indent += INC_INDENT
857 #define outdent() indent -= INC_INDENT
859 /* Size of the indent from the left margin. */
863 void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
866 /* Write line FORMAT to the output file, formatted as with printf,
867 indented `indent' characters from the left margin. If INDENTION is
868 greater than 0, indents BASE_INDENT * INDENTION characters after
869 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
870 * INDENTION characters _before_ writing the line. */
872 dump (int indention, const char *format, ...)
878 indent += BASE_INDENT * indention;
881 va_start (args, format);
882 for (i = 0; i < indent; i++)
884 vfprintf (out, format, args);
889 indent += BASE_INDENT * indention;
892 /* Write the structure members for specifier SPEC to the output file.
893 SBC is the including subcommand. */
895 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
898 dump (0, "long %s%s;", sbc->prefix, spec->varname);
903 for (s = spec->s; s; s = s->next)
905 if (s->value != VAL_NONE)
907 const char *typename;
909 assert (s->value == VAL_INT || s->value == VAL_DBL);
910 typename = s->value == VAL_INT ? "long" : "double";
912 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
918 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
920 is_keyword (const char *t)
922 static const char *kw[] =
924 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
925 "NE", "ALL", "BY", "TO", "WITH", 0,
929 for (cp = kw; *cp; cp++)
930 if (!strcmp (t, *cp))
935 /* Transforms a string NAME into a valid C identifier: makes
936 everything lowercase and maps nonalphabetic characters to
937 underscores. Returns a pointer to a static buffer. */
939 make_identifier (const char *name)
941 char *p = get_buffer ();
944 for (cp = p; *name; name++)
945 if (isalpha ((unsigned char) *name))
946 *cp++ = tolower ((unsigned char) (*name));
954 /* Writes the struct and enum declarations for the parser. */
956 dump_declarations (void)
960 /* Write out enums for all the identifiers in the symbol table. */
966 /* Note the squirmings necessary to make sure that the last enum
967 is not followed by a comma, as mandated by ANSI C89. */
968 for (sym = symtab, f = k = 0; sym; sym = sym->next)
969 if (!sym->unique && !is_keyword (sym->name))
973 dump (0, "/* Settings for subcommand specifiers. */");
980 buf = xmalloc (1024);
985 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
989 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
994 buf[strlen (buf) - 1] = 0;
1005 /* For every array subcommand, write out the associated enumerated
1010 for (sbc = subcommands; sbc; sbc = sbc->next)
1011 if (sbc->type == SBC_ARRAY && sbc->narray)
1013 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1021 for (spec = sbc->spec; spec; spec = spec->next)
1023 dump (0, "%s%s%s = %d,",
1024 st_upper (prefix), st_upper (sbc->prefix),
1025 st_upper (spec->varname), spec->index);
1027 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1035 /* Write out structure declaration. */
1039 dump (0, "/* %s structure. */", cmdname);
1040 dump (1, "struct cmd_%s", make_identifier (cmdname));
1042 for (sbc = subcommands; sbc; sbc = sbc->next)
1046 if (sbc != subcommands)
1049 dump (0, "/* %s subcommand. */", sbc->name);
1050 dump (0, "int sbc_%s;", st_lower (sbc->name));
1059 for (spec = sbc->spec; spec; spec = spec->next)
1063 if (sbc->type == SBC_PLAIN)
1064 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1068 dump (0, "int a_%s[%d];",
1069 st_lower (sbc->name), sbc->narray);
1074 dump_specifier_vars (spec, sbc);
1080 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1081 st_lower (sbc->name));
1082 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1083 st_lower (sbc->name));
1087 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1088 st_lower (sbc->name));
1092 dump (0, "char *s_%s;", st_lower (sbc->name));
1097 dump (0, "long n_%s;", st_lower (sbc->name));
1109 /* Write out prototypes for custom_*() functions as necessary. */
1114 for (sbc = subcommands; sbc; sbc = sbc->next)
1115 if (sbc->type == SBC_CUSTOM)
1120 dump (0, "/* Prototype for custom subcommands of %s. */",
1123 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1124 st_lower (prefix), st_lower (sbc->name),
1125 make_identifier (cmdname));
1132 /* Prototypes for parsing and freeing functions. */
1134 dump (0, "/* Command parsing functions. */");
1135 dump (0, "static int parse_%s (struct cmd_%s *);",
1136 make_identifier (cmdname), make_identifier (cmdname));
1137 dump (0, "static void free_%s (struct cmd_%s *);",
1138 make_identifier (cmdname), make_identifier (cmdname));
1143 /* Writes out code to initialize all the variables that need
1144 initialization for particular specifier SPEC inside subcommand SBC. */
1146 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1154 st_upper (prefix), find_symbol (spec->def->con)->name);
1157 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1163 for (s = spec->s; s; s = s->next)
1165 if (s->value != VAL_NONE)
1169 assert (s->value == VAL_INT || s->value == VAL_DBL);
1170 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1172 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1178 /* Write code to initialize all variables. */
1180 dump_vars_init (void)
1182 /* Loop through all the subcommands. */
1186 for (sbc = subcommands; sbc; sbc = sbc->next)
1190 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1205 for (spec = sbc->spec; spec; spec = spec->next)
1206 if (spec->s == NULL)
1208 if (sbc->type == SBC_PLAIN)
1209 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1212 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1213 st_lower (sbc->name), st_lower (sbc->name));
1218 dump_specifier_init (spec, sbc);
1223 dump (0, "p->%sn_%s = 0;",
1224 st_lower (sbc->prefix), st_lower (sbc->name));
1225 dump (0, "p->%sv_%s = NULL;",
1226 st_lower (sbc->prefix), st_lower (sbc->name));
1230 dump (0, "p->%sv_%s = NULL;",
1231 st_lower (sbc->prefix), st_lower (sbc->name));
1235 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1240 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1250 /* Return a pointer to a static buffer containing an expression that
1251 will match token T. */
1253 make_match (const char *t)
1263 sprintf (s, "lex_match (T_%s)", t);
1264 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1265 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1266 "|| lex_match_id (\"TRUE\"))");
1267 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1268 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1269 "|| lex_match_id (\"FALSE\"))");
1270 else if (isdigit ((unsigned char) t[0]))
1271 sprintf (s, "lex_match_int (%s)", t);
1273 sprintf (s, "lex_match_id (\"%s\")", t);
1278 /* Write out the parsing code for specifier SPEC within subcommand
1281 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1285 if (spec->omit_kw && spec->omit_kw->next)
1286 error ("Omittable setting is not last setting in `%s' specifier.",
1288 if (spec->omit_kw && spec->omit_kw->parent->next)
1289 error ("Default specifier is not in last specifier in `%s' "
1290 "subcommand.", sbc->name);
1292 for (s = spec->s; s; s = s->next)
1294 int first = spec == sbc->spec && s == spec->s;
1296 /* Match the setting's keyword. */
1297 if (spec->omit_kw == s)
1304 dump (1, "%s;", make_match (s->specname));
1307 dump (1, "%sif (%s)", first ? "" : "else ",
1308 make_match (s->specname));
1310 /* Handle values. */
1311 if (s->value == VAL_NONE)
1312 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1313 st_upper (prefix), find_symbol (s->con)->name);
1316 if (spec->omit_kw != s)
1320 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1321 st_upper (prefix), find_symbol (s->con)->name);
1323 if (s->valtype == VT_PAREN)
1327 dump (1, "if (lex_match ('('))");
1332 dump (1, "if (!lex_match ('('))");
1334 dump (0, "msg (SE, _(\"`(' expected after %s "
1335 "specifier of %s subcommand.\"));",
1336 s->specname, sbc->name);
1337 dump (0, "goto lossage;");
1343 if (s->value == VAL_INT)
1345 dump (1, "if (!lex_integer_p ())");
1347 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1348 "requires an integer argument.\"));",
1349 s->specname, sbc->name);
1350 dump (0, "goto lossage;");
1352 dump (-1, "p->%s%s = lex_integer ();",
1353 sbc->prefix, st_lower (s->valname));
1357 dump (1, "if (token != T_NUM)");
1359 dump (0, "msg (SE, _(\"Number expected after %s "
1360 "specifier of %s subcommand.\"));",
1361 s->specname, sbc->name);
1362 dump (0, "goto lossage;");
1364 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1365 st_lower (s->valname));
1372 str = xmalloc (MAX_TOK_LEN);
1373 str2 = xmalloc (MAX_TOK_LEN);
1374 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1375 sprintf (str, s->restriction, str2, str2, str2, str2,
1376 str2, str2, str2, str2);
1377 dump (1, "if (!(%s))", str);
1383 dump (0, "msg (SE, _(\"Bad argument for %s "
1384 "specifier of %s subcommand.\"));",
1385 s->specname, sbc->name);
1386 dump (0, "goto lossage;");
1391 dump (0, "lex_get ();");
1393 if (s->valtype == VT_PAREN)
1395 dump (1, "if (!lex_match (')'))");
1397 dump (0, "msg (SE, _(\"`)' expected after argument for "
1398 "%s specifier of %s.\"));",
1399 s->specname, sbc->name);
1400 dump (0, "goto lossage;");
1410 if (s != spec->omit_kw)
1414 if (s == spec->omit_kw)
1423 /* Write out the code to parse subcommand SBC. */
1425 dump_subcommand (const subcommand *sbc)
1427 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1431 dump (1, "while (token != '/' && token != '.')");
1437 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1440 dump_specifier_parse (spec, sbc);
1444 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1445 make_match (st_upper (spec->varname)));
1446 if (sbc->type == SBC_PLAIN)
1447 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1450 dump (0, "p->a_%s[%s%s%s] = 1;",
1451 st_lower (sbc->name),
1452 st_upper (prefix), st_upper (sbc->prefix),
1453 st_upper (spec->varname));
1463 /* This code first finds the last specifier in sbc. Then it
1464 finds the last setting within that last specifier. Either
1465 or both might be NULL. */
1478 if (spec && (!spec->s || !spec->omit_kw))
1482 dump (0, "lex_error (NULL);");
1483 dump (0, "goto lossage;");
1489 dump (0, "lex_match (',');");
1493 else if (sbc->type == SBC_VARLIST)
1495 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1497 st_lower (sbc->prefix), st_lower (sbc->name),
1498 st_lower (sbc->prefix), st_lower (sbc->name),
1499 sbc->message ? " |" : "",
1500 sbc->message ? sbc->message : "");
1501 dump (0, "goto lossage;");
1504 else if (sbc->type == SBC_VAR)
1506 dump (0, "p->%sv_%s = parse_variable ();",
1507 st_lower (sbc->prefix), st_lower (sbc->name));
1508 dump (1, "if (p->%sv_%s)",
1509 st_lower (sbc->prefix), st_lower (sbc->name));
1510 dump (0, "goto lossage;");
1513 else if (sbc->type == SBC_STRING)
1515 if (sbc->restriction)
1520 dump (1, "if (!lex_force_string ())");
1521 dump (0, "return 0;");
1523 if (sbc->restriction)
1525 dump (0, "x = ds_length (&tokstr);");
1526 dump (1, "if (!(%s))", sbc->restriction);
1528 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1529 sbc->name, sbc->message);
1530 dump (0, "goto lossage;");
1534 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1535 st_lower (sbc->name));
1536 dump (0, "lex_get ();");
1537 if (sbc->restriction)
1540 else if (sbc->type == SBC_INT)
1542 dump (1, "if (!lex_force_int ())");
1543 dump (0, "goto lossage;");
1544 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1546 else if (sbc->type == SBC_PINT)
1548 dump (0, "lex_match ('(');");
1549 dump (1, "if (!lex_force_int ())");
1550 dump (0, "goto lossage;");
1551 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1552 dump (0, "lex_match (')');");
1554 else if (sbc->type == SBC_CUSTOM)
1556 dump (1, "switch (%scustom_%s (p))",
1557 st_lower (prefix), st_lower (sbc->name));
1559 dump (1, "case 0:");
1560 dump (0, "goto lossage;");
1561 dump (-1, "case 1:");
1564 dump (-1, "case 2:");
1566 dump (0, "lex_error (NULL);");
1567 dump (0, "goto lossage;");
1568 dump (-1, "default:");
1570 dump (0, "assert (0);");
1576 /* Write out entire parser. */
1584 dump (0, "static int");
1585 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1586 make_identifier (cmdname));
1591 dump (1, "for (;;)");
1595 if (def && (def->type == SBC_VARLIST))
1597 if (def->type == SBC_VARLIST)
1598 dump (1, "if (token == T_ID "
1599 "&& dict_lookup_var (default_dict, tokid) != NULL "
1600 "&& lex_look_ahead () != '=')");
1603 dump (0, "if ((token == T_ID "
1604 "&& dict_lookup_var (default_dict, tokid) "
1605 "&& lex_look_ahead () != '=')");
1606 dump (1, " || token == T_ALL)");
1609 dump (0, "p->sbc_%s++;", st_lower (def->name));
1610 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1612 st_lower (def->prefix), st_lower (def->name),
1613 st_lower (def->prefix), st_lower (def->name));
1614 dump (0, "goto lossage;");
1619 else if (def && def->type == SBC_CUSTOM)
1621 dump (1, "switch (%scustom_%s (p))",
1622 st_lower (prefix), st_lower (def->name));
1624 dump (1, "case 0:");
1625 dump (0, "goto lossage;");
1626 dump (-1, "case 1:");
1628 dump (0, "p->sbc_%s++;", st_lower (def->name));
1629 dump (0, "continue;");
1630 dump (-1, "case 2:");
1633 dump (-1, "default:");
1635 dump (0, "assert (0);");
1643 for (sbc = subcommands; sbc; sbc = sbc->next)
1645 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1649 dump (0, "lex_match ('=');");
1650 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1653 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1655 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1657 dump (0, "goto lossage;");
1661 dump_subcommand (sbc);
1667 dump (1, "if (!lex_match ('/'))");
1672 dump (1, "if (token != '.')");
1674 dump (0, "lex_error (_(\"expecting end of command\"));");
1675 dump (0, "goto lossage;");
1678 dump (-1, "return 1;");
1680 dump (-1, "lossage:");
1682 dump (0, "free_%s (p);", make_identifier (cmdname));
1683 dump (0, "return 0;");
1688 /* Write the output file header. */
1697 curtime = time (NULL);
1698 loctime = localtime (&curtime);
1699 timep = asctime (loctime);
1700 timep[strlen (timep) - 1] = 0;
1701 dump (0, "/* %s", ofn);
1703 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1704 dump (0, " Do not modify!");
1709 /* Write out commands to free variable state. */
1719 for (sbc = subcommands; sbc; sbc = sbc->next)
1720 if (sbc->type == SBC_STRING)
1723 dump (0, "static void");
1724 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1725 make_identifier (cmdname), used ? "" : " unused");
1728 for (sbc = subcommands; sbc; sbc = sbc->next)
1729 if (sbc->type == SBC_STRING)
1730 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1735 /* Returns the name of a directive found on the current input line, if
1736 any, or a null pointer if none found. */
1738 recognize_directive (void)
1740 static char directive[16];
1744 if (strncmp (sp, "/*", 2))
1746 sp = skip_ws (sp + 2);
1751 ep = strchr (sp, ')');
1757 memcpy (directive, sp, ep - sp);
1758 directive[ep - sp] = '\0';
1763 main (int argc, char *argv[])
1767 fail ("Syntax: q2c input.q output.c");
1770 in = fopen (ifn, "r");
1772 fail ("%s: open: %s.", ifn, strerror (errno));
1775 out = fopen (ofn, "w");
1777 fail ("%s: open: %s.", ofn, strerror (errno));
1780 buf = xmalloc (MAX_LINE_LEN);
1781 tokstr = xmalloc (MAX_TOK_LEN);
1786 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1789 const char *directive = recognize_directive ();
1790 if (directive == NULL)
1792 dump (0, "%s", buf);
1796 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1797 if (!strcmp (directive, "specification"))
1799 /* Skip leading slash-star line. */
1805 /* Skip trailing star-slash line. */
1808 else if (!strcmp (directive, "headers"))
1812 dump (0, "#include <assert.h>");
1813 dump (0, "#include <stdlib.h>");
1814 dump (0, "#include \"alloc.h\"");
1815 dump (0, "#include \"error.h\"");
1816 dump (0, "#include \"lexer.h\"");
1817 dump (0, "#include \"str.h\"");
1818 dump (0, "#include \"var.h\"");
1821 else if (!strcmp (directive, "declarations"))
1822 dump_declarations ();
1823 else if (!strcmp (directive, "functions"))
1829 error ("unknown directive `%s'", directive);
1831 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1834 return EXIT_SUCCESS;