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. */
92 const char nullstr[] = "";
95 /* Close all open files and delete the output file, on failure. */
104 if (remove (ofn) == -1)
105 fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
109 void hcf (void) __attribute__ ((noreturn));
112 /* Terminate unsuccessfully. */
121 int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
122 int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
125 /* Output an error message and terminate unsuccessfully. */
127 fail (const char *format, ...)
131 va_start (args, format);
132 fprintf (stderr, "%s: ", pgmname);
133 vfprintf (stderr, format, args);
134 fprintf (stderr, "\n");
140 /* Output a context-dependent error message and terminate
143 error (const char *format,...)
147 va_start (args, format);
148 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
149 vfprintf (stderr, format, args);
150 fprintf (stderr, "\n");
156 #define VME "virtual memory exhausted"
158 /* Allocate a block of SIZE bytes and return a pointer to its
161 xmalloc (size_t size)
171 #if DEBUGGING && __CHECKER__
172 error ("xmalloc(%lu): Inducing segfault.", (unsigned long) size);
175 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
181 /* Resize the block at PTR to size SIZE and return a pointer to the
182 beginning of the new block. */
184 xrealloc (void *ptr, size_t size)
196 vp = realloc (ptr, size);
201 fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
206 /* Make a dynamically allocated copy of string S and return a pointer
207 to the first character. */
209 xstrdup (const char *s)
215 size = strlen (s) + 1;
219 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
225 /* Returns a pointer to one of 8 static buffers. The buffers are used
230 static char b[8][256];
239 /* Copies a string to a static buffer, converting it to lowercase in
240 the process, and returns a pointer to the static buffer. */
242 st_lower (const char *s)
246 p = cp = get_buffer ();
248 *cp++ = tolower ((unsigned char) (*s++));
254 /* Copies a string to a static buffer, converting it to uppercase in
255 the process, and returns a pointer to the static buffer. */
257 st_upper (const char *s)
261 p = cp = get_buffer ();
263 *cp++ = toupper ((unsigned char) (*s++));
269 /* Returns the address of the first non-whitespace character in S, or
270 the address of the null terminator if none. */
272 skip_ws (const char *s)
274 while (isspace ((unsigned char) *s))
279 /* Read one line from the input file into buf. Lines having special
280 formats are handled specially. */
285 if (0 == fgets (buf, MAX_LINE_LEN, in))
288 fail ("%s: fgets: %s", ifn, strerror (errno));
292 cp = strchr (buf, '\n');
300 /* Symbol table manager. */
302 /* Symbol table entry. */
303 typedef struct symbol symbol;
306 symbol *next; /* Next symbol in symbol table. */
307 char *name; /* Symbol name. */
308 int unique; /* 1=Name must be unique in this file. */
309 int ln; /* Line number of definition. */
310 int value; /* Symbol value. */
316 /* Add a symbol to the symbol table having name NAME, uniqueness
317 UNIQUE, and value VALUE. If a symbol having the same name is found
318 in the symbol table, its sequence number is returned and the symbol
319 table is not modified. Otherwise, the symbol is added and the next
320 available sequence number is returned. */
322 add_symbol (const char *name, int unique, int value)
327 sym = xmalloc (sizeof (symbol));
328 sym->name = xstrdup (name);
329 sym->unique = unique;
342 if (!strcmp (iter->name, name))
346 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
348 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
365 /* Finds the symbol having given sequence number X within the symbol
366 table, and returns the associated symbol structure. */
373 while (x > 1 && iter)
383 /* Writes a printable representation of the current token to
391 printf ("STRING\t\"%s\"\n", tokstr);
394 printf ("ID\t%s\n", tokstr);
397 printf ("PUNCT\t%c\n", token);
400 #endif /* DEBUGGING */
402 /* Reads a token from the input file. */
406 /* Skip whitespace and check for end of file. */
414 fail ("%s: Unexpected end of file.", ifn);
417 if (*cp == '_' || isalnum ((unsigned char) *cp))
421 while (*cp == '_' || isalnum ((unsigned char) *cp))
422 *dest++ = toupper ((unsigned char) (*cp++));
430 while (*cp != '"' && *cp)
436 error ("Unterminated string literal.");
444 error ("Unterminated string literal.");
457 /* Force the current token to be an identifier token. */
462 error ("Identifier expected.");
465 /* Force the current token to be a string token. */
469 if (token != T_STRING)
470 error ("String expected.");
473 /* Checks whether the current token is the identifier S; if so, skips
474 the token and returns 1; otherwise, returns 0. */
476 match_id (const char *s)
478 if (token == T_ID && !strcmp (tokstr, s))
486 /* Checks whether the current token is T. If so, skips the token and
487 returns 1; otherwise, returns 0. */
499 /* Force the current token to be T, and skip it. */
504 error ("`%c' expected.", t);
510 /* Some specifiers have associated values. */
513 VAL_NONE, /* No value. */
514 VAL_INT, /* Integer value. */
515 VAL_DBL /* Floating point value. */
518 /* For those specifiers with values, the syntax of those values. */
521 VT_PLAIN, /* Unadorned value. */
522 VT_PAREN /* Value must be enclosed in parentheses. */
525 /* Forward definition. */
526 typedef struct specifier specifier;
528 /* A single setting. */
529 typedef struct setting setting;
532 specifier *parent; /* Owning specifier. */
533 setting *next; /* Next in the chain. */
534 char *specname; /* Name of the setting. */
535 int con; /* Sequence number. */
538 int valtype; /* One of VT_*. */
539 int value; /* One of VAL_*. */
540 int optvalue; /* 1=value is optional, 0=value is required. */
541 char *valname; /* Variable name for the value. */
542 char *restriction; /* !=NULL: expression specifying valid values. */
545 /* A single specifier. */
548 specifier *next; /* Next in the chain. */
549 char *varname; /* Variable name. */
550 setting *s; /* Associated settings. */
552 setting *def; /* Default setting. */
553 setting *omit_kw; /* Setting for which the keyword can be omitted. */
555 int index; /* Next array index. */
558 /* Subcommand types. */
561 SBC_PLAIN, /* The usual case. */
562 SBC_VARLIST, /* Variable list. */
563 SBC_INT, /* Integer value. */
564 SBC_PINT, /* Integer inside parentheses. */
565 SBC_DBL, /* Floating point value. */
566 SBC_INT_LIST, /* List of integers (?). */
567 SBC_DBL_LIST, /* List of floating points (?). */
568 SBC_CUSTOM, /* Custom. */
569 SBC_ARRAY, /* Array of boolean values. */
570 SBC_STRING, /* String value. */
571 SBC_VAR /* Single variable name. */
575 /* A single subcommand. */
576 typedef struct subcommand subcommand;
579 subcommand *next; /* Next in the chain. */
580 char *name; /* Subcommand name. */
581 subcommand_type type; /* One of SBC_*. */
582 int once; /* 1=Subcommand may appear only once. */
583 int narray; /* Index of next array element. */
584 const char *prefix; /* Prefix for variable and constant names. */
585 specifier *spec; /* Array of specifiers. */
587 /* SBC_STRING only. */
588 char *restriction; /* Expression restricting string length. */
589 char *message; /* Error message. */
592 /* Name of the command; i.e., DESCRIPTIVES. */
595 /* Short prefix for the command; i.e., `dsc_'. */
598 /* List of subcommands. */
599 subcommand *subcommands;
601 /* Default subcommand if any, or NULL. */
606 void parse_subcommands (void);
608 /* Parse an entire specification. */
612 /* Get the command name and prefix. */
613 if (token != T_STRING && token != T_ID)
614 error ("Command name expected.");
615 cmdname = xstrdup (tokstr);
619 prefix = xstrdup (tokstr);
624 /* Read all the subcommands. */
627 parse_subcommands ();
630 /* Parses a single setting into S, given subcommand information SBC
631 and specifier information SPEC. */
633 parse_setting (setting *s, specifier *spec)
637 if (match_token ('*'))
640 error ("Cannot have two settings with omittable keywords.");
645 if (match_token ('!'))
648 error ("Cannot have two default settings.");
654 s->specname = xstrdup (tokstr);
655 s->con = add_symbol (s->specname, 0, 0);
660 /* Parse setting value info if necessary. */
661 if (token != '/' && token != ';' && token != '.' && token != ',')
665 s->valtype = VT_PAREN;
669 s->valtype = VT_PLAIN;
671 s->optvalue = match_token ('*');
675 else if (match_id ("D"))
678 error ("`n' or `d' expected.");
683 s->valname = xstrdup (tokstr);
690 s->restriction = xstrdup (tokstr);
694 s->restriction = NULL;
696 if (s->valtype == VT_PAREN)
701 /* Parse a single specifier into SPEC, given subcommand information
704 parse_specifier (specifier *spec, subcommand *sbc)
709 spec->omit_kw = NULL;
710 spec->varname = NULL;
714 spec->varname = xstrdup (st_lower (tokstr));
718 /* Handle array elements. */
721 spec->index = sbc->narray;
722 if (sbc->type == SBC_ARRAY)
734 /* Parse all the settings. */
736 setting **s = &spec->s;
740 *s = xmalloc (sizeof (setting));
741 parse_setting (*s, spec);
742 if (token == ',' || token == ';' || token == '.')
751 /* Parse a list of specifiers for subcommand SBC. */
753 parse_specifiers (subcommand *sbc)
755 specifier **spec = &sbc->spec;
757 if (token == ';' || token == '.')
765 *spec = xmalloc (sizeof (specifier));
766 parse_specifier (*spec, sbc);
767 if (token == ';' || token == '.')
770 spec = &(*spec)->next;
772 (*spec)->next = NULL;
775 /* Parse a subcommand into SBC. */
777 parse_subcommand (subcommand *sbc)
779 if (match_token ('*'))
782 error ("Multiple default subcommands.");
786 sbc->once = match_token ('+');
789 sbc->name = xstrdup (tokstr);
793 sbc->type = SBC_PLAIN;
796 if (match_token ('['))
799 sbc->prefix = xstrdup (st_lower (tokstr));
805 sbc->type = SBC_ARRAY;
806 parse_specifiers (sbc);
810 if (match_token ('('))
813 sbc->prefix = xstrdup (st_lower (tokstr));
823 if (match_id ("VAR"))
825 if (match_id ("VARLIST"))
827 if (match_token ('('))
830 sbc->message = xstrdup (tokstr);
835 else sbc->message = NULL;
837 sbc->type = SBC_VARLIST;
839 else if (match_id ("INTEGER"))
840 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
841 else if (match_id ("PINT"))
842 sbc->type = SBC_PINT;
843 else if (match_id ("DOUBLE"))
844 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
845 else if (match_id ("STRING"))
847 sbc->type = SBC_STRING;
848 if (token == T_STRING)
850 sbc->restriction = xstrdup (tokstr);
853 sbc->message = xstrdup (tokstr);
857 sbc->restriction = NULL;
859 else if (match_id ("CUSTOM"))
860 sbc->type = SBC_CUSTOM;
862 parse_specifiers (sbc);
866 /* Parse all the subcommands. */
868 parse_subcommands (void)
870 subcommand **sbc = &subcommands;
874 *sbc = xmalloc (sizeof (subcommand));
877 parse_subcommand (*sbc);
889 #define BASE_INDENT 2 /* Starting indent. */
890 #define INC_INDENT 2 /* Indent increment. */
892 /* Increment the indent. */
893 #define indent() indent += INC_INDENT
894 #define outdent() indent -= INC_INDENT
896 /* Size of the indent from the left margin. */
900 void dump (int, const char *, ...) __attribute__ ((format (printf, 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 /* For every array subcommand, write out the associated enumerated
1047 for (sbc = subcommands; sbc; sbc = sbc->next)
1048 if (sbc->type == SBC_ARRAY && sbc->narray)
1050 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1058 for (spec = sbc->spec; spec; spec = spec->next)
1060 dump (0, "%s%s%s = %d,",
1061 st_upper (prefix), st_upper (sbc->prefix),
1062 st_upper (spec->varname), spec->index);
1064 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1072 /* Write out structure declaration. */
1076 dump (0, "/* %s structure. */", cmdname);
1077 dump (1, "struct cmd_%s", make_identifier (cmdname));
1079 for (sbc = subcommands; sbc; sbc = sbc->next)
1083 if (sbc != subcommands)
1086 dump (0, "/* %s subcommand. */", sbc->name);
1087 dump (0, "int sbc_%s;", st_lower (sbc->name));
1096 for (spec = sbc->spec; spec; spec = spec->next)
1100 if (sbc->type == SBC_PLAIN)
1101 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1105 dump (0, "int a_%s[%d];",
1106 st_lower (sbc->name), sbc->narray);
1111 dump_specifier_vars (spec, sbc);
1117 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1118 st_lower (sbc->name));
1119 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1120 st_lower (sbc->name));
1124 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1125 st_lower (sbc->name));
1129 dump (0, "char *s_%s;", st_lower (sbc->name));
1134 dump (0, "long n_%s;", st_lower (sbc->name));
1146 /* Write out prototypes for custom_*() functions as necessary. */
1151 for (sbc = subcommands; sbc; sbc = sbc->next)
1152 if (sbc->type == SBC_CUSTOM)
1157 dump (0, "/* Prototype for custom subcommands of %s. */",
1160 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1161 st_lower (prefix), st_lower (sbc->name),
1162 make_identifier (cmdname));
1169 /* Prototypes for parsing and freeing functions. */
1171 dump (0, "/* Command parsing functions. */");
1172 dump (0, "static int parse_%s (struct cmd_%s *);",
1173 make_identifier (cmdname), make_identifier (cmdname));
1174 dump (0, "static void free_%s (struct cmd_%s *);",
1175 make_identifier (cmdname), make_identifier (cmdname));
1180 /* Writes out code to initialize all the variables that need
1181 initialization for particular specifier SPEC inside subcommand SBC. */
1183 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1191 st_upper (prefix), find_symbol (spec->def->con)->name);
1194 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1200 for (s = spec->s; s; s = s->next)
1202 if (s->value != VAL_NONE)
1206 assert (s->value == VAL_INT || s->value == VAL_DBL);
1207 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1209 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1215 /* Write code to initialize all variables. */
1217 dump_vars_init (void)
1219 /* Loop through all the subcommands. */
1223 for (sbc = subcommands; sbc; sbc = sbc->next)
1227 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));
1287 /* Return a pointer to a static buffer containing an expression that
1288 will match token T. */
1290 make_match (const char *t)
1300 sprintf (s, "lex_match (T_%s)", t);
1301 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1302 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1303 "|| lex_match_id (\"TRUE\"))");
1304 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1305 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1306 "|| lex_match_id (\"FALSE\"))");
1307 else if (isdigit ((unsigned char) t[0]))
1308 sprintf (s, "lex_match_int (%s)", t);
1310 sprintf (s, "lex_match_id (\"%s\")", t);
1315 /* Write out the parsing code for specifier SPEC within subcommand
1318 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1322 if (spec->omit_kw && spec->omit_kw->next)
1323 error ("Omittable setting is not last setting in `%s' specifier.",
1325 if (spec->omit_kw && spec->omit_kw->parent->next)
1326 error ("Default specifier is not in last specifier in `%s' "
1327 "subcommand.", sbc->name);
1329 for (s = spec->s; s; s = s->next)
1331 int first = spec == sbc->spec && s == spec->s;
1333 /* Match the setting's keyword. */
1334 if (spec->omit_kw == s)
1341 dump (1, "%s;", make_match (s->specname));
1344 dump (1, "%sif (%s)", first ? "" : "else ",
1345 make_match (s->specname));
1347 /* Handle values. */
1348 if (s->value == VAL_NONE)
1349 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1350 st_upper (prefix), find_symbol (s->con)->name);
1353 if (spec->omit_kw != s)
1357 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1358 st_upper (prefix), find_symbol (s->con)->name);
1360 if (s->valtype == VT_PAREN)
1364 dump (1, "if (lex_match ('('))");
1369 dump (1, "if (!lex_match ('('))");
1371 dump (0, "msg (SE, _(\"`(' expected after %s "
1372 "specifier of %s subcommand.\"));",
1373 s->specname, sbc->name);
1374 dump (0, "goto lossage;");
1380 if (s->value == VAL_INT)
1382 dump (1, "if (!lex_integer_p ())");
1384 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1385 "requires an integer argument.\"));",
1386 s->specname, sbc->name);
1387 dump (0, "goto lossage;");
1389 dump (-1, "p->%s%s = lex_integer ();",
1390 sbc->prefix, st_lower (s->valname));
1394 dump (1, "if (token != T_NUM)");
1396 dump (0, "msg (SE, _(\"Number expected after %s "
1397 "specifier of %s subcommand.\"));",
1398 s->specname, sbc->name);
1399 dump (0, "goto lossage;");
1401 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1402 st_lower (s->valname));
1409 str = xmalloc (MAX_TOK_LEN);
1410 str2 = xmalloc (MAX_TOK_LEN);
1411 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1412 sprintf (str, s->restriction, str2, str2, str2, str2,
1413 str2, str2, str2, str2);
1414 dump (1, "if (!(%s))", str);
1420 dump (0, "msg (SE, _(\"Bad argument for %s "
1421 "specifier of %s subcommand.\"));",
1422 s->specname, sbc->name);
1423 dump (0, "goto lossage;");
1428 dump (0, "lex_get ();");
1430 if (s->valtype == VT_PAREN)
1432 dump (1, "if (!lex_match (')'))");
1434 dump (0, "msg (SE, _(\"`)' expected after argument for "
1435 "%s specifier of %s.\"));",
1436 s->specname, sbc->name);
1437 dump (0, "goto lossage;");
1447 if (s != spec->omit_kw)
1451 if (s == spec->omit_kw)
1460 /* Write out the code to parse subcommand SBC. */
1462 dump_subcommand (const subcommand *sbc)
1464 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1468 dump (1, "while (token != '/' && token != '.')");
1474 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1477 dump_specifier_parse (spec, sbc);
1481 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1482 make_match (st_upper (spec->varname)));
1483 if (sbc->type == SBC_PLAIN)
1484 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1487 dump (0, "p->a_%s[%s%s%s] = 1;",
1488 st_lower (sbc->name),
1489 st_upper (prefix), st_upper (sbc->prefix),
1490 st_upper (spec->varname));
1500 /* This code first finds the last specifier in sbc. Then it
1501 finds the last setting within that last specifier. Either
1502 or both might be NULL. */
1515 if (spec && (!spec->s || !spec->omit_kw))
1519 dump (0, "lex_error (NULL);");
1520 dump (0, "goto lossage;");
1526 dump (0, "lex_match (',');");
1530 else if (sbc->type == SBC_VARLIST)
1532 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1534 st_lower (sbc->prefix), st_lower (sbc->name),
1535 st_lower (sbc->prefix), st_lower (sbc->name),
1536 sbc->message ? " |" : "",
1537 sbc->message ? sbc->message : "");
1538 dump (0, "goto lossage;");
1541 else if (sbc->type == SBC_VAR)
1543 dump (0, "p->%sv_%s = parse_variable ();",
1544 st_lower (sbc->prefix), st_lower (sbc->name));
1545 dump (1, "if (p->%sv_%s)",
1546 st_lower (sbc->prefix), st_lower (sbc->name));
1547 dump (0, "goto lossage;");
1550 else if (sbc->type == SBC_STRING)
1552 if (sbc->restriction)
1557 dump (1, "if (!lex_force_string ())");
1558 dump (0, "return 0;");
1560 if (sbc->restriction)
1562 dump (0, "x = ds_length (&tokstr);");
1563 dump (1, "if (!(%s))", sbc->restriction);
1565 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1566 sbc->name, sbc->message);
1567 dump (0, "goto lossage;");
1571 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1572 st_lower (sbc->name));
1573 dump (0, "lex_get ();");
1574 if (sbc->restriction)
1577 else if (sbc->type == SBC_INT)
1579 dump (1, "if (!lex_force_int ())");
1580 dump (0, "goto lossage;");
1581 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1583 else if (sbc->type == SBC_PINT)
1585 dump (0, "lex_match ('(');");
1586 dump (1, "if (!lex_force_int ())");
1587 dump (0, "goto lossage;");
1588 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1589 dump (0, "lex_match (')');");
1591 else if (sbc->type == SBC_CUSTOM)
1593 dump (1, "switch (%scustom_%s (p))",
1594 st_lower (prefix), st_lower (sbc->name));
1596 dump (1, "case 0:");
1597 dump (0, "goto lossage;");
1598 dump (-1, "case 1:");
1601 dump (-1, "case 2:");
1603 dump (0, "lex_error (NULL);");
1604 dump (0, "goto lossage;");
1605 dump (-1, "default:");
1607 dump (0, "assert (0);");
1613 /* Write out entire parser. */
1621 dump (0, "static int");
1622 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1623 make_identifier (cmdname));
1628 dump (1, "for (;;)");
1632 if (def && (def->type == SBC_VARLIST))
1634 if (def->type == SBC_VARLIST)
1635 dump (1, "if (token == T_ID && is_varname (tokid) && "
1636 "lex_look_ahead () != '=')");
1639 dump (0, "if ((token == T_ID && is_varname (tokid) && "
1640 "lex_look_ahead () != '=')");
1641 dump (1, " || token == T_ALL)");
1644 dump (0, "p->sbc_%s++;", st_lower (def->name));
1645 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1647 st_lower (def->prefix), st_lower (def->name),
1648 st_lower (def->prefix), st_lower (def->name));
1649 dump (0, "goto lossage;");
1654 else if (def && def->type == SBC_CUSTOM)
1656 dump (1, "switch (%scustom_%s (p))",
1657 st_lower (prefix), st_lower (def->name));
1659 dump (1, "case 0:");
1660 dump (0, "goto lossage;");
1661 dump (-1, "case 1:");
1663 dump (0, "p->sbc_%s++;", st_lower (def->name));
1664 dump (0, "continue;");
1665 dump (-1, "case 2:");
1668 dump (-1, "default:");
1670 dump (0, "assert (0);");
1678 for (sbc = subcommands; sbc; sbc = sbc->next)
1680 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1684 dump (0, "lex_match ('=');");
1685 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1688 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1690 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1692 dump (0, "goto lossage;");
1696 dump_subcommand (sbc);
1702 dump (1, "if (!lex_match ('/'))");
1707 dump (1, "if (token != '.')");
1709 dump (0, "lex_error (_(\"expecting end of command\"));");
1710 dump (0, "goto lossage;");
1713 dump (-1, "return 1;");
1715 dump (-1, "lossage:");
1717 dump (0, "free_%s (p);", make_identifier (cmdname));
1718 dump (0, "return 0;");
1723 /* Write the output file header. */
1732 curtime = time (NULL);
1733 loctime = localtime (&curtime);
1734 timep = asctime (loctime);
1735 timep[strlen (timep) - 1] = 0;
1736 dump (0, "/* %s", ofn);
1738 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1739 dump (0, " Do not modify!");
1744 /* Write out commands to free variable state. */
1754 for (sbc = subcommands; sbc; sbc = sbc->next)
1755 if (sbc->type == SBC_STRING)
1758 dump (0, "static void");
1759 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1760 make_identifier (cmdname), used ? "" : " unused");
1763 for (sbc = subcommands; sbc; sbc = sbc->next)
1764 if (sbc->type == SBC_STRING)
1765 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1770 /* Returns the name of a directive found on the current input line, if
1771 any, or a null pointer if none found. */
1773 recognize_directive (void)
1775 static char directive[16];
1779 if (strncmp (sp, "/*", 2))
1781 sp = skip_ws (sp + 2);
1786 ep = strchr (sp, ')');
1792 memcpy (directive, sp, ep - sp);
1793 directive[ep - sp] = '\0';
1798 main (int argc, char *argv[])
1802 fail ("Syntax: q2c input.q output.c");
1805 in = fopen (ifn, "r");
1807 fail ("%s: open: %s.", ifn, strerror (errno));
1810 out = fopen (ofn, "w");
1812 fail ("%s: open: %s.", ofn, strerror (errno));
1815 buf = xmalloc (MAX_LINE_LEN);
1816 tokstr = xmalloc (MAX_TOK_LEN);
1821 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1824 const char *directive = recognize_directive ();
1825 if (directive == NULL)
1827 dump (0, "%s", buf);
1831 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1832 if (!strcmp (directive, "specification"))
1834 /* Skip leading slash-star line. */
1840 /* Skip trailing star-slash line. */
1843 else if (!strcmp (directive, "headers"))
1847 dump (0, "#include <assert.h>");
1848 dump (0, "#include <stdlib.h>");
1849 dump (0, "#include \"alloc.h\"");
1850 dump (0, "#include \"error.h\"");
1851 dump (0, "#include \"lexer.h\"");
1852 dump (0, "#include \"str.h\"");
1853 dump (0, "#include \"var.h\"");
1856 else if (!strcmp (directive, "declarations"))
1857 dump_declarations ();
1858 else if (!strcmp (directive, "functions"))
1864 error ("unknown directive `%s'", directive);
1866 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1869 return EXIT_SUCCESS;