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)
167 #if DEBUGGING && __CHECKER__
168 error ("xmalloc(%lu): Inducing segfault.", (unsigned long) size);
171 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
177 /* Resize the block at PTR to size SIZE and return a pointer to the
178 beginning of the new block. */
180 xrealloc (void *ptr, size_t size)
192 vp = realloc (ptr, size);
197 fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
202 /* Make a dynamically allocated copy of string S and return a pointer
203 to the first character. */
205 xstrdup (const char *s)
211 size = strlen (s) + 1;
215 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
221 /* Returns a pointer to one of 8 static buffers. The buffers are used
226 static char b[8][256];
235 /* Copies a string to a static buffer, converting it to lowercase in
236 the process, and returns a pointer to the static buffer. */
238 st_lower (const char *s)
242 p = cp = get_buffer ();
244 *cp++ = tolower ((unsigned char) (*s++));
250 /* Copies a string to a static buffer, converting it to uppercase in
251 the process, and returns a pointer to the static buffer. */
253 st_upper (const char *s)
257 p = cp = get_buffer ();
259 *cp++ = toupper ((unsigned char) (*s++));
265 /* Returns the address of the first non-whitespace character in S, or
266 the address of the null terminator if none. */
268 skip_ws (const char *s)
270 while (isspace ((unsigned char) *s))
275 /* Read one line from the input file into buf. Lines having special
276 formats are handled specially. */
281 if (0 == fgets (buf, MAX_LINE_LEN, in))
284 fail ("%s: fgets: %s", ifn, strerror (errno));
288 cp = strchr (buf, '\n');
296 /* Symbol table manager. */
298 /* Symbol table entry. */
299 typedef struct symbol symbol;
302 symbol *next; /* Next symbol in symbol table. */
303 char *name; /* Symbol name. */
304 int unique; /* 1=Name must be unique in this file. */
305 int ln; /* Line number of definition. */
306 int value; /* Symbol value. */
312 /* Add a symbol to the symbol table having name NAME, uniqueness
313 UNIQUE, and value VALUE. If a symbol having the same name is found
314 in the symbol table, its sequence number is returned and the symbol
315 table is not modified. Otherwise, the symbol is added and the next
316 available sequence number is returned. */
318 add_symbol (const char *name, int unique, int value)
323 sym = xmalloc (sizeof (symbol));
324 sym->name = xstrdup (name);
325 sym->unique = unique;
338 if (!strcmp (iter->name, name))
342 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
344 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
361 /* Finds the symbol having given sequence number X within the symbol
362 table, and returns the associated symbol structure. */
369 while (x > 1 && iter)
379 /* Writes a printable representation of the current token to
387 printf ("STRING\t\"%s\"\n", tokstr);
390 printf ("ID\t%s\n", tokstr);
393 printf ("PUNCT\t%c\n", token);
396 #endif /* DEBUGGING */
398 /* Reads a token from the input file. */
402 /* Skip whitespace and check for end of file. */
410 fail ("%s: Unexpected end of file.", ifn);
413 if (*cp == '_' || isalnum ((unsigned char) *cp))
417 while (*cp == '_' || isalnum ((unsigned char) *cp))
418 *dest++ = toupper ((unsigned char) (*cp++));
426 while (*cp != '"' && *cp)
432 error ("Unterminated string literal.");
440 error ("Unterminated string literal.");
453 /* Force the current token to be an identifier token. */
458 error ("Identifier expected.");
461 /* Force the current token to be a string token. */
465 if (token != T_STRING)
466 error ("String expected.");
469 /* Checks whether the current token is the identifier S; if so, skips
470 the token and returns 1; otherwise, returns 0. */
472 match_id (const char *s)
474 if (token == T_ID && !strcmp (tokstr, s))
482 /* Checks whether the current token is T. If so, skips the token and
483 returns 1; otherwise, returns 0. */
495 /* Force the current token to be T, and skip it. */
500 error ("`%c' expected.", t);
506 /* Some specifiers have associated values. */
509 VAL_NONE, /* No value. */
510 VAL_INT, /* Integer value. */
511 VAL_DBL /* Floating point value. */
514 /* For those specifiers with values, the syntax of those values. */
517 VT_PLAIN, /* Unadorned value. */
518 VT_PAREN /* Value must be enclosed in parentheses. */
521 /* Forward definition. */
522 typedef struct specifier specifier;
524 /* A single setting. */
525 typedef struct setting setting;
528 specifier *parent; /* Owning specifier. */
529 setting *next; /* Next in the chain. */
530 char *specname; /* Name of the setting. */
531 int con; /* Sequence number. */
534 int valtype; /* One of VT_*. */
535 int value; /* One of VAL_*. */
536 int optvalue; /* 1=value is optional, 0=value is required. */
537 char *valname; /* Variable name for the value. */
538 char *restriction; /* !=NULL: expression specifying valid values. */
541 /* A single specifier. */
544 specifier *next; /* Next in the chain. */
545 char *varname; /* Variable name. */
546 setting *s; /* Associated settings. */
548 setting *def; /* Default setting. */
549 setting *omit_kw; /* Setting for which the keyword can be omitted. */
551 int index; /* Next array index. */
554 /* Subcommand types. */
557 SBC_PLAIN, /* The usual case. */
558 SBC_VARLIST, /* Variable list. */
559 SBC_INT, /* Integer value. */
560 SBC_PINT, /* Integer inside parentheses. */
561 SBC_DBL, /* Floating point value. */
562 SBC_INT_LIST, /* List of integers (?). */
563 SBC_DBL_LIST, /* List of floating points (?). */
564 SBC_CUSTOM, /* Custom. */
565 SBC_ARRAY, /* Array of boolean values. */
566 SBC_STRING, /* String value. */
567 SBC_VAR /* Single variable name. */
571 /* A single subcommand. */
572 typedef struct subcommand subcommand;
575 subcommand *next; /* Next in the chain. */
576 char *name; /* Subcommand name. */
577 subcommand_type type; /* One of SBC_*. */
578 int once; /* 1=Subcommand may appear only once. */
579 int narray; /* Index of next array element. */
580 const char *prefix; /* Prefix for variable and constant names. */
581 specifier *spec; /* Array of specifiers. */
583 /* SBC_STRING only. */
584 char *restriction; /* Expression restricting string length. */
585 char *message; /* Error message. */
588 /* Name of the command; i.e., DESCRIPTIVES. */
591 /* Short prefix for the command; i.e., `dsc_'. */
594 /* List of subcommands. */
595 subcommand *subcommands;
597 /* Default subcommand if any, or NULL. */
602 void parse_subcommands (void);
604 /* Parse an entire specification. */
608 /* Get the command name and prefix. */
609 if (token != T_STRING && token != T_ID)
610 error ("Command name expected.");
611 cmdname = xstrdup (tokstr);
615 prefix = xstrdup (tokstr);
620 /* Read all the subcommands. */
623 parse_subcommands ();
626 /* Parses a single setting into S, given subcommand information SBC
627 and specifier information SPEC. */
629 parse_setting (setting *s, specifier *spec)
633 if (match_token ('*'))
636 error ("Cannot have two settings with omittable keywords.");
641 if (match_token ('!'))
644 error ("Cannot have two default settings.");
650 s->specname = xstrdup (tokstr);
651 s->con = add_symbol (s->specname, 0, 0);
656 /* Parse setting value info if necessary. */
657 if (token != '/' && token != ';' && token != '.' && token != ',')
661 s->valtype = VT_PAREN;
665 s->valtype = VT_PLAIN;
667 s->optvalue = match_token ('*');
671 else if (match_id ("D"))
674 error ("`n' or `d' expected.");
679 s->valname = xstrdup (tokstr);
686 s->restriction = xstrdup (tokstr);
690 s->restriction = NULL;
692 if (s->valtype == VT_PAREN)
697 /* Parse a single specifier into SPEC, given subcommand information
700 parse_specifier (specifier *spec, subcommand *sbc)
705 spec->omit_kw = NULL;
706 spec->varname = NULL;
710 spec->varname = xstrdup (st_lower (tokstr));
714 /* Handle array elements. */
717 spec->index = sbc->narray;
718 if (sbc->type == SBC_ARRAY)
730 /* Parse all the settings. */
732 setting **s = &spec->s;
736 *s = xmalloc (sizeof (setting));
737 parse_setting (*s, spec);
738 if (token == ',' || token == ';' || token == '.')
747 /* Parse a list of specifiers for subcommand SBC. */
749 parse_specifiers (subcommand *sbc)
751 specifier **spec = &sbc->spec;
753 if (token == ';' || token == '.')
761 *spec = xmalloc (sizeof (specifier));
762 parse_specifier (*spec, sbc);
763 if (token == ';' || token == '.')
766 spec = &(*spec)->next;
768 (*spec)->next = NULL;
771 /* Parse a subcommand into SBC. */
773 parse_subcommand (subcommand *sbc)
775 if (match_token ('*'))
778 error ("Multiple default subcommands.");
782 sbc->once = match_token ('+');
785 sbc->name = xstrdup (tokstr);
789 sbc->type = SBC_PLAIN;
792 if (match_token ('['))
795 sbc->prefix = xstrdup (st_lower (tokstr));
801 sbc->type = SBC_ARRAY;
802 parse_specifiers (sbc);
806 if (match_token ('('))
809 sbc->prefix = xstrdup (st_lower (tokstr));
819 if (match_id ("VAR"))
821 if (match_id ("VARLIST"))
823 if (match_token ('('))
826 sbc->message = xstrdup (tokstr);
831 else sbc->message = NULL;
833 sbc->type = SBC_VARLIST;
835 else if (match_id ("INTEGER"))
836 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
837 else if (match_id ("PINT"))
838 sbc->type = SBC_PINT;
839 else if (match_id ("DOUBLE"))
840 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
841 else if (match_id ("STRING"))
843 sbc->type = SBC_STRING;
844 if (token == T_STRING)
846 sbc->restriction = xstrdup (tokstr);
849 sbc->message = xstrdup (tokstr);
853 sbc->restriction = NULL;
855 else if (match_id ("CUSTOM"))
856 sbc->type = SBC_CUSTOM;
858 parse_specifiers (sbc);
862 /* Parse all the subcommands. */
864 parse_subcommands (void)
866 subcommand **sbc = &subcommands;
870 *sbc = xmalloc (sizeof (subcommand));
873 parse_subcommand (*sbc);
885 #define BASE_INDENT 2 /* Starting indent. */
886 #define INC_INDENT 2 /* Indent increment. */
888 /* Increment the indent. */
889 #define indent() indent += INC_INDENT
890 #define outdent() indent -= INC_INDENT
892 /* Size of the indent from the left margin. */
896 void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
899 /* Write line FORMAT to the output file, formatted as with printf,
900 indented `indent' characters from the left margin. If INDENTION is
901 greater than 0, indents BASE_INDENT * INDENTION characters after
902 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
903 * INDENTION characters _before_ writing the line. */
905 dump (int indention, const char *format, ...)
911 indent += BASE_INDENT * indention;
914 va_start (args, format);
915 for (i = 0; i < indent; i++)
917 vfprintf (out, format, args);
922 indent += BASE_INDENT * indention;
925 /* Write the structure members for specifier SPEC to the output file.
926 SBC is the including subcommand. */
928 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
931 dump (0, "long %s%s;", sbc->prefix, spec->varname);
936 for (s = spec->s; s; s = s->next)
938 if (s->value != VAL_NONE)
940 const char *typename;
942 assert (s->value == VAL_INT || s->value == VAL_DBL);
943 typename = s->value == VAL_INT ? "long" : "double";
945 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
951 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
953 is_keyword (const char *t)
955 static const char *kw[] =
957 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
958 "NE", "ALL", "BY", "TO", "WITH", 0,
962 for (cp = kw; *cp; cp++)
963 if (!strcmp (t, *cp))
968 /* Transforms a string NAME into a valid C identifier: makes
969 everything lowercase and maps nonalphabetic characters to
970 underscores. Returns a pointer to a static buffer. */
972 make_identifier (const char *name)
974 char *p = get_buffer ();
977 for (cp = p; *name; name++)
978 if (isalpha ((unsigned char) *name))
979 *cp++ = tolower ((unsigned char) (*name));
987 /* Writes the struct and enum declarations for the parser. */
989 dump_declarations (void)
993 /* Write out enums for all the identifiers in the symbol table. */
999 /* Note the squirmings necessary to make sure that the last enum
1000 is not followed by a comma, as mandated by ANSI C89. */
1001 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1002 if (!sym->unique && !is_keyword (sym->name))
1006 dump (0, "/* Settings for subcommand specifiers. */");
1013 buf = xmalloc (1024);
1018 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1022 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1027 buf[strlen (buf) - 1] = 0;
1038 /* For every array subcommand, write out the associated enumerated
1043 for (sbc = subcommands; sbc; sbc = sbc->next)
1044 if (sbc->type == SBC_ARRAY && sbc->narray)
1046 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1054 for (spec = sbc->spec; spec; spec = spec->next)
1056 dump (0, "%s%s%s = %d,",
1057 st_upper (prefix), st_upper (sbc->prefix),
1058 st_upper (spec->varname), spec->index);
1060 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1068 /* Write out structure declaration. */
1072 dump (0, "/* %s structure. */", cmdname);
1073 dump (1, "struct cmd_%s", make_identifier (cmdname));
1075 for (sbc = subcommands; sbc; sbc = sbc->next)
1079 if (sbc != subcommands)
1082 dump (0, "/* %s subcommand. */", sbc->name);
1083 dump (0, "int sbc_%s;", st_lower (sbc->name));
1092 for (spec = sbc->spec; spec; spec = spec->next)
1096 if (sbc->type == SBC_PLAIN)
1097 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1101 dump (0, "int a_%s[%d];",
1102 st_lower (sbc->name), sbc->narray);
1107 dump_specifier_vars (spec, sbc);
1113 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1114 st_lower (sbc->name));
1115 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1116 st_lower (sbc->name));
1120 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1121 st_lower (sbc->name));
1125 dump (0, "char *s_%s;", st_lower (sbc->name));
1130 dump (0, "long n_%s;", st_lower (sbc->name));
1142 /* Write out prototypes for custom_*() functions as necessary. */
1147 for (sbc = subcommands; sbc; sbc = sbc->next)
1148 if (sbc->type == SBC_CUSTOM)
1153 dump (0, "/* Prototype for custom subcommands of %s. */",
1156 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1157 st_lower (prefix), st_lower (sbc->name),
1158 make_identifier (cmdname));
1165 /* Prototypes for parsing and freeing functions. */
1167 dump (0, "/* Command parsing functions. */");
1168 dump (0, "static int parse_%s (struct cmd_%s *);",
1169 make_identifier (cmdname), make_identifier (cmdname));
1170 dump (0, "static void free_%s (struct cmd_%s *);",
1171 make_identifier (cmdname), make_identifier (cmdname));
1176 /* Writes out code to initialize all the variables that need
1177 initialization for particular specifier SPEC inside subcommand SBC. */
1179 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1187 st_upper (prefix), find_symbol (spec->def->con)->name);
1190 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1196 for (s = spec->s; s; s = s->next)
1198 if (s->value != VAL_NONE)
1202 assert (s->value == VAL_INT || s->value == VAL_DBL);
1203 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1205 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1211 /* Write code to initialize all variables. */
1213 dump_vars_init (void)
1215 /* Loop through all the subcommands. */
1219 for (sbc = subcommands; sbc; sbc = sbc->next)
1223 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1238 for (spec = sbc->spec; spec; spec = spec->next)
1239 if (spec->s == NULL)
1241 if (sbc->type == SBC_PLAIN)
1242 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1245 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1246 st_lower (sbc->name), st_lower (sbc->name));
1251 dump_specifier_init (spec, sbc);
1256 dump (0, "p->%sn_%s = 0;",
1257 st_lower (sbc->prefix), st_lower (sbc->name));
1258 dump (0, "p->%sv_%s = NULL;",
1259 st_lower (sbc->prefix), st_lower (sbc->name));
1263 dump (0, "p->%sv_%s = NULL;",
1264 st_lower (sbc->prefix), st_lower (sbc->name));
1268 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1273 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1283 /* Return a pointer to a static buffer containing an expression that
1284 will match token T. */
1286 make_match (const char *t)
1296 sprintf (s, "lex_match (T_%s)", t);
1297 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1298 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1299 "|| lex_match_id (\"TRUE\"))");
1300 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1301 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1302 "|| lex_match_id (\"FALSE\"))");
1303 else if (isdigit ((unsigned char) t[0]))
1304 sprintf (s, "lex_match_int (%s)", t);
1306 sprintf (s, "lex_match_id (\"%s\")", t);
1311 /* Write out the parsing code for specifier SPEC within subcommand
1314 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1318 if (spec->omit_kw && spec->omit_kw->next)
1319 error ("Omittable setting is not last setting in `%s' specifier.",
1321 if (spec->omit_kw && spec->omit_kw->parent->next)
1322 error ("Default specifier is not in last specifier in `%s' "
1323 "subcommand.", sbc->name);
1325 for (s = spec->s; s; s = s->next)
1327 int first = spec == sbc->spec && s == spec->s;
1329 /* Match the setting's keyword. */
1330 if (spec->omit_kw == s)
1337 dump (1, "%s;", make_match (s->specname));
1340 dump (1, "%sif (%s)", first ? "" : "else ",
1341 make_match (s->specname));
1343 /* Handle values. */
1344 if (s->value == VAL_NONE)
1345 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1346 st_upper (prefix), find_symbol (s->con)->name);
1349 if (spec->omit_kw != s)
1353 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1354 st_upper (prefix), find_symbol (s->con)->name);
1356 if (s->valtype == VT_PAREN)
1360 dump (1, "if (lex_match ('('))");
1365 dump (1, "if (!lex_match ('('))");
1367 dump (0, "msg (SE, _(\"`(' expected after %s "
1368 "specifier of %s subcommand.\"));",
1369 s->specname, sbc->name);
1370 dump (0, "goto lossage;");
1376 if (s->value == VAL_INT)
1378 dump (1, "if (!lex_integer_p ())");
1380 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1381 "requires an integer argument.\"));",
1382 s->specname, sbc->name);
1383 dump (0, "goto lossage;");
1385 dump (-1, "p->%s%s = lex_integer ();",
1386 sbc->prefix, st_lower (s->valname));
1390 dump (1, "if (token != T_NUM)");
1392 dump (0, "msg (SE, _(\"Number expected after %s "
1393 "specifier of %s subcommand.\"));",
1394 s->specname, sbc->name);
1395 dump (0, "goto lossage;");
1397 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1398 st_lower (s->valname));
1405 str = xmalloc (MAX_TOK_LEN);
1406 str2 = xmalloc (MAX_TOK_LEN);
1407 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1408 sprintf (str, s->restriction, str2, str2, str2, str2,
1409 str2, str2, str2, str2);
1410 dump (1, "if (!(%s))", str);
1416 dump (0, "msg (SE, _(\"Bad argument for %s "
1417 "specifier of %s subcommand.\"));",
1418 s->specname, sbc->name);
1419 dump (0, "goto lossage;");
1424 dump (0, "lex_get ();");
1426 if (s->valtype == VT_PAREN)
1428 dump (1, "if (!lex_match (')'))");
1430 dump (0, "msg (SE, _(\"`)' expected after argument for "
1431 "%s specifier of %s.\"));",
1432 s->specname, sbc->name);
1433 dump (0, "goto lossage;");
1443 if (s != spec->omit_kw)
1447 if (s == spec->omit_kw)
1456 /* Write out the code to parse subcommand SBC. */
1458 dump_subcommand (const subcommand *sbc)
1460 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1464 dump (1, "while (token != '/' && token != '.')");
1470 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1473 dump_specifier_parse (spec, sbc);
1477 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1478 make_match (st_upper (spec->varname)));
1479 if (sbc->type == SBC_PLAIN)
1480 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1483 dump (0, "p->a_%s[%s%s%s] = 1;",
1484 st_lower (sbc->name),
1485 st_upper (prefix), st_upper (sbc->prefix),
1486 st_upper (spec->varname));
1496 /* This code first finds the last specifier in sbc. Then it
1497 finds the last setting within that last specifier. Either
1498 or both might be NULL. */
1511 if (spec && (!spec->s || !spec->omit_kw))
1515 dump (0, "lex_error (NULL);");
1516 dump (0, "goto lossage;");
1522 dump (0, "lex_match (',');");
1526 else if (sbc->type == SBC_VARLIST)
1528 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1530 st_lower (sbc->prefix), st_lower (sbc->name),
1531 st_lower (sbc->prefix), st_lower (sbc->name),
1532 sbc->message ? " |" : "",
1533 sbc->message ? sbc->message : "");
1534 dump (0, "goto lossage;");
1537 else if (sbc->type == SBC_VAR)
1539 dump (0, "p->%sv_%s = parse_variable ();",
1540 st_lower (sbc->prefix), st_lower (sbc->name));
1541 dump (1, "if (p->%sv_%s)",
1542 st_lower (sbc->prefix), st_lower (sbc->name));
1543 dump (0, "goto lossage;");
1546 else if (sbc->type == SBC_STRING)
1548 if (sbc->restriction)
1553 dump (1, "if (!lex_force_string ())");
1554 dump (0, "return 0;");
1556 if (sbc->restriction)
1558 dump (0, "x = ds_length (&tokstr);");
1559 dump (1, "if (!(%s))", sbc->restriction);
1561 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1562 sbc->name, sbc->message);
1563 dump (0, "goto lossage;");
1567 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1568 st_lower (sbc->name));
1569 dump (0, "lex_get ();");
1570 if (sbc->restriction)
1573 else if (sbc->type == SBC_INT)
1575 dump (1, "if (!lex_force_int ())");
1576 dump (0, "goto lossage;");
1577 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1579 else if (sbc->type == SBC_PINT)
1581 dump (0, "lex_match ('(');");
1582 dump (1, "if (!lex_force_int ())");
1583 dump (0, "goto lossage;");
1584 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1585 dump (0, "lex_match (')');");
1587 else if (sbc->type == SBC_CUSTOM)
1589 dump (1, "switch (%scustom_%s (p))",
1590 st_lower (prefix), st_lower (sbc->name));
1592 dump (1, "case 0:");
1593 dump (0, "goto lossage;");
1594 dump (-1, "case 1:");
1597 dump (-1, "case 2:");
1599 dump (0, "lex_error (NULL);");
1600 dump (0, "goto lossage;");
1601 dump (-1, "default:");
1603 dump (0, "assert (0);");
1609 /* Write out entire parser. */
1617 dump (0, "static int");
1618 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1619 make_identifier (cmdname));
1624 dump (1, "for (;;)");
1628 if (def && (def->type == SBC_VARLIST))
1630 if (def->type == SBC_VARLIST)
1631 dump (1, "if (token == T_ID && is_varname (tokid) && "
1632 "lex_look_ahead () != '=')");
1635 dump (0, "if ((token == T_ID && is_varname (tokid) && "
1636 "lex_look_ahead () != '=')");
1637 dump (1, " || token == T_ALL)");
1640 dump (0, "p->sbc_%s++;", st_lower (def->name));
1641 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1643 st_lower (def->prefix), st_lower (def->name),
1644 st_lower (def->prefix), st_lower (def->name));
1645 dump (0, "goto lossage;");
1650 else if (def && def->type == SBC_CUSTOM)
1652 dump (1, "switch (%scustom_%s (p))",
1653 st_lower (prefix), st_lower (def->name));
1655 dump (1, "case 0:");
1656 dump (0, "goto lossage;");
1657 dump (-1, "case 1:");
1659 dump (0, "p->sbc_%s++;", st_lower (def->name));
1660 dump (0, "continue;");
1661 dump (-1, "case 2:");
1664 dump (-1, "default:");
1666 dump (0, "assert (0);");
1674 for (sbc = subcommands; sbc; sbc = sbc->next)
1676 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1680 dump (0, "lex_match ('=');");
1681 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1684 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1686 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1688 dump (0, "goto lossage;");
1692 dump_subcommand (sbc);
1698 dump (1, "if (!lex_match ('/'))");
1703 dump (1, "if (token != '.')");
1705 dump (0, "lex_error (_(\"expecting end of command\"));");
1706 dump (0, "goto lossage;");
1709 dump (-1, "return 1;");
1711 dump (-1, "lossage:");
1713 dump (0, "free_%s (p);", make_identifier (cmdname));
1714 dump (0, "return 0;");
1719 /* Write the output file header. */
1728 curtime = time (NULL);
1729 loctime = localtime (&curtime);
1730 timep = asctime (loctime);
1731 timep[strlen (timep) - 1] = 0;
1732 dump (0, "/* %s", ofn);
1734 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1735 dump (0, " Do not modify!");
1740 /* Write out commands to free variable state. */
1750 for (sbc = subcommands; sbc; sbc = sbc->next)
1751 if (sbc->type == SBC_STRING)
1754 dump (0, "static void");
1755 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1756 make_identifier (cmdname), used ? "" : " unused");
1759 for (sbc = subcommands; sbc; sbc = sbc->next)
1760 if (sbc->type == SBC_STRING)
1761 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1766 /* Returns the name of a directive found on the current input line, if
1767 any, or a null pointer if none found. */
1769 recognize_directive (void)
1771 static char directive[16];
1775 if (strncmp (sp, "/*", 2))
1777 sp = skip_ws (sp + 2);
1782 ep = strchr (sp, ')');
1788 memcpy (directive, sp, ep - sp);
1789 directive[ep - sp] = '\0';
1794 main (int argc, char *argv[])
1798 fail ("Syntax: q2c input.q output.c");
1801 in = fopen (ifn, "r");
1803 fail ("%s: open: %s.", ifn, strerror (errno));
1806 out = fopen (ofn, "w");
1808 fail ("%s: open: %s.", ofn, strerror (errno));
1811 buf = xmalloc (MAX_LINE_LEN);
1812 tokstr = xmalloc (MAX_TOK_LEN);
1817 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1820 const char *directive = recognize_directive ();
1821 if (directive == NULL)
1823 dump (0, "%s", buf);
1827 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1828 if (!strcmp (directive, "specification"))
1830 /* Skip leading slash-star line. */
1836 /* Skip trailing star-slash line. */
1839 else if (!strcmp (directive, "headers"))
1843 dump (0, "#include <assert.h>");
1844 dump (0, "#include <stdlib.h>");
1845 dump (0, "#include \"alloc.h\"");
1846 dump (0, "#include \"error.h\"");
1847 dump (0, "#include \"lexer.h\"");
1848 dump (0, "#include \"str.h\"");
1849 dump (0, "#include \"var.h\"");
1852 else if (!strcmp (directive, "declarations"))
1853 dump_declarations ();
1854 else if (!strcmp (directive, "functions"))
1860 error ("unknown directive `%s'", directive);
1862 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1865 return EXIT_SUCCESS;