1 /* q2c - parser generator for PSPP procedures.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
35 #define EXIT_SUCCESS 0
39 #define EXIT_FAILURE 1
43 #include "misc/strerror.c"
46 #include "debug-print.h"
48 /* Max length of an input line. */
49 #define MAX_LINE_LEN 1024
51 /* Max token length. */
52 #define MAX_TOK_LEN 1024
57 /* Have the input and output files been opened yet? */
60 /* Input, output files. */
63 /* Input, output file names. */
66 /* Input, output file line number. */
69 /* Input line buffer, current position. */
75 T_STRING = 256, /* String literal. */
76 T_ID = 257 /* Identifier. */
79 /* Current token: either one of the above, or a single character. */
82 /* Token string value. */
85 /* Utility functions. */
89 /* Close all open files and delete the output file, on failure. */
98 if (remove (ofn) == -1)
99 fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
103 void hcf (void) __attribute__ ((noreturn));
106 /* Terminate unsuccessfully. */
115 int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
116 int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
119 /* Output an error message and terminate unsuccessfully. */
121 fail (const char *format, ...)
125 va_start (args, format);
126 fprintf (stderr, "%s: ", pgmname);
127 vfprintf (stderr, format, args);
128 fprintf (stderr, "\n");
134 /* Output a context-dependent error message and terminate
137 error (const char *format,...)
141 va_start (args, format);
142 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
143 vfprintf (stderr, format, args);
144 fprintf (stderr, "\n");
150 #define VME "virtual memory exhausted"
152 /* Allocate a block of SIZE bytes and return a pointer to its
155 xmalloc (size_t size)
164 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
169 /* Resize the block at PTR to size SIZE and return a pointer to the
170 beginning of the new block. */
172 xrealloc (void *ptr, size_t size)
184 vp = realloc (ptr, size);
189 fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
194 /* Make a dynamically allocated copy of string S and return a pointer
195 to the first character. */
197 xstrdup (const char *s)
203 size = strlen (s) + 1;
207 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
213 /* Returns a pointer to one of 8 static buffers. The buffers are used
218 static char b[8][256];
227 /* Copies a string to a static buffer, converting it to lowercase in
228 the process, and returns a pointer to the static buffer. */
230 st_lower (const char *s)
234 p = cp = get_buffer ();
236 *cp++ = tolower ((unsigned char) (*s++));
242 /* Copies a string to a static buffer, converting it to uppercase in
243 the process, and returns a pointer to the static buffer. */
245 st_upper (const char *s)
249 p = cp = get_buffer ();
251 *cp++ = toupper ((unsigned char) (*s++));
257 /* Returns the address of the first non-whitespace character in S, or
258 the address of the null terminator if none. */
260 skip_ws (const char *s)
262 while (isspace ((unsigned char) *s))
267 /* Read one line from the input file into buf. Lines having special
268 formats are handled specially. */
273 if (0 == fgets (buf, MAX_LINE_LEN, in))
276 fail ("%s: fgets: %s", ifn, strerror (errno));
280 cp = strchr (buf, '\n');
288 /* Symbol table manager. */
290 /* Symbol table entry. */
291 typedef struct symbol symbol;
294 symbol *next; /* Next symbol in symbol table. */
295 char *name; /* Symbol name. */
296 int unique; /* 1=Name must be unique in this file. */
297 int ln; /* Line number of definition. */
298 int value; /* Symbol value. */
304 /* Add a symbol to the symbol table having name NAME, uniqueness
305 UNIQUE, and value VALUE. If a symbol having the same name is found
306 in the symbol table, its sequence number is returned and the symbol
307 table is not modified. Otherwise, the symbol is added and the next
308 available sequence number is returned. */
310 add_symbol (const char *name, int unique, int value)
315 sym = xmalloc (sizeof (symbol));
316 sym->name = xstrdup (name);
317 sym->unique = unique;
330 if (!strcmp (iter->name, name))
334 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
336 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
353 /* Finds the symbol having given sequence number X within the symbol
354 table, and returns the associated symbol structure. */
361 while (x > 1 && iter)
371 /* Writes a printable representation of the current token to
379 printf ("STRING\t\"%s\"\n", tokstr);
382 printf ("ID\t%s\n", tokstr);
385 printf ("PUNCT\t%c\n", token);
388 #endif /* DEBUGGING */
390 /* Reads a token from the input file. */
394 /* Skip whitespace and check for end of file. */
402 fail ("%s: Unexpected end of file.", ifn);
405 if (*cp == '_' || isalnum ((unsigned char) *cp))
409 while (*cp == '_' || isalnum ((unsigned char) *cp))
410 *dest++ = toupper ((unsigned char) (*cp++));
418 while (*cp != '"' && *cp)
424 error ("Unterminated string literal.");
432 error ("Unterminated string literal.");
445 /* Force the current token to be an identifier token. */
450 error ("Identifier expected.");
453 /* Force the current token to be a string token. */
457 if (token != T_STRING)
458 error ("String expected.");
461 /* Checks whether the current token is the identifier S; if so, skips
462 the token and returns 1; otherwise, returns 0. */
464 match_id (const char *s)
466 if (token == T_ID && !strcmp (tokstr, s))
474 /* Checks whether the current token is T. If so, skips the token and
475 returns 1; otherwise, returns 0. */
487 /* Force the current token to be T, and skip it. */
492 error ("`%c' expected.", t);
498 /* Some specifiers have associated values. */
501 VAL_NONE, /* No value. */
502 VAL_INT, /* Integer value. */
503 VAL_DBL /* Floating point value. */
506 /* For those specifiers with values, the syntax of those values. */
509 VT_PLAIN, /* Unadorned value. */
510 VT_PAREN /* Value must be enclosed in parentheses. */
513 /* Forward definition. */
514 typedef struct specifier specifier;
516 /* A single setting. */
517 typedef struct setting setting;
520 specifier *parent; /* Owning specifier. */
521 setting *next; /* Next in the chain. */
522 char *specname; /* Name of the setting. */
523 int con; /* Sequence number. */
526 int valtype; /* One of VT_*. */
527 int value; /* One of VAL_*. */
528 int optvalue; /* 1=value is optional, 0=value is required. */
529 char *valname; /* Variable name for the value. */
530 char *restriction; /* !=NULL: expression specifying valid values. */
533 /* A single specifier. */
536 specifier *next; /* Next in the chain. */
537 char *varname; /* Variable name. */
538 setting *s; /* Associated settings. */
540 setting *def; /* Default setting. */
541 setting *omit_kw; /* Setting for which the keyword can be omitted. */
543 int index; /* Next array index. */
546 /* Subcommand types. */
549 SBC_PLAIN, /* The usual case. */
550 SBC_VARLIST, /* Variable list. */
551 SBC_INT, /* Integer value. */
552 SBC_PINT, /* Integer inside parentheses. */
553 SBC_DBL, /* Floating point value. */
554 SBC_INT_LIST, /* List of integers (?). */
555 SBC_DBL_LIST, /* List of floating points (?). */
556 SBC_CUSTOM, /* Custom. */
557 SBC_ARRAY, /* Array of boolean values. */
558 SBC_STRING, /* String value. */
559 SBC_VAR /* Single variable name. */
563 /* A single subcommand. */
564 typedef struct subcommand subcommand;
567 subcommand *next; /* Next in the chain. */
568 char *name; /* Subcommand name. */
569 subcommand_type type; /* One of SBC_*. */
570 int once; /* 1=Subcommand may appear only once. */
571 int narray; /* Index of next array element. */
572 const char *prefix; /* Prefix for variable and constant names. */
573 specifier *spec; /* Array of specifiers. */
575 /* SBC_STRING only. */
576 char *restriction; /* Expression restricting string length. */
577 char *message; /* Error message. */
580 /* Name of the command; i.e., DESCRIPTIVES. */
583 /* Short prefix for the command; i.e., `dsc_'. */
586 /* List of subcommands. */
587 subcommand *subcommands;
589 /* Default subcommand if any, or NULL. */
594 void parse_subcommands (void);
596 /* Parse an entire specification. */
600 /* Get the command name and prefix. */
601 if (token != T_STRING && token != T_ID)
602 error ("Command name expected.");
603 cmdname = xstrdup (tokstr);
607 prefix = xstrdup (tokstr);
612 /* Read all the subcommands. */
615 parse_subcommands ();
618 /* Parses a single setting into S, given subcommand information SBC
619 and specifier information SPEC. */
621 parse_setting (setting *s, specifier *spec)
625 if (match_token ('*'))
628 error ("Cannot have two settings with omittable keywords.");
633 if (match_token ('!'))
636 error ("Cannot have two default settings.");
642 s->specname = xstrdup (tokstr);
643 s->con = add_symbol (s->specname, 0, 0);
648 /* Parse setting value info if necessary. */
649 if (token != '/' && token != ';' && token != '.' && token != ',')
653 s->valtype = VT_PAREN;
657 s->valtype = VT_PLAIN;
659 s->optvalue = match_token ('*');
663 else if (match_id ("D"))
666 error ("`n' or `d' expected.");
671 s->valname = xstrdup (tokstr);
678 s->restriction = xstrdup (tokstr);
682 s->restriction = NULL;
684 if (s->valtype == VT_PAREN)
689 /* Parse a single specifier into SPEC, given subcommand information
692 parse_specifier (specifier *spec, subcommand *sbc)
697 spec->omit_kw = NULL;
698 spec->varname = NULL;
702 spec->varname = xstrdup (st_lower (tokstr));
706 /* Handle array elements. */
709 spec->index = sbc->narray;
710 if (sbc->type == SBC_ARRAY)
722 /* Parse all the settings. */
724 setting **s = &spec->s;
728 *s = xmalloc (sizeof (setting));
729 parse_setting (*s, spec);
730 if (token == ',' || token == ';' || token == '.')
739 /* Parse a list of specifiers for subcommand SBC. */
741 parse_specifiers (subcommand *sbc)
743 specifier **spec = &sbc->spec;
745 if (token == ';' || token == '.')
753 *spec = xmalloc (sizeof (specifier));
754 parse_specifier (*spec, sbc);
755 if (token == ';' || token == '.')
758 spec = &(*spec)->next;
760 (*spec)->next = NULL;
763 /* Parse a subcommand into SBC. */
765 parse_subcommand (subcommand *sbc)
767 if (match_token ('*'))
770 error ("Multiple default subcommands.");
774 sbc->once = match_token ('+');
777 sbc->name = xstrdup (tokstr);
781 sbc->type = SBC_PLAIN;
784 if (match_token ('['))
787 sbc->prefix = xstrdup (st_lower (tokstr));
793 sbc->type = SBC_ARRAY;
794 parse_specifiers (sbc);
798 if (match_token ('('))
801 sbc->prefix = xstrdup (st_lower (tokstr));
811 if (match_id ("VAR"))
813 if (match_id ("VARLIST"))
815 if (match_token ('('))
818 sbc->message = xstrdup (tokstr);
823 else sbc->message = NULL;
825 sbc->type = SBC_VARLIST;
827 else if (match_id ("INTEGER"))
828 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
829 else if (match_id ("PINT"))
830 sbc->type = SBC_PINT;
831 else if (match_id ("DOUBLE"))
832 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
833 else if (match_id ("STRING"))
835 sbc->type = SBC_STRING;
836 if (token == T_STRING)
838 sbc->restriction = xstrdup (tokstr);
841 sbc->message = xstrdup (tokstr);
845 sbc->restriction = NULL;
847 else if (match_id ("CUSTOM"))
848 sbc->type = SBC_CUSTOM;
850 parse_specifiers (sbc);
854 /* Parse all the subcommands. */
856 parse_subcommands (void)
858 subcommand **sbc = &subcommands;
862 *sbc = xmalloc (sizeof (subcommand));
865 parse_subcommand (*sbc);
877 #define BASE_INDENT 2 /* Starting indent. */
878 #define INC_INDENT 2 /* Indent increment. */
880 /* Increment the indent. */
881 #define indent() indent += INC_INDENT
882 #define outdent() indent -= INC_INDENT
884 /* Size of the indent from the left margin. */
888 void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
891 /* Write line FORMAT to the output file, formatted as with printf,
892 indented `indent' characters from the left margin. If INDENTION is
893 greater than 0, indents BASE_INDENT * INDENTION characters after
894 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
895 * INDENTION characters _before_ writing the line. */
897 dump (int indention, const char *format, ...)
903 indent += BASE_INDENT * indention;
906 va_start (args, format);
907 for (i = 0; i < indent; i++)
909 vfprintf (out, format, args);
914 indent += BASE_INDENT * indention;
917 /* Write the structure members for specifier SPEC to the output file.
918 SBC is the including subcommand. */
920 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
923 dump (0, "long %s%s;", sbc->prefix, spec->varname);
928 for (s = spec->s; s; s = s->next)
930 if (s->value != VAL_NONE)
932 const char *typename;
934 assert (s->value == VAL_INT || s->value == VAL_DBL);
935 typename = s->value == VAL_INT ? "long" : "double";
937 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
943 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
945 is_keyword (const char *t)
947 static const char *kw[] =
949 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
950 "NE", "ALL", "BY", "TO", "WITH", 0,
954 for (cp = kw; *cp; cp++)
955 if (!strcmp (t, *cp))
960 /* Transforms a string NAME into a valid C identifier: makes
961 everything lowercase and maps nonalphabetic characters to
962 underscores. Returns a pointer to a static buffer. */
964 make_identifier (const char *name)
966 char *p = get_buffer ();
969 for (cp = p; *name; name++)
970 if (isalpha ((unsigned char) *name))
971 *cp++ = tolower ((unsigned char) (*name));
979 /* Writes the struct and enum declarations for the parser. */
981 dump_declarations (void)
985 /* Write out enums for all the identifiers in the symbol table. */
991 /* Note the squirmings necessary to make sure that the last enum
992 is not followed by a comma, as mandated by ANSI C89. */
993 for (sym = symtab, f = k = 0; sym; sym = sym->next)
994 if (!sym->unique && !is_keyword (sym->name))
998 dump (0, "/* Settings for subcommand specifiers. */");
1005 buf = xmalloc (1024);
1010 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1014 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1019 buf[strlen (buf) - 1] = 0;
1030 /* For every array subcommand, write out the associated enumerated
1035 for (sbc = subcommands; sbc; sbc = sbc->next)
1036 if (sbc->type == SBC_ARRAY && sbc->narray)
1038 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1046 for (spec = sbc->spec; spec; spec = spec->next)
1048 dump (0, "%s%s%s = %d,",
1049 st_upper (prefix), st_upper (sbc->prefix),
1050 st_upper (spec->varname), spec->index);
1052 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1060 /* Write out structure declaration. */
1064 dump (0, "/* %s structure. */", cmdname);
1065 dump (1, "struct cmd_%s", make_identifier (cmdname));
1067 for (sbc = subcommands; sbc; sbc = sbc->next)
1071 if (sbc != subcommands)
1074 dump (0, "/* %s subcommand. */", sbc->name);
1075 dump (0, "int sbc_%s;", st_lower (sbc->name));
1084 for (spec = sbc->spec; spec; spec = spec->next)
1088 if (sbc->type == SBC_PLAIN)
1089 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1093 dump (0, "int a_%s[%d];",
1094 st_lower (sbc->name), sbc->narray);
1099 dump_specifier_vars (spec, sbc);
1105 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1106 st_lower (sbc->name));
1107 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1108 st_lower (sbc->name));
1112 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1113 st_lower (sbc->name));
1117 dump (0, "char *s_%s;", st_lower (sbc->name));
1122 dump (0, "long n_%s;", st_lower (sbc->name));
1134 /* Write out prototypes for custom_*() functions as necessary. */
1139 for (sbc = subcommands; sbc; sbc = sbc->next)
1140 if (sbc->type == SBC_CUSTOM)
1145 dump (0, "/* Prototype for custom subcommands of %s. */",
1148 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1149 st_lower (prefix), st_lower (sbc->name),
1150 make_identifier (cmdname));
1157 /* Prototypes for parsing and freeing functions. */
1159 dump (0, "/* Command parsing functions. */");
1160 dump (0, "static int parse_%s (struct cmd_%s *);",
1161 make_identifier (cmdname), make_identifier (cmdname));
1162 dump (0, "static void free_%s (struct cmd_%s *);",
1163 make_identifier (cmdname), make_identifier (cmdname));
1168 /* Writes out code to initialize all the variables that need
1169 initialization for particular specifier SPEC inside subcommand SBC. */
1171 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1179 st_upper (prefix), find_symbol (spec->def->con)->name);
1182 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1188 for (s = spec->s; s; s = s->next)
1190 if (s->value != VAL_NONE)
1194 assert (s->value == VAL_INT || s->value == VAL_DBL);
1195 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1197 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1203 /* Write code to initialize all variables. */
1205 dump_vars_init (void)
1207 /* Loop through all the subcommands. */
1211 for (sbc = subcommands; sbc; sbc = sbc->next)
1215 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1230 for (spec = sbc->spec; spec; spec = spec->next)
1231 if (spec->s == NULL)
1233 if (sbc->type == SBC_PLAIN)
1234 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1237 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1238 st_lower (sbc->name), st_lower (sbc->name));
1243 dump_specifier_init (spec, sbc);
1248 dump (0, "p->%sn_%s = 0;",
1249 st_lower (sbc->prefix), st_lower (sbc->name));
1250 dump (0, "p->%sv_%s = NULL;",
1251 st_lower (sbc->prefix), st_lower (sbc->name));
1255 dump (0, "p->%sv_%s = NULL;",
1256 st_lower (sbc->prefix), st_lower (sbc->name));
1260 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1265 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1275 /* Return a pointer to a static buffer containing an expression that
1276 will match token T. */
1278 make_match (const char *t)
1288 sprintf (s, "lex_match (T_%s)", t);
1289 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1290 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1291 "|| lex_match_id (\"TRUE\"))");
1292 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1293 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1294 "|| lex_match_id (\"FALSE\"))");
1295 else if (isdigit ((unsigned char) t[0]))
1296 sprintf (s, "lex_match_int (%s)", t);
1298 sprintf (s, "lex_match_id (\"%s\")", t);
1303 /* Write out the parsing code for specifier SPEC within subcommand
1306 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1310 if (spec->omit_kw && spec->omit_kw->next)
1311 error ("Omittable setting is not last setting in `%s' specifier.",
1313 if (spec->omit_kw && spec->omit_kw->parent->next)
1314 error ("Default specifier is not in last specifier in `%s' "
1315 "subcommand.", sbc->name);
1317 for (s = spec->s; s; s = s->next)
1319 int first = spec == sbc->spec && s == spec->s;
1321 /* Match the setting's keyword. */
1322 if (spec->omit_kw == s)
1329 dump (1, "%s;", make_match (s->specname));
1332 dump (1, "%sif (%s)", first ? "" : "else ",
1333 make_match (s->specname));
1335 /* Handle values. */
1336 if (s->value == VAL_NONE)
1337 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1338 st_upper (prefix), find_symbol (s->con)->name);
1341 if (spec->omit_kw != s)
1345 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1346 st_upper (prefix), find_symbol (s->con)->name);
1348 if (s->valtype == VT_PAREN)
1352 dump (1, "if (lex_match ('('))");
1357 dump (1, "if (!lex_match ('('))");
1359 dump (0, "msg (SE, _(\"`(' expected after %s "
1360 "specifier of %s subcommand.\"));",
1361 s->specname, sbc->name);
1362 dump (0, "goto lossage;");
1368 if (s->value == VAL_INT)
1370 dump (1, "if (!lex_integer_p ())");
1372 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1373 "requires an integer argument.\"));",
1374 s->specname, sbc->name);
1375 dump (0, "goto lossage;");
1377 dump (-1, "p->%s%s = lex_integer ();",
1378 sbc->prefix, st_lower (s->valname));
1382 dump (1, "if (token != T_NUM)");
1384 dump (0, "msg (SE, _(\"Number expected after %s "
1385 "specifier of %s subcommand.\"));",
1386 s->specname, sbc->name);
1387 dump (0, "goto lossage;");
1389 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1390 st_lower (s->valname));
1397 str = xmalloc (MAX_TOK_LEN);
1398 str2 = xmalloc (MAX_TOK_LEN);
1399 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1400 sprintf (str, s->restriction, str2, str2, str2, str2,
1401 str2, str2, str2, str2);
1402 dump (1, "if (!(%s))", str);
1408 dump (0, "msg (SE, _(\"Bad argument for %s "
1409 "specifier of %s subcommand.\"));",
1410 s->specname, sbc->name);
1411 dump (0, "goto lossage;");
1416 dump (0, "lex_get ();");
1418 if (s->valtype == VT_PAREN)
1420 dump (1, "if (!lex_match (')'))");
1422 dump (0, "msg (SE, _(\"`)' expected after argument for "
1423 "%s specifier of %s.\"));",
1424 s->specname, sbc->name);
1425 dump (0, "goto lossage;");
1435 if (s != spec->omit_kw)
1439 if (s == spec->omit_kw)
1448 /* Write out the code to parse subcommand SBC. */
1450 dump_subcommand (const subcommand *sbc)
1452 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1456 dump (1, "while (token != '/' && token != '.')");
1462 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1465 dump_specifier_parse (spec, sbc);
1469 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1470 make_match (st_upper (spec->varname)));
1471 if (sbc->type == SBC_PLAIN)
1472 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1475 dump (0, "p->a_%s[%s%s%s] = 1;",
1476 st_lower (sbc->name),
1477 st_upper (prefix), st_upper (sbc->prefix),
1478 st_upper (spec->varname));
1488 /* This code first finds the last specifier in sbc. Then it
1489 finds the last setting within that last specifier. Either
1490 or both might be NULL. */
1503 if (spec && (!spec->s || !spec->omit_kw))
1507 dump (0, "lex_error (NULL);");
1508 dump (0, "goto lossage;");
1514 dump (0, "lex_match (',');");
1518 else if (sbc->type == SBC_VARLIST)
1520 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1522 st_lower (sbc->prefix), st_lower (sbc->name),
1523 st_lower (sbc->prefix), st_lower (sbc->name),
1524 sbc->message ? " |" : "",
1525 sbc->message ? sbc->message : "");
1526 dump (0, "goto lossage;");
1529 else if (sbc->type == SBC_VAR)
1531 dump (0, "p->%sv_%s = parse_variable ();",
1532 st_lower (sbc->prefix), st_lower (sbc->name));
1533 dump (1, "if (p->%sv_%s)",
1534 st_lower (sbc->prefix), st_lower (sbc->name));
1535 dump (0, "goto lossage;");
1538 else if (sbc->type == SBC_STRING)
1540 if (sbc->restriction)
1545 dump (1, "if (!lex_force_string ())");
1546 dump (0, "return 0;");
1548 if (sbc->restriction)
1550 dump (0, "x = ds_length (&tokstr);");
1551 dump (1, "if (!(%s))", sbc->restriction);
1553 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1554 sbc->name, sbc->message);
1555 dump (0, "goto lossage;");
1559 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1560 st_lower (sbc->name));
1561 dump (0, "lex_get ();");
1562 if (sbc->restriction)
1565 else if (sbc->type == SBC_INT)
1567 dump (1, "if (!lex_force_int ())");
1568 dump (0, "goto lossage;");
1569 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1571 else if (sbc->type == SBC_PINT)
1573 dump (0, "lex_match ('(');");
1574 dump (1, "if (!lex_force_int ())");
1575 dump (0, "goto lossage;");
1576 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1577 dump (0, "lex_match (')');");
1579 else if (sbc->type == SBC_CUSTOM)
1581 dump (1, "switch (%scustom_%s (p))",
1582 st_lower (prefix), st_lower (sbc->name));
1584 dump (1, "case 0:");
1585 dump (0, "goto lossage;");
1586 dump (-1, "case 1:");
1589 dump (-1, "case 2:");
1591 dump (0, "lex_error (NULL);");
1592 dump (0, "goto lossage;");
1593 dump (-1, "default:");
1595 dump (0, "assert (0);");
1601 /* Write out entire parser. */
1609 dump (0, "static int");
1610 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1611 make_identifier (cmdname));
1616 dump (1, "for (;;)");
1620 if (def && (def->type == SBC_VARLIST))
1622 if (def->type == SBC_VARLIST)
1623 dump (1, "if (token == T_ID && is_varname (tokid) && "
1624 "lex_look_ahead () != '=')");
1627 dump (0, "if ((token == T_ID && is_varname (tokid) && "
1628 "lex_look_ahead () != '=')");
1629 dump (1, " || token == T_ALL)");
1632 dump (0, "p->sbc_%s++;", st_lower (def->name));
1633 dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
1635 st_lower (def->prefix), st_lower (def->name),
1636 st_lower (def->prefix), st_lower (def->name));
1637 dump (0, "goto lossage;");
1642 else if (def && def->type == SBC_CUSTOM)
1644 dump (1, "switch (%scustom_%s (p))",
1645 st_lower (prefix), st_lower (def->name));
1647 dump (1, "case 0:");
1648 dump (0, "goto lossage;");
1649 dump (-1, "case 1:");
1651 dump (0, "p->sbc_%s++;", st_lower (def->name));
1652 dump (0, "continue;");
1653 dump (-1, "case 2:");
1656 dump (-1, "default:");
1658 dump (0, "assert (0);");
1666 for (sbc = subcommands; sbc; sbc = sbc->next)
1668 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1672 dump (0, "lex_match ('=');");
1673 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1676 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1678 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1680 dump (0, "goto lossage;");
1684 dump_subcommand (sbc);
1690 dump (1, "if (!lex_match ('/'))");
1695 dump (1, "if (token != '.')");
1697 dump (0, "lex_error (_(\"expecting end of command\"));");
1698 dump (0, "goto lossage;");
1701 dump (-1, "return 1;");
1703 dump (-1, "lossage:");
1705 dump (0, "free_%s (p);", make_identifier (cmdname));
1706 dump (0, "return 0;");
1711 /* Write the output file header. */
1720 curtime = time (NULL);
1721 loctime = localtime (&curtime);
1722 timep = asctime (loctime);
1723 timep[strlen (timep) - 1] = 0;
1724 dump (0, "/* %s", ofn);
1726 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1727 dump (0, " Do not modify!");
1732 /* Write out commands to free variable state. */
1742 for (sbc = subcommands; sbc; sbc = sbc->next)
1743 if (sbc->type == SBC_STRING)
1746 dump (0, "static void");
1747 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1748 make_identifier (cmdname), used ? "" : " unused");
1751 for (sbc = subcommands; sbc; sbc = sbc->next)
1752 if (sbc->type == SBC_STRING)
1753 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1758 /* Returns the name of a directive found on the current input line, if
1759 any, or a null pointer if none found. */
1761 recognize_directive (void)
1763 static char directive[16];
1767 if (strncmp (sp, "/*", 2))
1769 sp = skip_ws (sp + 2);
1774 ep = strchr (sp, ')');
1780 memcpy (directive, sp, ep - sp);
1781 directive[ep - sp] = '\0';
1786 main (int argc, char *argv[])
1790 fail ("Syntax: q2c input.q output.c");
1793 in = fopen (ifn, "r");
1795 fail ("%s: open: %s.", ifn, strerror (errno));
1798 out = fopen (ofn, "w");
1800 fail ("%s: open: %s.", ofn, strerror (errno));
1803 buf = xmalloc (MAX_LINE_LEN);
1804 tokstr = xmalloc (MAX_TOK_LEN);
1809 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1812 const char *directive = recognize_directive ();
1813 if (directive == NULL)
1815 dump (0, "%s", buf);
1819 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1820 if (!strcmp (directive, "specification"))
1822 /* Skip leading slash-star line. */
1828 /* Skip trailing star-slash line. */
1831 else if (!strcmp (directive, "headers"))
1835 dump (0, "#include <assert.h>");
1836 dump (0, "#include <stdlib.h>");
1837 dump (0, "#include \"alloc.h\"");
1838 dump (0, "#include \"error.h\"");
1839 dump (0, "#include \"lexer.h\"");
1840 dump (0, "#include \"str.h\"");
1841 dump (0, "#include \"var.h\"");
1844 else if (!strcmp (directive, "declarations"))
1845 dump_declarations ();
1846 else if (!strcmp (directive, "functions"))
1852 error ("unknown directive `%s'", directive);
1854 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1857 return EXIT_SUCCESS;