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"
47 /*#define DEBUGGING 1*/
48 #include "debug-print.h"
50 /* Max length of an input line. */
51 #define MAX_LINE_LEN 1024
53 /* Max token length. */
54 #define MAX_TOK_LEN 1024
59 /* Have the input and output files been opened yet? */
62 /* Input, output files. */
65 /* Input, output file names. */
68 /* Input, output file line number. */
71 /* Input line buffer, current position. */
77 T_STRING = 256, /* String literal. */
78 T_ID = 257 /* Identifier. */
81 /* Current token: either one of the above, or a single character. */
84 /* Token string value. */
87 /* Utility functions. */
91 /* Close all open files and delete the output file, on failure. */
100 if (remove (ofn) == -1)
101 fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
105 void hcf (void) __attribute__ ((noreturn));
108 /* Terminate unsuccessfully. */
117 int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
118 int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
121 /* Output an error message and terminate unsuccessfully. */
123 fail (const char *format, ...)
127 va_start (args, format);
128 fprintf (stderr, "%s: ", pgmname);
129 vfprintf (stderr, format, args);
130 fprintf (stderr, "\n");
136 /* Output a context-dependent error message and terminate
139 error (const char *format,...)
143 va_start (args, format);
144 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
145 vfprintf (stderr, format, args);
146 fprintf (stderr, "\n");
152 #define VME "virtual memory exhausted"
154 /* Allocate a block of SIZE bytes and return a pointer to its
157 xmalloc (size_t size)
166 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
171 /* Resize the block at PTR to size SIZE and return a pointer to the
172 beginning of the new block. */
174 xrealloc (void *ptr, size_t size)
186 vp = realloc (ptr, size);
191 fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
196 /* Make a dynamically allocated copy of string S and return a pointer
197 to the first character. */
199 xstrdup (const char *s)
205 size = strlen (s) + 1;
209 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
215 /* Returns a pointer to one of 8 static buffers. The buffers are used
220 static char b[8][256];
229 /* Copies a string to a static buffer, converting it to lowercase in
230 the process, and returns a pointer to the static buffer. */
232 st_lower (const char *s)
236 p = cp = get_buffer ();
238 *cp++ = tolower ((unsigned char) (*s++));
244 /* Copies a string to a static buffer, converting it to uppercase in
245 the process, and returns a pointer to the static buffer. */
247 st_upper (const char *s)
251 p = cp = get_buffer ();
253 *cp++ = toupper ((unsigned char) (*s++));
259 /* Returns the address of the first non-whitespace character in S, or
260 the address of the null terminator if none. */
262 skip_ws (const char *s)
264 while (isspace ((unsigned char) *s))
269 /* Read one line from the input file into buf. Lines having special
270 formats are handled specially. */
275 if (0 == fgets (buf, MAX_LINE_LEN, in))
278 fail ("%s: fgets: %s", ifn, strerror (errno));
282 cp = strchr (buf, '\n');
290 /* Symbol table manager. */
292 /* Symbol table entry. */
293 typedef struct symbol symbol;
296 symbol *next; /* Next symbol in symbol table. */
297 char *name; /* Symbol name. */
298 int unique; /* 1=Name must be unique in this file. */
299 int ln; /* Line number of definition. */
300 int value; /* Symbol value. */
306 /* Add a symbol to the symbol table having name NAME, uniqueness
307 UNIQUE, and value VALUE. If a symbol having the same name is found
308 in the symbol table, its sequence number is returned and the symbol
309 table is not modified. Otherwise, the symbol is added and the next
310 available sequence number is returned. */
312 add_symbol (const char *name, int unique, int value)
317 sym = xmalloc (sizeof (symbol));
318 sym->name = xstrdup (name);
319 sym->unique = unique;
332 if (!strcmp (iter->name, name))
336 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
338 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
355 /* Finds the symbol having given sequence number X within the symbol
356 table, and returns the associated symbol structure. */
363 while (x > 1 && iter)
373 /* Writes a printable representation of the current token to
381 printf ("STRING\t\"%s\"\n", tokstr);
384 printf ("ID\t%s\n", tokstr);
387 printf ("PUNCT\t%c\n", token);
390 #endif /* DEBUGGING */
392 /* Reads a token from the input file. */
396 /* Skip whitespace and check for end of file. */
404 fail ("%s: Unexpected end of file.", ifn);
407 if (*cp == '_' || isalnum ((unsigned char) *cp))
411 while (*cp == '_' || isalnum ((unsigned char) *cp))
412 *dest++ = toupper ((unsigned char) (*cp++));
420 while (*cp != '"' && *cp)
426 error ("Unterminated string literal.");
434 error ("Unterminated string literal.");
447 /* Force the current token to be an identifier token. */
452 error ("Identifier expected.");
455 /* Force the current token to be a string token. */
459 if (token != T_STRING)
460 error ("String expected.");
463 /* Checks whether the current token is the identifier S; if so, skips
464 the token and returns 1; otherwise, returns 0. */
466 match_id (const char *s)
468 if (token == T_ID && !strcmp (tokstr, s))
476 /* Checks whether the current token is T. If so, skips the token and
477 returns 1; otherwise, returns 0. */
489 /* Force the current token to be T, and skip it. */
494 error ("`%c' expected.", t);
500 /* Some specifiers have associated values. */
503 VAL_NONE, /* No value. */
504 VAL_INT, /* Integer value. */
505 VAL_DBL /* Floating point value. */
508 /* For those specifiers with values, the syntax of those values. */
511 VT_PLAIN, /* Unadorned value. */
512 VT_PAREN /* Value must be enclosed in parentheses. */
515 /* Forward definition. */
516 typedef struct specifier specifier;
518 /* A single setting. */
519 typedef struct setting setting;
522 specifier *parent; /* Owning specifier. */
523 setting *next; /* Next in the chain. */
524 char *specname; /* Name of the setting. */
525 int con; /* Sequence number. */
528 int valtype; /* One of VT_*. */
529 int value; /* One of VAL_*. */
530 int optvalue; /* 1=value is optional, 0=value is required. */
531 char *valname; /* Variable name for the value. */
532 char *restriction; /* !=NULL: expression specifying valid values. */
535 /* A single specifier. */
538 specifier *next; /* Next in the chain. */
539 char *varname; /* Variable name. */
540 setting *s; /* Associated settings. */
542 setting *def; /* Default setting. */
543 setting *omit_kw; /* Setting for which the keyword can be omitted. */
545 int index; /* Next array index. */
548 /* Subcommand types. */
551 SBC_PLAIN, /* The usual case. */
552 SBC_VARLIST, /* Variable list. */
553 SBC_INT, /* Integer value. */
554 SBC_PINT, /* Integer inside parentheses. */
555 SBC_DBL, /* Floating point value. */
556 SBC_INT_LIST, /* List of integers (?). */
557 SBC_DBL_LIST, /* List of floating points (?). */
558 SBC_CUSTOM, /* Custom. */
559 SBC_ARRAY, /* Array of boolean values. */
560 SBC_STRING, /* String value. */
561 SBC_VAR /* Single variable name. */
565 /* A single subcommand. */
566 typedef struct subcommand subcommand;
569 subcommand *next; /* Next in the chain. */
570 char *name; /* Subcommand name. */
571 subcommand_type type; /* One of SBC_*. */
572 int once; /* 1=Subcommand may appear only once. */
573 int narray; /* Index of next array element. */
574 const char *prefix; /* Prefix for variable and constant names. */
575 specifier *spec; /* Array of specifiers. */
577 /* SBC_STRING only. */
578 char *restriction; /* Expression restricting string length. */
579 char *message; /* Error message. */
582 /* Name of the command; i.e., DESCRIPTIVES. */
585 /* Short prefix for the command; i.e., `dsc_'. */
588 /* List of subcommands. */
589 subcommand *subcommands;
591 /* Default subcommand if any, or NULL. */
596 void parse_subcommands (void);
598 /* Parse an entire specification. */
602 /* Get the command name and prefix. */
603 if (token != T_STRING && token != T_ID)
604 error ("Command name expected.");
605 cmdname = xstrdup (tokstr);
609 prefix = xstrdup (tokstr);
614 /* Read all the subcommands. */
617 parse_subcommands ();
620 /* Parses a single setting into S, given subcommand information SBC
621 and specifier information SPEC. */
623 parse_setting (setting *s, specifier *spec)
627 if (match_token ('*'))
630 error ("Cannot have two settings with omittable keywords.");
635 if (match_token ('!'))
638 error ("Cannot have two default settings.");
644 s->specname = xstrdup (tokstr);
645 s->con = add_symbol (s->specname, 0, 0);
650 /* Parse setting value info if necessary. */
651 if (token != '/' && token != ';' && token != '.' && token != ',')
655 s->valtype = VT_PAREN;
659 s->valtype = VT_PLAIN;
661 s->optvalue = match_token ('*');
665 else if (match_id ("D"))
668 error ("`n' or `d' expected.");
673 s->valname = xstrdup (tokstr);
680 s->restriction = xstrdup (tokstr);
684 s->restriction = NULL;
686 if (s->valtype == VT_PAREN)
691 /* Parse a single specifier into SPEC, given subcommand information
694 parse_specifier (specifier *spec, subcommand *sbc)
699 spec->omit_kw = NULL;
700 spec->varname = NULL;
704 spec->varname = xstrdup (st_lower (tokstr));
708 /* Handle array elements. */
711 spec->index = sbc->narray;
712 if (sbc->type == SBC_ARRAY)
724 /* Parse all the settings. */
726 setting **s = &spec->s;
730 *s = xmalloc (sizeof (setting));
731 parse_setting (*s, spec);
732 if (token == ',' || token == ';' || token == '.')
741 /* Parse a list of specifiers for subcommand SBC. */
743 parse_specifiers (subcommand *sbc)
745 specifier **spec = &sbc->spec;
747 if (token == ';' || token == '.')
755 *spec = xmalloc (sizeof (specifier));
756 parse_specifier (*spec, sbc);
757 if (token == ';' || token == '.')
760 spec = &(*spec)->next;
762 (*spec)->next = NULL;
765 /* Parse a subcommand into SBC. */
767 parse_subcommand (subcommand *sbc)
769 if (match_token ('*'))
772 error ("Multiple default subcommands.");
776 sbc->once = match_token ('+');
779 sbc->name = xstrdup (tokstr);
783 sbc->type = SBC_PLAIN;
786 if (match_token ('['))
789 sbc->prefix = xstrdup (st_lower (tokstr));
795 sbc->type = SBC_ARRAY;
796 parse_specifiers (sbc);
800 if (match_token ('('))
803 sbc->prefix = xstrdup (st_lower (tokstr));
813 if (match_id ("VAR"))
815 if (match_id ("VARLIST"))
817 if (match_token ('('))
820 sbc->message = xstrdup (tokstr);
825 else sbc->message = NULL;
827 sbc->type = SBC_VARLIST;
829 else if (match_id ("INTEGER"))
830 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
831 else if (match_id ("PINT"))
832 sbc->type = SBC_PINT;
833 else if (match_id ("DOUBLE"))
834 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
835 else if (match_id ("STRING"))
837 sbc->type = SBC_STRING;
838 if (token == T_STRING)
840 sbc->restriction = xstrdup (tokstr);
843 sbc->message = xstrdup (tokstr);
847 sbc->restriction = NULL;
849 else if (match_id ("CUSTOM"))
850 sbc->type = SBC_CUSTOM;
852 parse_specifiers (sbc);
856 /* Parse all the subcommands. */
858 parse_subcommands (void)
860 subcommand **sbc = &subcommands;
864 *sbc = xmalloc (sizeof (subcommand));
867 parse_subcommand (*sbc);
879 #define BASE_INDENT 2 /* Starting indent. */
880 #define INC_INDENT 2 /* Indent increment. */
882 /* Increment the indent. */
883 #define indent() indent += INC_INDENT
884 #define outdent() indent -= INC_INDENT
886 /* Size of the indent from the left margin. */
890 void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
893 /* Write line FORMAT to the output file, formatted as with printf,
894 indented `indent' characters from the left margin. If INDENTION is
895 greater than 0, indents BASE_INDENT * INDENTION characters after
896 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
897 * INDENTION characters _before_ writing the line. */
899 dump (int indention, const char *format, ...)
905 indent += BASE_INDENT * indention;
908 va_start (args, format);
909 for (i = 0; i < indent; i++)
911 vfprintf (out, format, args);
916 indent += BASE_INDENT * indention;
919 /* Write the structure members for specifier SPEC to the output file.
920 SBC is the including subcommand. */
922 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
925 dump (0, "long %s%s;", sbc->prefix, spec->varname);
930 for (s = spec->s; s; s = s->next)
932 if (s->value != VAL_NONE)
934 const char *typename;
936 assert (s->value == VAL_INT || s->value == VAL_DBL);
937 typename = s->value == VAL_INT ? "long" : "double";
939 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
945 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
947 is_keyword (const char *t)
949 static const char *kw[] =
951 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
952 "NE", "ALL", "BY", "TO", "WITH", 0,
956 for (cp = kw; *cp; cp++)
957 if (!strcmp (t, *cp))
962 /* Transforms a string NAME into a valid C identifier: makes
963 everything lowercase and maps nonalphabetic characters to
964 underscores. Returns a pointer to a static buffer. */
966 make_identifier (const char *name)
968 char *p = get_buffer ();
971 for (cp = p; *name; name++)
972 if (isalpha ((unsigned char) *name))
973 *cp++ = tolower ((unsigned char) (*name));
981 /* Writes the struct and enum declarations for the parser. */
983 dump_declarations (void)
987 /* Write out enums for all the identifiers in the symbol table. */
993 /* Note the squirmings necessary to make sure that the last enum
994 is not followed by a comma, as mandated by ANSI C89. */
995 for (sym = symtab, f = k = 0; sym; sym = sym->next)
996 if (!sym->unique && !is_keyword (sym->name))
1000 dump (0, "/* Settings for subcommand specifiers. */");
1007 buf = xmalloc (1024);
1012 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1016 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1021 buf[strlen (buf) - 1] = 0;
1032 /* For every array subcommand, write out the associated enumerated
1037 for (sbc = subcommands; sbc; sbc = sbc->next)
1038 if (sbc->type == SBC_ARRAY && sbc->narray)
1040 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1048 for (spec = sbc->spec; spec; spec = spec->next)
1050 dump (0, "%s%s%s = %d,",
1051 st_upper (prefix), st_upper (sbc->prefix),
1052 st_upper (spec->varname), spec->index);
1054 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1062 /* Write out structure declaration. */
1066 dump (0, "/* %s structure. */", cmdname);
1067 dump (1, "struct cmd_%s", make_identifier (cmdname));
1069 for (sbc = subcommands; sbc; sbc = sbc->next)
1073 if (sbc != subcommands)
1076 dump (0, "/* %s subcommand. */", sbc->name);
1077 dump (0, "int sbc_%s;", st_lower (sbc->name));
1086 for (spec = sbc->spec; spec; spec = spec->next)
1090 if (sbc->type == SBC_PLAIN)
1091 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1095 dump (0, "int a_%s[%d];",
1096 st_lower (sbc->name), sbc->narray);
1101 dump_specifier_vars (spec, sbc);
1107 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1108 st_lower (sbc->name));
1109 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1110 st_lower (sbc->name));
1114 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1115 st_lower (sbc->name));
1119 dump (0, "char *s_%s;", st_lower (sbc->name));
1124 dump (0, "long n_%s;", st_lower (sbc->name));
1136 /* Write out prototypes for custom_*() functions as necessary. */
1141 for (sbc = subcommands; sbc; sbc = sbc->next)
1142 if (sbc->type == SBC_CUSTOM)
1147 dump (0, "/* Prototype for custom subcommands of %s. */",
1150 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1151 st_lower (prefix), st_lower (sbc->name),
1152 make_identifier (cmdname));
1159 /* Prototypes for parsing and freeing functions. */
1161 dump (0, "/* Command parsing functions. */");
1162 dump (0, "static int parse_%s (struct cmd_%s *);",
1163 make_identifier (cmdname), make_identifier (cmdname));
1164 dump (0, "static void free_%s (struct cmd_%s *);",
1165 make_identifier (cmdname), make_identifier (cmdname));
1170 /* Writes out code to initialize all the variables that need
1171 initialization for particular specifier SPEC inside subcommand SBC. */
1173 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1181 st_upper (prefix), find_symbol (spec->def->con)->name);
1184 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1190 for (s = spec->s; s; s = s->next)
1192 if (s->value != VAL_NONE)
1196 assert (s->value == VAL_INT || s->value == VAL_DBL);
1197 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1199 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1205 /* Write code to initialize all variables. */
1207 dump_vars_init (void)
1209 /* Loop through all the subcommands. */
1213 for (sbc = subcommands; sbc; sbc = sbc->next)
1217 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1232 for (spec = sbc->spec; spec; spec = spec->next)
1233 if (spec->s == NULL)
1235 if (sbc->type == SBC_PLAIN)
1236 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1239 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1240 st_lower (sbc->name), st_lower (sbc->name));
1245 dump_specifier_init (spec, sbc);
1250 dump (0, "p->%sn_%s = 0;",
1251 st_lower (sbc->prefix), st_lower (sbc->name));
1252 dump (0, "p->%sv_%s = NULL;",
1253 st_lower (sbc->prefix), st_lower (sbc->name));
1257 dump (0, "p->%sv_%s = NULL;",
1258 st_lower (sbc->prefix), st_lower (sbc->name));
1262 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1267 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1277 /* Return a pointer to a static buffer containing an expression that
1278 will match token T. */
1280 make_match (const char *t)
1290 sprintf (s, "lex_match (T_%s)", t);
1291 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1292 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1293 "|| lex_match_id (\"TRUE\"))");
1294 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1295 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1296 "|| lex_match_id (\"FALSE\"))");
1297 else if (isdigit ((unsigned char) t[0]))
1298 sprintf (s, "lex_match_int (%s)", t);
1300 sprintf (s, "lex_match_id (\"%s\")", t);
1305 /* Write out the parsing code for specifier SPEC within subcommand
1308 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1312 if (spec->omit_kw && spec->omit_kw->next)
1313 error ("Omittable setting is not last setting in `%s' specifier.",
1315 if (spec->omit_kw && spec->omit_kw->parent->next)
1316 error ("Default specifier is not in last specifier in `%s' "
1317 "subcommand.", sbc->name);
1319 for (s = spec->s; s; s = s->next)
1321 int first = spec == sbc->spec && s == spec->s;
1323 /* Match the setting's keyword. */
1324 if (spec->omit_kw == s)
1331 dump (1, "%s;", make_match (s->specname));
1334 dump (1, "%sif (%s)", first ? "" : "else ",
1335 make_match (s->specname));
1337 /* Handle values. */
1338 if (s->value == VAL_NONE)
1339 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1340 st_upper (prefix), find_symbol (s->con)->name);
1343 if (spec->omit_kw != s)
1347 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1348 st_upper (prefix), find_symbol (s->con)->name);
1350 if (s->valtype == VT_PAREN)
1354 dump (1, "if (lex_match ('('))");
1359 dump (1, "if (!lex_match ('('))");
1361 dump (0, "msg (SE, _(\"`(' expected after %s "
1362 "specifier of %s subcommand.\"));",
1363 s->specname, sbc->name);
1364 dump (0, "goto lossage;");
1370 if (s->value == VAL_INT)
1372 dump (1, "if (!lex_integer_p ())");
1374 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1375 "requires an integer argument.\"));",
1376 s->specname, sbc->name);
1377 dump (0, "goto lossage;");
1379 dump (-1, "p->%s%s = lex_integer ();",
1380 sbc->prefix, st_lower (s->valname));
1384 dump (1, "if (token != T_NUM)");
1386 dump (0, "msg (SE, _(\"Number expected after %s "
1387 "specifier of %s subcommand.\"));",
1388 s->specname, sbc->name);
1389 dump (0, "goto lossage;");
1391 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1392 st_lower (s->valname));
1399 str = xmalloc (MAX_TOK_LEN);
1400 str2 = xmalloc (MAX_TOK_LEN);
1401 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1402 sprintf (str, s->restriction, str2, str2, str2, str2,
1403 str2, str2, str2, str2);
1404 dump (1, "if (!(%s))", str);
1410 dump (0, "msg (SE, _(\"Bad argument for %s "
1411 "specifier of %s subcommand.\"));",
1412 s->specname, sbc->name);
1413 dump (0, "goto lossage;");
1418 dump (0, "lex_get ();");
1420 if (s->valtype == VT_PAREN)
1422 dump (1, "if (!lex_match (')'))");
1424 dump (0, "msg (SE, _(\"`)' expected after argument for "
1425 "%s specifier of %s.\"));",
1426 s->specname, sbc->name);
1427 dump (0, "goto lossage;");
1437 if (s != spec->omit_kw)
1441 if (s == spec->omit_kw)
1450 /* Write out the code to parse subcommand SBC. */
1452 dump_subcommand (const subcommand *sbc)
1454 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1458 dump (1, "while (token != '/' && token != '.')");
1464 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1467 dump_specifier_parse (spec, sbc);
1471 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1472 make_match (st_upper (spec->varname)));
1473 if (sbc->type == SBC_PLAIN)
1474 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1477 dump (0, "p->a_%s[%s%s%s] = 1;",
1478 st_lower (sbc->name),
1479 st_upper (prefix), st_upper (sbc->prefix),
1480 st_upper (spec->varname));
1490 /* This code first finds the last specifier in sbc. Then it
1491 finds the last setting within that last specifier. Either
1492 or both might be NULL. */
1505 if (spec && (!spec->s || !spec->omit_kw))
1509 dump (0, "lex_error (NULL);");
1510 dump (0, "goto lossage;");
1516 dump (0, "lex_match (',');");
1520 else if (sbc->type == SBC_VARLIST)
1522 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1524 st_lower (sbc->prefix), st_lower (sbc->name),
1525 st_lower (sbc->prefix), st_lower (sbc->name),
1526 sbc->message ? " |" : "",
1527 sbc->message ? sbc->message : "");
1528 dump (0, "goto lossage;");
1531 else if (sbc->type == SBC_VAR)
1533 dump (0, "p->%sv_%s = parse_variable ();",
1534 st_lower (sbc->prefix), st_lower (sbc->name));
1535 dump (1, "if (p->%sv_%s)",
1536 st_lower (sbc->prefix), st_lower (sbc->name));
1537 dump (0, "goto lossage;");
1540 else if (sbc->type == SBC_STRING)
1542 if (sbc->restriction)
1547 dump (1, "if (!lex_force_string ())");
1548 dump (0, "return 0;");
1550 if (sbc->restriction)
1552 dump (0, "x = ds_length (&tokstr);");
1553 dump (1, "if (!(%s))", sbc->restriction);
1555 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1556 sbc->name, sbc->message);
1557 dump (0, "goto lossage;");
1561 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1562 st_lower (sbc->name));
1563 dump (0, "lex_get ();");
1564 if (sbc->restriction)
1567 else if (sbc->type == SBC_INT)
1569 dump (1, "if (!lex_force_int ())");
1570 dump (0, "goto lossage;");
1571 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1573 else if (sbc->type == SBC_PINT)
1575 dump (0, "lex_match ('(');");
1576 dump (1, "if (!lex_force_int ())");
1577 dump (0, "goto lossage;");
1578 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1579 dump (0, "lex_match (')');");
1581 else if (sbc->type == SBC_CUSTOM)
1583 dump (1, "switch (%scustom_%s (p))",
1584 st_lower (prefix), st_lower (sbc->name));
1586 dump (1, "case 0:");
1587 dump (0, "goto lossage;");
1588 dump (-1, "case 1:");
1591 dump (-1, "case 2:");
1593 dump (0, "lex_error (NULL);");
1594 dump (0, "goto lossage;");
1595 dump (-1, "default:");
1597 dump (0, "assert (0);");
1603 /* Write out entire parser. */
1611 dump (0, "static int");
1612 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1613 make_identifier (cmdname));
1618 dump (1, "for (;;)");
1622 if (def && (def->type == SBC_VARLIST))
1624 if (def->type == SBC_VARLIST)
1625 dump (1, "if (token == T_ID && is_varname (tokid) && "
1626 "lex_look_ahead () != '=')");
1629 dump (0, "if ((token == T_ID && is_varname (tokid) && "
1630 "lex_look_ahead () != '=')");
1631 dump (1, " || token == T_ALL)");
1634 dump (0, "p->sbc_%s++;", st_lower (def->name));
1635 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1637 st_lower (def->prefix), st_lower (def->name),
1638 st_lower (def->prefix), st_lower (def->name));
1639 dump (0, "goto lossage;");
1644 else if (def && def->type == SBC_CUSTOM)
1646 dump (1, "switch (%scustom_%s (p))",
1647 st_lower (prefix), st_lower (def->name));
1649 dump (1, "case 0:");
1650 dump (0, "goto lossage;");
1651 dump (-1, "case 1:");
1653 dump (0, "p->sbc_%s++;", st_lower (def->name));
1654 dump (0, "continue;");
1655 dump (-1, "case 2:");
1658 dump (-1, "default:");
1660 dump (0, "assert (0);");
1668 for (sbc = subcommands; sbc; sbc = sbc->next)
1670 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1674 dump (0, "lex_match ('=');");
1675 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1678 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1680 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1682 dump (0, "goto lossage;");
1686 dump_subcommand (sbc);
1692 dump (1, "if (!lex_match ('/'))");
1697 dump (1, "if (token != '.')");
1699 dump (0, "lex_error (_(\"expecting end of command\"));");
1700 dump (0, "goto lossage;");
1703 dump (-1, "return 1;");
1705 dump (-1, "lossage:");
1707 dump (0, "free_%s (p);", make_identifier (cmdname));
1708 dump (0, "return 0;");
1713 /* Write the output file header. */
1722 curtime = time (NULL);
1723 loctime = localtime (&curtime);
1724 timep = asctime (loctime);
1725 timep[strlen (timep) - 1] = 0;
1726 dump (0, "/* %s", ofn);
1728 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1729 dump (0, " Do not modify!");
1734 /* Write out commands to free variable state. */
1744 for (sbc = subcommands; sbc; sbc = sbc->next)
1745 if (sbc->type == SBC_STRING)
1748 dump (0, "static void");
1749 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1750 make_identifier (cmdname), used ? "" : " unused");
1753 for (sbc = subcommands; sbc; sbc = sbc->next)
1754 if (sbc->type == SBC_STRING)
1755 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1760 /* Returns the name of a directive found on the current input line, if
1761 any, or a null pointer if none found. */
1763 recognize_directive (void)
1765 static char directive[16];
1769 if (strncmp (sp, "/*", 2))
1771 sp = skip_ws (sp + 2);
1776 ep = strchr (sp, ')');
1782 memcpy (directive, sp, ep - sp);
1783 directive[ep - sp] = '\0';
1788 main (int argc, char *argv[])
1792 fail ("Syntax: q2c input.q output.c");
1795 in = fopen (ifn, "r");
1797 fail ("%s: open: %s.", ifn, strerror (errno));
1800 out = fopen (ofn, "w");
1802 fail ("%s: open: %s.", ofn, strerror (errno));
1805 buf = xmalloc (MAX_LINE_LEN);
1806 tokstr = xmalloc (MAX_TOK_LEN);
1811 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1814 const char *directive = recognize_directive ();
1815 if (directive == NULL)
1817 dump (0, "%s", buf);
1821 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1822 if (!strcmp (directive, "specification"))
1824 /* Skip leading slash-star line. */
1830 /* Skip trailing star-slash line. */
1833 else if (!strcmp (directive, "headers"))
1837 dump (0, "#include <assert.h>");
1838 dump (0, "#include <stdlib.h>");
1839 dump (0, "#include \"alloc.h\"");
1840 dump (0, "#include \"error.h\"");
1841 dump (0, "#include \"lexer.h\"");
1842 dump (0, "#include \"str.h\"");
1843 dump (0, "#include \"var.h\"");
1846 else if (!strcmp (directive, "declarations"))
1847 dump_declarations ();
1848 else if (!strcmp (directive, "functions"))
1854 error ("unknown directive `%s'", directive);
1856 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1859 return EXIT_SUCCESS;