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));
102 void hcf (void) NO_RETURN;
104 /* Terminate unsuccessfully. */
112 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
113 int error (const char *, ...) PRINTF_FORMAT (1, 2);
115 /* Output an error message and terminate unsuccessfully. */
117 fail (const char *format, ...)
121 va_start (args, format);
122 fprintf (stderr, "%s: ", pgmname);
123 vfprintf (stderr, format, args);
124 fprintf (stderr, "\n");
130 /* Output a context-dependent error message and terminate
133 error (const char *format,...)
137 va_start (args, format);
138 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
139 vfprintf (stderr, format, args);
140 fprintf (stderr, "\n");
146 #define VME "virtual memory exhausted"
148 /* Allocate a block of SIZE bytes and return a pointer to its
151 xmalloc (size_t size)
160 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
165 /* Make a dynamically allocated copy of string S and return a pointer
166 to the first character. */
168 xstrdup (const char *s)
174 size = strlen (s) + 1;
178 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
184 /* Returns a pointer to one of 8 static buffers. The buffers are used
189 static char b[8][256];
198 /* Copies a string to a static buffer, converting it to lowercase in
199 the process, and returns a pointer to the static buffer. */
201 st_lower (const char *s)
205 p = cp = get_buffer ();
207 *cp++ = tolower ((unsigned char) (*s++));
213 /* Copies a string to a static buffer, converting it to uppercase in
214 the process, and returns a pointer to the static buffer. */
216 st_upper (const char *s)
220 p = cp = get_buffer ();
222 *cp++ = toupper ((unsigned char) (*s++));
228 /* Returns the address of the first non-whitespace character in S, or
229 the address of the null terminator if none. */
231 skip_ws (const char *s)
233 while (isspace ((unsigned char) *s))
238 /* Read one line from the input file into buf. Lines having special
239 formats are handled specially. */
244 if (0 == fgets (buf, MAX_LINE_LEN, in))
247 fail ("%s: fgets: %s", ifn, strerror (errno));
251 cp = strchr (buf, '\n');
259 /* Symbol table manager. */
261 /* Symbol table entry. */
262 typedef struct symbol symbol;
265 symbol *next; /* Next symbol in symbol table. */
266 char *name; /* Symbol name. */
267 int unique; /* 1=Name must be unique in this file. */
268 int ln; /* Line number of definition. */
269 int value; /* Symbol value. */
275 /* Add a symbol to the symbol table having name NAME, uniqueness
276 UNIQUE, and value VALUE. If a symbol having the same name is found
277 in the symbol table, its sequence number is returned and the symbol
278 table is not modified. Otherwise, the symbol is added and the next
279 available sequence number is returned. */
281 add_symbol (const char *name, int unique, int value)
286 sym = xmalloc (sizeof (symbol));
287 sym->name = xstrdup (name);
288 sym->unique = unique;
301 if (!strcmp (iter->name, name))
305 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
307 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
324 /* Finds the symbol having given sequence number X within the symbol
325 table, and returns the associated symbol structure. */
332 while (x > 1 && iter)
342 /* Writes a printable representation of the current token to
350 printf ("STRING\t\"%s\"\n", tokstr);
353 printf ("ID\t%s\n", tokstr);
356 printf ("PUNCT\t%c\n", token);
359 #endif /* DEBUGGING */
361 /* Reads a token from the input file. */
365 /* Skip whitespace and check for end of file. */
373 fail ("%s: Unexpected end of file.", ifn);
376 if (*cp == '_' || isalnum ((unsigned char) *cp))
380 while (*cp == '_' || isalnum ((unsigned char) *cp))
381 *dest++ = toupper ((unsigned char) (*cp++));
389 while (*cp != '"' && *cp)
395 error ("Unterminated string literal.");
403 error ("Unterminated string literal.");
416 /* Force the current token to be an identifier token. */
421 error ("Identifier expected.");
424 /* Force the current token to be a string token. */
428 if (token != T_STRING)
429 error ("String expected.");
432 /* Checks whether the current token is the identifier S; if so, skips
433 the token and returns 1; otherwise, returns 0. */
435 match_id (const char *s)
437 if (token == T_ID && !strcmp (tokstr, s))
445 /* Checks whether the current token is T. If so, skips the token and
446 returns 1; otherwise, returns 0. */
458 /* Force the current token to be T, and skip it. */
463 error ("`%c' expected.", t);
469 /* Some specifiers have associated values. */
472 VAL_NONE, /* No value. */
473 VAL_INT, /* Integer value. */
474 VAL_DBL /* Floating point value. */
477 /* For those specifiers with values, the syntax of those values. */
480 VT_PLAIN, /* Unadorned value. */
481 VT_PAREN /* Value must be enclosed in parentheses. */
484 /* Forward definition. */
485 typedef struct specifier specifier;
487 /* A single setting. */
488 typedef struct setting setting;
491 specifier *parent; /* Owning specifier. */
492 setting *next; /* Next in the chain. */
493 char *specname; /* Name of the setting. */
494 int con; /* Sequence number. */
497 int valtype; /* One of VT_*. */
498 int value; /* One of VAL_*. */
499 int optvalue; /* 1=value is optional, 0=value is required. */
500 char *valname; /* Variable name for the value. */
501 char *restriction; /* !=NULL: expression specifying valid values. */
504 /* A single specifier. */
507 specifier *next; /* Next in the chain. */
508 char *varname; /* Variable name. */
509 setting *s; /* Associated settings. */
511 setting *def; /* Default setting. */
512 setting *omit_kw; /* Setting for which the keyword can be omitted. */
514 int index; /* Next array index. */
517 /* Subcommand types. */
520 SBC_PLAIN, /* The usual case. */
521 SBC_VARLIST, /* Variable list. */
522 SBC_INT, /* Integer value. */
523 SBC_PINT, /* Integer inside parentheses. */
524 SBC_DBL, /* Floating point value. */
525 SBC_INT_LIST, /* List of integers (?). */
526 SBC_DBL_LIST, /* List of floating points (?). */
527 SBC_CUSTOM, /* Custom. */
528 SBC_ARRAY, /* Array of boolean values. */
529 SBC_STRING, /* String value. */
530 SBC_VAR /* Single variable name. */
534 /* A single subcommand. */
535 typedef struct subcommand subcommand;
538 subcommand *next; /* Next in the chain. */
539 char *name; /* Subcommand name. */
540 subcommand_type type; /* One of SBC_*. */
541 int once; /* 1=Subcommand may appear only once. */
542 int narray; /* Index of next array element. */
543 const char *prefix; /* Prefix for variable and constant names. */
544 specifier *spec; /* Array of specifiers. */
546 /* SBC_STRING only. */
547 char *restriction; /* Expression restricting string length. */
548 char *message; /* Error message. */
551 /* Name of the command; i.e., DESCRIPTIVES. */
554 /* Short prefix for the command; i.e., `dsc_'. */
557 /* List of subcommands. */
558 subcommand *subcommands;
560 /* Default subcommand if any, or NULL. */
565 void parse_subcommands (void);
567 /* Parse an entire specification. */
571 /* Get the command name and prefix. */
572 if (token != T_STRING && token != T_ID)
573 error ("Command name expected.");
574 cmdname = xstrdup (tokstr);
578 prefix = xstrdup (tokstr);
583 /* Read all the subcommands. */
586 parse_subcommands ();
589 /* Parses a single setting into S, given subcommand information SBC
590 and specifier information SPEC. */
592 parse_setting (setting *s, specifier *spec)
596 if (match_token ('*'))
599 error ("Cannot have two settings with omittable keywords.");
604 if (match_token ('!'))
607 error ("Cannot have two default settings.");
613 s->specname = xstrdup (tokstr);
614 s->con = add_symbol (s->specname, 0, 0);
619 /* Parse setting value info if necessary. */
620 if (token != '/' && token != ';' && token != '.' && token != ',')
624 s->valtype = VT_PAREN;
628 s->valtype = VT_PLAIN;
630 s->optvalue = match_token ('*');
634 else if (match_id ("D"))
637 error ("`n' or `d' expected.");
642 s->valname = xstrdup (tokstr);
649 s->restriction = xstrdup (tokstr);
653 s->restriction = NULL;
655 if (s->valtype == VT_PAREN)
660 /* Parse a single specifier into SPEC, given subcommand information
663 parse_specifier (specifier *spec, subcommand *sbc)
668 spec->omit_kw = NULL;
669 spec->varname = NULL;
673 spec->varname = xstrdup (st_lower (tokstr));
677 /* Handle array elements. */
680 spec->index = sbc->narray;
681 if (sbc->type == SBC_ARRAY)
693 /* Parse all the settings. */
695 setting **s = &spec->s;
699 *s = xmalloc (sizeof (setting));
700 parse_setting (*s, spec);
701 if (token == ',' || token == ';' || token == '.')
710 /* Parse a list of specifiers for subcommand SBC. */
712 parse_specifiers (subcommand *sbc)
714 specifier **spec = &sbc->spec;
716 if (token == ';' || token == '.')
724 *spec = xmalloc (sizeof (specifier));
725 parse_specifier (*spec, sbc);
726 if (token == ';' || token == '.')
729 spec = &(*spec)->next;
731 (*spec)->next = NULL;
734 /* Parse a subcommand into SBC. */
736 parse_subcommand (subcommand *sbc)
738 if (match_token ('*'))
741 error ("Multiple default subcommands.");
745 sbc->once = match_token ('+');
748 sbc->name = xstrdup (tokstr);
752 sbc->type = SBC_PLAIN;
755 if (match_token ('['))
758 sbc->prefix = xstrdup (st_lower (tokstr));
764 sbc->type = SBC_ARRAY;
765 parse_specifiers (sbc);
769 if (match_token ('('))
772 sbc->prefix = xstrdup (st_lower (tokstr));
782 if (match_id ("VAR"))
784 if (match_id ("VARLIST"))
786 if (match_token ('('))
789 sbc->message = xstrdup (tokstr);
794 else sbc->message = NULL;
796 sbc->type = SBC_VARLIST;
798 else if (match_id ("INTEGER"))
799 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
800 else if (match_id ("PINT"))
801 sbc->type = SBC_PINT;
802 else if (match_id ("DOUBLE"))
803 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
804 else if (match_id ("STRING"))
806 sbc->type = SBC_STRING;
807 if (token == T_STRING)
809 sbc->restriction = xstrdup (tokstr);
812 sbc->message = xstrdup (tokstr);
816 sbc->restriction = NULL;
818 else if (match_id ("CUSTOM"))
819 sbc->type = SBC_CUSTOM;
821 parse_specifiers (sbc);
825 /* Parse all the subcommands. */
827 parse_subcommands (void)
829 subcommand **sbc = &subcommands;
833 *sbc = xmalloc (sizeof (subcommand));
836 parse_subcommand (*sbc);
848 #define BASE_INDENT 2 /* Starting indent. */
849 #define INC_INDENT 2 /* Indent increment. */
851 /* Increment the indent. */
852 #define indent() indent += INC_INDENT
853 #define outdent() indent -= INC_INDENT
855 /* Size of the indent from the left margin. */
858 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
860 /* Write line FORMAT to the output file, formatted as with printf,
861 indented `indent' characters from the left margin. If INDENTION is
862 greater than 0, indents BASE_INDENT * INDENTION characters after
863 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
864 * INDENTION characters _before_ writing the line. */
866 dump (int indention, const char *format, ...)
872 indent += BASE_INDENT * indention;
875 va_start (args, format);
876 for (i = 0; i < indent; i++)
878 vfprintf (out, format, args);
883 indent += BASE_INDENT * indention;
886 /* Write the structure members for specifier SPEC to the output file.
887 SBC is the including subcommand. */
889 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
892 dump (0, "long %s%s;", sbc->prefix, spec->varname);
897 for (s = spec->s; s; s = s->next)
899 if (s->value != VAL_NONE)
901 const char *typename;
903 assert (s->value == VAL_INT || s->value == VAL_DBL);
904 typename = s->value == VAL_INT ? "long" : "double";
906 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
912 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
914 is_keyword (const char *t)
916 static const char *kw[] =
918 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
919 "NE", "ALL", "BY", "TO", "WITH", 0,
923 for (cp = kw; *cp; cp++)
924 if (!strcmp (t, *cp))
929 /* Transforms a string NAME into a valid C identifier: makes
930 everything lowercase and maps nonalphabetic characters to
931 underscores. Returns a pointer to a static buffer. */
933 make_identifier (const char *name)
935 char *p = get_buffer ();
938 for (cp = p; *name; name++)
939 if (isalpha ((unsigned char) *name))
940 *cp++ = tolower ((unsigned char) (*name));
948 /* Writes the struct and enum declarations for the parser. */
950 dump_declarations (void)
954 /* Write out enums for all the identifiers in the symbol table. */
960 /* Note the squirmings necessary to make sure that the last enum
961 is not followed by a comma, as mandated by ANSI C89. */
962 for (sym = symtab, f = k = 0; sym; sym = sym->next)
963 if (!sym->unique && !is_keyword (sym->name))
967 dump (0, "/* Settings for subcommand specifiers. */");
974 buf = xmalloc (1024);
979 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
983 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
988 buf[strlen (buf) - 1] = 0;
999 /* For every array subcommand, write out the associated enumerated
1004 for (sbc = subcommands; sbc; sbc = sbc->next)
1005 if (sbc->type == SBC_ARRAY && sbc->narray)
1007 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1015 for (spec = sbc->spec; spec; spec = spec->next)
1017 dump (0, "%s%s%s = %d,",
1018 st_upper (prefix), st_upper (sbc->prefix),
1019 st_upper (spec->varname), spec->index);
1021 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1029 /* Write out structure declaration. */
1033 dump (0, "/* %s structure. */", cmdname);
1034 dump (1, "struct cmd_%s", make_identifier (cmdname));
1036 for (sbc = subcommands; sbc; sbc = sbc->next)
1040 if (sbc != subcommands)
1043 dump (0, "/* %s subcommand. */", sbc->name);
1044 dump (0, "int sbc_%s;", st_lower (sbc->name));
1053 for (spec = sbc->spec; spec; spec = spec->next)
1057 if (sbc->type == SBC_PLAIN)
1058 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1062 dump (0, "int a_%s[%d];",
1063 st_lower (sbc->name), sbc->narray);
1068 dump_specifier_vars (spec, sbc);
1074 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1075 st_lower (sbc->name));
1076 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1077 st_lower (sbc->name));
1081 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1082 st_lower (sbc->name));
1086 dump (0, "char *s_%s;", st_lower (sbc->name));
1091 dump (0, "long n_%s;", st_lower (sbc->name));
1095 dump (0, "double n_%s;", st_lower (sbc->name));
1107 /* Write out prototypes for custom_*() functions as necessary. */
1112 for (sbc = subcommands; sbc; sbc = sbc->next)
1113 if (sbc->type == SBC_CUSTOM)
1118 dump (0, "/* Prototype for custom subcommands of %s. */",
1121 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1122 st_lower (prefix), st_lower (sbc->name),
1123 make_identifier (cmdname));
1130 /* Prototypes for parsing and freeing functions. */
1132 dump (0, "/* Command parsing functions. */");
1133 dump (0, "static int parse_%s (struct cmd_%s *);",
1134 make_identifier (cmdname), make_identifier (cmdname));
1135 dump (0, "static void free_%s (struct cmd_%s *);",
1136 make_identifier (cmdname), make_identifier (cmdname));
1141 /* Writes out code to initialize all the variables that need
1142 initialization for particular specifier SPEC inside subcommand SBC. */
1144 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1152 st_upper (prefix), find_symbol (spec->def->con)->name);
1155 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1161 for (s = spec->s; s; s = s->next)
1163 if (s->value != VAL_NONE)
1167 assert (s->value == VAL_INT || s->value == VAL_DBL);
1168 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1170 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1176 /* Write code to initialize all variables. */
1178 dump_vars_init (void)
1180 /* Loop through all the subcommands. */
1184 for (sbc = subcommands; sbc; sbc = sbc->next)
1188 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1203 for (spec = sbc->spec; spec; spec = spec->next)
1204 if (spec->s == NULL)
1206 if (sbc->type == SBC_PLAIN)
1207 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1210 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1211 st_lower (sbc->name), st_lower (sbc->name));
1216 dump_specifier_init (spec, sbc);
1221 dump (0, "p->%sn_%s = 0;",
1222 st_lower (sbc->prefix), st_lower (sbc->name));
1223 dump (0, "p->%sv_%s = NULL;",
1224 st_lower (sbc->prefix), st_lower (sbc->name));
1228 dump (0, "p->%sv_%s = NULL;",
1229 st_lower (sbc->prefix), st_lower (sbc->name));
1233 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1238 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1248 /* Return a pointer to a static buffer containing an expression that
1249 will match token T. */
1251 make_match (const char *t)
1261 sprintf (s, "lex_match (T_%s)", t);
1262 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1263 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1264 "|| lex_match_id (\"TRUE\"))");
1265 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1266 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1267 "|| lex_match_id (\"FALSE\"))");
1268 else if (isdigit ((unsigned char) t[0]))
1269 sprintf (s, "lex_match_int (%s)", t);
1271 sprintf (s, "lex_match_id (\"%s\")", t);
1276 /* Write out the parsing code for specifier SPEC within subcommand
1279 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1283 if (spec->omit_kw && spec->omit_kw->next)
1284 error ("Omittable setting is not last setting in `%s' specifier.",
1286 if (spec->omit_kw && spec->omit_kw->parent->next)
1287 error ("Default specifier is not in last specifier in `%s' "
1288 "subcommand.", sbc->name);
1290 for (s = spec->s; s; s = s->next)
1292 int first = spec == sbc->spec && s == spec->s;
1294 /* Match the setting's keyword. */
1295 if (spec->omit_kw == s)
1302 dump (1, "%s;", make_match (s->specname));
1305 dump (1, "%sif (%s)", first ? "" : "else ",
1306 make_match (s->specname));
1308 /* Handle values. */
1309 if (s->value == VAL_NONE)
1310 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1311 st_upper (prefix), find_symbol (s->con)->name);
1314 if (spec->omit_kw != s)
1318 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1319 st_upper (prefix), find_symbol (s->con)->name);
1321 if (s->valtype == VT_PAREN)
1325 dump (1, "if (lex_match ('('))");
1330 dump (1, "if (!lex_match ('('))");
1332 dump (0, "msg (SE, _(\"`(' expected after %s "
1333 "specifier of %s subcommand.\"));",
1334 s->specname, sbc->name);
1335 dump (0, "goto lossage;");
1341 if (s->value == VAL_INT)
1343 dump (1, "if (!lex_integer_p ())");
1345 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1346 "requires an integer argument.\"));",
1347 s->specname, sbc->name);
1348 dump (0, "goto lossage;");
1350 dump (-1, "p->%s%s = lex_integer ();",
1351 sbc->prefix, st_lower (s->valname));
1355 dump (1, "if (token != T_NUM)");
1357 dump (0, "msg (SE, _(\"Number expected after %s "
1358 "specifier of %s subcommand.\"));",
1359 s->specname, sbc->name);
1360 dump (0, "goto lossage;");
1362 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1363 st_lower (s->valname));
1370 str = xmalloc (MAX_TOK_LEN);
1371 str2 = xmalloc (MAX_TOK_LEN);
1372 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1373 sprintf (str, s->restriction, str2, str2, str2, str2,
1374 str2, str2, str2, str2);
1375 dump (1, "if (!(%s))", str);
1381 dump (0, "msg (SE, _(\"Bad argument for %s "
1382 "specifier of %s subcommand.\"));",
1383 s->specname, sbc->name);
1384 dump (0, "goto lossage;");
1389 dump (0, "lex_get ();");
1391 if (s->valtype == VT_PAREN)
1393 dump (1, "if (!lex_match (')'))");
1395 dump (0, "msg (SE, _(\"`)' expected after argument for "
1396 "%s specifier of %s.\"));",
1397 s->specname, sbc->name);
1398 dump (0, "goto lossage;");
1408 if (s != spec->omit_kw)
1412 if (s == spec->omit_kw)
1421 /* Write out the code to parse subcommand SBC. */
1423 dump_subcommand (const subcommand *sbc)
1425 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1429 dump (1, "while (token != '/' && token != '.')");
1435 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1438 dump_specifier_parse (spec, sbc);
1442 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1443 make_match (st_upper (spec->varname)));
1444 if (sbc->type == SBC_PLAIN)
1445 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1448 dump (0, "p->a_%s[%s%s%s] = 1;",
1449 st_lower (sbc->name),
1450 st_upper (prefix), st_upper (sbc->prefix),
1451 st_upper (spec->varname));
1461 /* This code first finds the last specifier in sbc. Then it
1462 finds the last setting within that last specifier. Either
1463 or both might be NULL. */
1476 if (spec && (!spec->s || !spec->omit_kw))
1480 dump (0, "lex_error (NULL);");
1481 dump (0, "goto lossage;");
1487 dump (0, "lex_match (',');");
1491 else if (sbc->type == SBC_VARLIST)
1493 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1495 st_lower (sbc->prefix), st_lower (sbc->name),
1496 st_lower (sbc->prefix), st_lower (sbc->name),
1497 sbc->message ? " |" : "",
1498 sbc->message ? sbc->message : "");
1499 dump (0, "goto lossage;");
1502 else if (sbc->type == SBC_VAR)
1504 dump (0, "p->%sv_%s = parse_variable ();",
1505 st_lower (sbc->prefix), st_lower (sbc->name));
1506 dump (1, "if (p->%sv_%s)",
1507 st_lower (sbc->prefix), st_lower (sbc->name));
1508 dump (0, "goto lossage;");
1511 else if (sbc->type == SBC_STRING)
1513 if (sbc->restriction)
1518 dump (1, "if (!lex_force_string ())");
1519 dump (0, "return 0;");
1521 if (sbc->restriction)
1523 dump (0, "x = ds_length (&tokstr);");
1524 dump (1, "if (!(%s))", sbc->restriction);
1526 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1527 sbc->name, sbc->message);
1528 dump (0, "goto lossage;");
1532 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1533 st_lower (sbc->name));
1534 dump (0, "lex_get ();");
1535 if (sbc->restriction)
1538 else if (sbc->type == SBC_DBL)
1540 dump (1, "if (!lex_force_num ())");
1541 dump (0, "goto lossage;");
1542 dump (-1, "p->n_%s = lex_double ();", st_lower (sbc->name));
1543 dump (0, "lex_get();");
1545 else if (sbc->type == SBC_INT)
1547 dump (1, "if (!lex_force_int ())");
1548 dump (0, "goto lossage;");
1549 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1550 dump (0, "lex_get();");
1552 else if (sbc->type == SBC_PINT)
1554 dump (0, "lex_match ('(');");
1555 dump (1, "if (!lex_force_int ())");
1556 dump (0, "goto lossage;");
1557 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1558 dump (0, "lex_match (')');");
1560 else if (sbc->type == SBC_CUSTOM)
1562 dump (1, "switch (%scustom_%s (p))",
1563 st_lower (prefix), st_lower (sbc->name));
1565 dump (1, "case 0:");
1566 dump (0, "goto lossage;");
1567 dump (-1, "case 1:");
1570 dump (-1, "case 2:");
1572 dump (0, "lex_error (NULL);");
1573 dump (0, "goto lossage;");
1574 dump (-1, "default:");
1576 dump (0, "assert (0);");
1582 /* Write out entire parser. */
1590 dump (0, "static int");
1591 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1592 make_identifier (cmdname));
1597 dump (1, "for (;;)");
1601 if (def && (def->type == SBC_VARLIST))
1603 if (def->type == SBC_VARLIST)
1604 dump (1, "if (token == T_ID "
1605 "&& dict_lookup_var (default_dict, tokid) != NULL "
1606 "&& lex_look_ahead () != '=')");
1609 dump (0, "if ((token == T_ID "
1610 "&& dict_lookup_var (default_dict, tokid) "
1611 "&& lex_look_ahead () != '=')");
1612 dump (1, " || token == T_ALL)");
1615 dump (0, "p->sbc_%s++;", st_lower (def->name));
1616 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1618 st_lower (def->prefix), st_lower (def->name),
1619 st_lower (def->prefix), st_lower (def->name));
1620 dump (0, "goto lossage;");
1625 else if (def && def->type == SBC_CUSTOM)
1627 dump (1, "switch (%scustom_%s (p))",
1628 st_lower (prefix), st_lower (def->name));
1630 dump (1, "case 0:");
1631 dump (0, "goto lossage;");
1632 dump (-1, "case 1:");
1634 dump (0, "p->sbc_%s++;", st_lower (def->name));
1635 dump (0, "continue;");
1636 dump (-1, "case 2:");
1639 dump (-1, "default:");
1641 dump (0, "assert (0);");
1649 for (sbc = subcommands; sbc; sbc = sbc->next)
1651 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1655 dump (0, "lex_match ('=');");
1656 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1659 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1661 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1663 dump (0, "goto lossage;");
1667 dump_subcommand (sbc);
1673 dump (1, "if (!lex_match ('/'))");
1678 dump (1, "if (token != '.')");
1680 dump (0, "lex_error (_(\"expecting end of command\"));");
1681 dump (0, "goto lossage;");
1684 dump (-1, "return 1;");
1686 dump (-1, "lossage:");
1688 dump (0, "free_%s (p);", make_identifier (cmdname));
1689 dump (0, "return 0;");
1694 /* Write the output file header. */
1703 curtime = time (NULL);
1704 loctime = localtime (&curtime);
1705 timep = asctime (loctime);
1706 timep[strlen (timep) - 1] = 0;
1707 dump (0, "/* %s", ofn);
1709 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1710 dump (0, " Do not modify!");
1715 /* Write out commands to free variable state. */
1725 for (sbc = subcommands; sbc; sbc = sbc->next)
1726 if (sbc->type == SBC_STRING)
1729 dump (0, "static void");
1730 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1731 make_identifier (cmdname), used ? "" : " UNUSED");
1734 for (sbc = subcommands; sbc; sbc = sbc->next)
1735 if (sbc->type == SBC_STRING)
1736 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1741 /* Returns the name of a directive found on the current input line, if
1742 any, or a null pointer if none found. */
1744 recognize_directive (void)
1746 static char directive[16];
1750 if (strncmp (sp, "/*", 2))
1752 sp = skip_ws (sp + 2);
1757 ep = strchr (sp, ')');
1763 memcpy (directive, sp, ep - sp);
1764 directive[ep - sp] = '\0';
1769 main (int argc, char *argv[])
1773 fail ("Syntax: q2c input.q output.c");
1776 in = fopen (ifn, "r");
1778 fail ("%s: open: %s.", ifn, strerror (errno));
1781 out = fopen (ofn, "w");
1783 fail ("%s: open: %s.", ofn, strerror (errno));
1786 buf = xmalloc (MAX_LINE_LEN);
1787 tokstr = xmalloc (MAX_TOK_LEN);
1792 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1795 const char *directive = recognize_directive ();
1796 if (directive == NULL)
1798 dump (0, "%s", buf);
1802 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1803 if (!strcmp (directive, "specification"))
1805 /* Skip leading slash-star line. */
1811 /* Skip trailing star-slash line. */
1814 else if (!strcmp (directive, "headers"))
1818 dump (0, "#include <assert.h>");
1819 dump (0, "#include <stdlib.h>");
1820 dump (0, "#include \"alloc.h\"");
1821 dump (0, "#include \"error.h\"");
1822 dump (0, "#include \"lexer.h\"");
1823 dump (0, "#include \"str.h\"");
1824 dump (0, "#include \"var.h\"");
1827 else if (!strcmp (directive, "declarations"))
1828 dump_declarations ();
1829 else if (!strcmp (directive, "functions"))
1835 error ("unknown directive `%s'", directive);
1837 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1840 return EXIT_SUCCESS;