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 /* Make a dynamically allocated copy of string S and return a pointer
170 to the first character. */
172 xstrdup (const char *s)
178 size = strlen (s) + 1;
182 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
188 /* Returns a pointer to one of 8 static buffers. The buffers are used
193 static char b[8][256];
202 /* Copies a string to a static buffer, converting it to lowercase in
203 the process, and returns a pointer to the static buffer. */
205 st_lower (const char *s)
209 p = cp = get_buffer ();
211 *cp++ = tolower ((unsigned char) (*s++));
217 /* Copies a string to a static buffer, converting it to uppercase in
218 the process, and returns a pointer to the static buffer. */
220 st_upper (const char *s)
224 p = cp = get_buffer ();
226 *cp++ = toupper ((unsigned char) (*s++));
232 /* Returns the address of the first non-whitespace character in S, or
233 the address of the null terminator if none. */
235 skip_ws (const char *s)
237 while (isspace ((unsigned char) *s))
242 /* Read one line from the input file into buf. Lines having special
243 formats are handled specially. */
248 if (0 == fgets (buf, MAX_LINE_LEN, in))
251 fail ("%s: fgets: %s", ifn, strerror (errno));
255 cp = strchr (buf, '\n');
263 /* Symbol table manager. */
265 /* Symbol table entry. */
266 typedef struct symbol symbol;
269 symbol *next; /* Next symbol in symbol table. */
270 char *name; /* Symbol name. */
271 int unique; /* 1=Name must be unique in this file. */
272 int ln; /* Line number of definition. */
273 int value; /* Symbol value. */
279 /* Add a symbol to the symbol table having name NAME, uniqueness
280 UNIQUE, and value VALUE. If a symbol having the same name is found
281 in the symbol table, its sequence number is returned and the symbol
282 table is not modified. Otherwise, the symbol is added and the next
283 available sequence number is returned. */
285 add_symbol (const char *name, int unique, int value)
290 sym = xmalloc (sizeof (symbol));
291 sym->name = xstrdup (name);
292 sym->unique = unique;
305 if (!strcmp (iter->name, name))
309 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
311 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
328 /* Finds the symbol having given sequence number X within the symbol
329 table, and returns the associated symbol structure. */
336 while (x > 1 && iter)
346 /* Writes a printable representation of the current token to
354 printf ("STRING\t\"%s\"\n", tokstr);
357 printf ("ID\t%s\n", tokstr);
360 printf ("PUNCT\t%c\n", token);
363 #endif /* DEBUGGING */
365 /* Reads a token from the input file. */
369 /* Skip whitespace and check for end of file. */
377 fail ("%s: Unexpected end of file.", ifn);
380 if (*cp == '_' || isalnum ((unsigned char) *cp))
384 while (*cp == '_' || isalnum ((unsigned char) *cp))
385 *dest++ = toupper ((unsigned char) (*cp++));
393 while (*cp != '"' && *cp)
399 error ("Unterminated string literal.");
407 error ("Unterminated string literal.");
420 /* Force the current token to be an identifier token. */
425 error ("Identifier expected.");
428 /* Force the current token to be a string token. */
432 if (token != T_STRING)
433 error ("String expected.");
436 /* Checks whether the current token is the identifier S; if so, skips
437 the token and returns 1; otherwise, returns 0. */
439 match_id (const char *s)
441 if (token == T_ID && !strcmp (tokstr, s))
449 /* Checks whether the current token is T. If so, skips the token and
450 returns 1; otherwise, returns 0. */
462 /* Force the current token to be T, and skip it. */
467 error ("`%c' expected.", t);
473 /* Some specifiers have associated values. */
476 VAL_NONE, /* No value. */
477 VAL_INT, /* Integer value. */
478 VAL_DBL /* Floating point value. */
481 /* For those specifiers with values, the syntax of those values. */
484 VT_PLAIN, /* Unadorned value. */
485 VT_PAREN /* Value must be enclosed in parentheses. */
488 /* Forward definition. */
489 typedef struct specifier specifier;
491 /* A single setting. */
492 typedef struct setting setting;
495 specifier *parent; /* Owning specifier. */
496 setting *next; /* Next in the chain. */
497 char *specname; /* Name of the setting. */
498 int con; /* Sequence number. */
501 int valtype; /* One of VT_*. */
502 int value; /* One of VAL_*. */
503 int optvalue; /* 1=value is optional, 0=value is required. */
504 char *valname; /* Variable name for the value. */
505 char *restriction; /* !=NULL: expression specifying valid values. */
508 /* A single specifier. */
511 specifier *next; /* Next in the chain. */
512 char *varname; /* Variable name. */
513 setting *s; /* Associated settings. */
515 setting *def; /* Default setting. */
516 setting *omit_kw; /* Setting for which the keyword can be omitted. */
518 int index; /* Next array index. */
521 /* Subcommand types. */
524 SBC_PLAIN, /* The usual case. */
525 SBC_VARLIST, /* Variable list. */
526 SBC_INT, /* Integer value. */
527 SBC_PINT, /* Integer inside parentheses. */
528 SBC_DBL, /* Floating point value. */
529 SBC_INT_LIST, /* List of integers (?). */
530 SBC_DBL_LIST, /* List of floating points (?). */
531 SBC_CUSTOM, /* Custom. */
532 SBC_ARRAY, /* Array of boolean values. */
533 SBC_STRING, /* String value. */
534 SBC_VAR /* Single variable name. */
538 /* A single subcommand. */
539 typedef struct subcommand subcommand;
542 subcommand *next; /* Next in the chain. */
543 char *name; /* Subcommand name. */
544 subcommand_type type; /* One of SBC_*. */
545 int once; /* 1=Subcommand may appear only once. */
546 int narray; /* Index of next array element. */
547 const char *prefix; /* Prefix for variable and constant names. */
548 specifier *spec; /* Array of specifiers. */
550 /* SBC_STRING only. */
551 char *restriction; /* Expression restricting string length. */
552 char *message; /* Error message. */
555 /* Name of the command; i.e., DESCRIPTIVES. */
558 /* Short prefix for the command; i.e., `dsc_'. */
561 /* List of subcommands. */
562 subcommand *subcommands;
564 /* Default subcommand if any, or NULL. */
569 void parse_subcommands (void);
571 /* Parse an entire specification. */
575 /* Get the command name and prefix. */
576 if (token != T_STRING && token != T_ID)
577 error ("Command name expected.");
578 cmdname = xstrdup (tokstr);
582 prefix = xstrdup (tokstr);
587 /* Read all the subcommands. */
590 parse_subcommands ();
593 /* Parses a single setting into S, given subcommand information SBC
594 and specifier information SPEC. */
596 parse_setting (setting *s, specifier *spec)
600 if (match_token ('*'))
603 error ("Cannot have two settings with omittable keywords.");
608 if (match_token ('!'))
611 error ("Cannot have two default settings.");
617 s->specname = xstrdup (tokstr);
618 s->con = add_symbol (s->specname, 0, 0);
623 /* Parse setting value info if necessary. */
624 if (token != '/' && token != ';' && token != '.' && token != ',')
628 s->valtype = VT_PAREN;
632 s->valtype = VT_PLAIN;
634 s->optvalue = match_token ('*');
638 else if (match_id ("D"))
641 error ("`n' or `d' expected.");
646 s->valname = xstrdup (tokstr);
653 s->restriction = xstrdup (tokstr);
657 s->restriction = NULL;
659 if (s->valtype == VT_PAREN)
664 /* Parse a single specifier into SPEC, given subcommand information
667 parse_specifier (specifier *spec, subcommand *sbc)
672 spec->omit_kw = NULL;
673 spec->varname = NULL;
677 spec->varname = xstrdup (st_lower (tokstr));
681 /* Handle array elements. */
684 spec->index = sbc->narray;
685 if (sbc->type == SBC_ARRAY)
697 /* Parse all the settings. */
699 setting **s = &spec->s;
703 *s = xmalloc (sizeof (setting));
704 parse_setting (*s, spec);
705 if (token == ',' || token == ';' || token == '.')
714 /* Parse a list of specifiers for subcommand SBC. */
716 parse_specifiers (subcommand *sbc)
718 specifier **spec = &sbc->spec;
720 if (token == ';' || token == '.')
728 *spec = xmalloc (sizeof (specifier));
729 parse_specifier (*spec, sbc);
730 if (token == ';' || token == '.')
733 spec = &(*spec)->next;
735 (*spec)->next = NULL;
738 /* Parse a subcommand into SBC. */
740 parse_subcommand (subcommand *sbc)
742 if (match_token ('*'))
745 error ("Multiple default subcommands.");
749 sbc->once = match_token ('+');
752 sbc->name = xstrdup (tokstr);
756 sbc->type = SBC_PLAIN;
759 if (match_token ('['))
762 sbc->prefix = xstrdup (st_lower (tokstr));
768 sbc->type = SBC_ARRAY;
769 parse_specifiers (sbc);
773 if (match_token ('('))
776 sbc->prefix = xstrdup (st_lower (tokstr));
786 if (match_id ("VAR"))
788 if (match_id ("VARLIST"))
790 if (match_token ('('))
793 sbc->message = xstrdup (tokstr);
798 else sbc->message = NULL;
800 sbc->type = SBC_VARLIST;
802 else if (match_id ("INTEGER"))
803 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
804 else if (match_id ("PINT"))
805 sbc->type = SBC_PINT;
806 else if (match_id ("DOUBLE"))
807 sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
808 else if (match_id ("STRING"))
810 sbc->type = SBC_STRING;
811 if (token == T_STRING)
813 sbc->restriction = xstrdup (tokstr);
816 sbc->message = xstrdup (tokstr);
820 sbc->restriction = NULL;
822 else if (match_id ("CUSTOM"))
823 sbc->type = SBC_CUSTOM;
825 parse_specifiers (sbc);
829 /* Parse all the subcommands. */
831 parse_subcommands (void)
833 subcommand **sbc = &subcommands;
837 *sbc = xmalloc (sizeof (subcommand));
840 parse_subcommand (*sbc);
852 #define BASE_INDENT 2 /* Starting indent. */
853 #define INC_INDENT 2 /* Indent increment. */
855 /* Increment the indent. */
856 #define indent() indent += INC_INDENT
857 #define outdent() indent -= INC_INDENT
859 /* Size of the indent from the left margin. */
863 void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
866 /* Write line FORMAT to the output file, formatted as with printf,
867 indented `indent' characters from the left margin. If INDENTION is
868 greater than 0, indents BASE_INDENT * INDENTION characters after
869 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
870 * INDENTION characters _before_ writing the line. */
872 dump (int indention, const char *format, ...)
878 indent += BASE_INDENT * indention;
881 va_start (args, format);
882 for (i = 0; i < indent; i++)
884 vfprintf (out, format, args);
889 indent += BASE_INDENT * indention;
892 /* Write the structure members for specifier SPEC to the output file.
893 SBC is the including subcommand. */
895 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
898 dump (0, "long %s%s;", sbc->prefix, spec->varname);
903 for (s = spec->s; s; s = s->next)
905 if (s->value != VAL_NONE)
907 const char *typename;
909 assert (s->value == VAL_INT || s->value == VAL_DBL);
910 typename = s->value == VAL_INT ? "long" : "double";
912 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
918 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
920 is_keyword (const char *t)
922 static const char *kw[] =
924 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
925 "NE", "ALL", "BY", "TO", "WITH", 0,
929 for (cp = kw; *cp; cp++)
930 if (!strcmp (t, *cp))
935 /* Transforms a string NAME into a valid C identifier: makes
936 everything lowercase and maps nonalphabetic characters to
937 underscores. Returns a pointer to a static buffer. */
939 make_identifier (const char *name)
941 char *p = get_buffer ();
944 for (cp = p; *name; name++)
945 if (isalpha ((unsigned char) *name))
946 *cp++ = tolower ((unsigned char) (*name));
954 /* Writes the struct and enum declarations for the parser. */
956 dump_declarations (void)
960 /* Write out enums for all the identifiers in the symbol table. */
966 /* Note the squirmings necessary to make sure that the last enum
967 is not followed by a comma, as mandated by ANSI C89. */
968 for (sym = symtab, f = k = 0; sym; sym = sym->next)
969 if (!sym->unique && !is_keyword (sym->name))
973 dump (0, "/* Settings for subcommand specifiers. */");
980 buf = xmalloc (1024);
985 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
989 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
994 buf[strlen (buf) - 1] = 0;
1005 /* For every array subcommand, write out the associated enumerated
1010 for (sbc = subcommands; sbc; sbc = sbc->next)
1011 if (sbc->type == SBC_ARRAY && sbc->narray)
1013 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1021 for (spec = sbc->spec; spec; spec = spec->next)
1023 dump (0, "%s%s%s = %d,",
1024 st_upper (prefix), st_upper (sbc->prefix),
1025 st_upper (spec->varname), spec->index);
1027 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1035 /* Write out structure declaration. */
1039 dump (0, "/* %s structure. */", cmdname);
1040 dump (1, "struct cmd_%s", make_identifier (cmdname));
1042 for (sbc = subcommands; sbc; sbc = sbc->next)
1046 if (sbc != subcommands)
1049 dump (0, "/* %s subcommand. */", sbc->name);
1050 dump (0, "int sbc_%s;", st_lower (sbc->name));
1059 for (spec = sbc->spec; spec; spec = spec->next)
1063 if (sbc->type == SBC_PLAIN)
1064 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1068 dump (0, "int a_%s[%d];",
1069 st_lower (sbc->name), sbc->narray);
1074 dump_specifier_vars (spec, sbc);
1080 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1081 st_lower (sbc->name));
1082 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1083 st_lower (sbc->name));
1087 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1088 st_lower (sbc->name));
1092 dump (0, "char *s_%s;", st_lower (sbc->name));
1097 dump (0, "long n_%s;", st_lower (sbc->name));
1101 dump (0, "double n_%s;", st_lower (sbc->name));
1113 /* Write out prototypes for custom_*() functions as necessary. */
1118 for (sbc = subcommands; sbc; sbc = sbc->next)
1119 if (sbc->type == SBC_CUSTOM)
1124 dump (0, "/* Prototype for custom subcommands of %s. */",
1127 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1128 st_lower (prefix), st_lower (sbc->name),
1129 make_identifier (cmdname));
1136 /* Prototypes for parsing and freeing functions. */
1138 dump (0, "/* Command parsing functions. */");
1139 dump (0, "static int parse_%s (struct cmd_%s *);",
1140 make_identifier (cmdname), make_identifier (cmdname));
1141 dump (0, "static void free_%s (struct cmd_%s *);",
1142 make_identifier (cmdname), make_identifier (cmdname));
1147 /* Writes out code to initialize all the variables that need
1148 initialization for particular specifier SPEC inside subcommand SBC. */
1150 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1158 st_upper (prefix), find_symbol (spec->def->con)->name);
1161 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1167 for (s = spec->s; s; s = s->next)
1169 if (s->value != VAL_NONE)
1173 assert (s->value == VAL_INT || s->value == VAL_DBL);
1174 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1176 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1182 /* Write code to initialize all variables. */
1184 dump_vars_init (void)
1186 /* Loop through all the subcommands. */
1190 for (sbc = subcommands; sbc; sbc = sbc->next)
1194 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1209 for (spec = sbc->spec; spec; spec = spec->next)
1210 if (spec->s == NULL)
1212 if (sbc->type == SBC_PLAIN)
1213 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1216 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1217 st_lower (sbc->name), st_lower (sbc->name));
1222 dump_specifier_init (spec, sbc);
1227 dump (0, "p->%sn_%s = 0;",
1228 st_lower (sbc->prefix), st_lower (sbc->name));
1229 dump (0, "p->%sv_%s = NULL;",
1230 st_lower (sbc->prefix), st_lower (sbc->name));
1234 dump (0, "p->%sv_%s = NULL;",
1235 st_lower (sbc->prefix), st_lower (sbc->name));
1239 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1244 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1254 /* Return a pointer to a static buffer containing an expression that
1255 will match token T. */
1257 make_match (const char *t)
1267 sprintf (s, "lex_match (T_%s)", t);
1268 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1269 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1270 "|| lex_match_id (\"TRUE\"))");
1271 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1272 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1273 "|| lex_match_id (\"FALSE\"))");
1274 else if (isdigit ((unsigned char) t[0]))
1275 sprintf (s, "lex_match_int (%s)", t);
1277 sprintf (s, "lex_match_id (\"%s\")", t);
1282 /* Write out the parsing code for specifier SPEC within subcommand
1285 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1289 if (spec->omit_kw && spec->omit_kw->next)
1290 error ("Omittable setting is not last setting in `%s' specifier.",
1292 if (spec->omit_kw && spec->omit_kw->parent->next)
1293 error ("Default specifier is not in last specifier in `%s' "
1294 "subcommand.", sbc->name);
1296 for (s = spec->s; s; s = s->next)
1298 int first = spec == sbc->spec && s == spec->s;
1300 /* Match the setting's keyword. */
1301 if (spec->omit_kw == s)
1308 dump (1, "%s;", make_match (s->specname));
1311 dump (1, "%sif (%s)", first ? "" : "else ",
1312 make_match (s->specname));
1314 /* Handle values. */
1315 if (s->value == VAL_NONE)
1316 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1317 st_upper (prefix), find_symbol (s->con)->name);
1320 if (spec->omit_kw != s)
1324 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1325 st_upper (prefix), find_symbol (s->con)->name);
1327 if (s->valtype == VT_PAREN)
1331 dump (1, "if (lex_match ('('))");
1336 dump (1, "if (!lex_match ('('))");
1338 dump (0, "msg (SE, _(\"`(' expected after %s "
1339 "specifier of %s subcommand.\"));",
1340 s->specname, sbc->name);
1341 dump (0, "goto lossage;");
1347 if (s->value == VAL_INT)
1349 dump (1, "if (!lex_integer_p ())");
1351 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1352 "requires an integer argument.\"));",
1353 s->specname, sbc->name);
1354 dump (0, "goto lossage;");
1356 dump (-1, "p->%s%s = lex_integer ();",
1357 sbc->prefix, st_lower (s->valname));
1361 dump (1, "if (token != T_NUM)");
1363 dump (0, "msg (SE, _(\"Number expected after %s "
1364 "specifier of %s subcommand.\"));",
1365 s->specname, sbc->name);
1366 dump (0, "goto lossage;");
1368 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1369 st_lower (s->valname));
1376 str = xmalloc (MAX_TOK_LEN);
1377 str2 = xmalloc (MAX_TOK_LEN);
1378 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1379 sprintf (str, s->restriction, str2, str2, str2, str2,
1380 str2, str2, str2, str2);
1381 dump (1, "if (!(%s))", str);
1387 dump (0, "msg (SE, _(\"Bad argument for %s "
1388 "specifier of %s subcommand.\"));",
1389 s->specname, sbc->name);
1390 dump (0, "goto lossage;");
1395 dump (0, "lex_get ();");
1397 if (s->valtype == VT_PAREN)
1399 dump (1, "if (!lex_match (')'))");
1401 dump (0, "msg (SE, _(\"`)' expected after argument for "
1402 "%s specifier of %s.\"));",
1403 s->specname, sbc->name);
1404 dump (0, "goto lossage;");
1414 if (s != spec->omit_kw)
1418 if (s == spec->omit_kw)
1427 /* Write out the code to parse subcommand SBC. */
1429 dump_subcommand (const subcommand *sbc)
1431 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1435 dump (1, "while (token != '/' && token != '.')");
1441 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1444 dump_specifier_parse (spec, sbc);
1448 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1449 make_match (st_upper (spec->varname)));
1450 if (sbc->type == SBC_PLAIN)
1451 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1454 dump (0, "p->a_%s[%s%s%s] = 1;",
1455 st_lower (sbc->name),
1456 st_upper (prefix), st_upper (sbc->prefix),
1457 st_upper (spec->varname));
1467 /* This code first finds the last specifier in sbc. Then it
1468 finds the last setting within that last specifier. Either
1469 or both might be NULL. */
1482 if (spec && (!spec->s || !spec->omit_kw))
1486 dump (0, "lex_error (NULL);");
1487 dump (0, "goto lossage;");
1493 dump (0, "lex_match (',');");
1497 else if (sbc->type == SBC_VARLIST)
1499 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1501 st_lower (sbc->prefix), st_lower (sbc->name),
1502 st_lower (sbc->prefix), st_lower (sbc->name),
1503 sbc->message ? " |" : "",
1504 sbc->message ? sbc->message : "");
1505 dump (0, "goto lossage;");
1508 else if (sbc->type == SBC_VAR)
1510 dump (0, "p->%sv_%s = parse_variable ();",
1511 st_lower (sbc->prefix), st_lower (sbc->name));
1512 dump (1, "if (p->%sv_%s)",
1513 st_lower (sbc->prefix), st_lower (sbc->name));
1514 dump (0, "goto lossage;");
1517 else if (sbc->type == SBC_STRING)
1519 if (sbc->restriction)
1524 dump (1, "if (!lex_force_string ())");
1525 dump (0, "return 0;");
1527 if (sbc->restriction)
1529 dump (0, "x = ds_length (&tokstr);");
1530 dump (1, "if (!(%s))", sbc->restriction);
1532 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1533 sbc->name, sbc->message);
1534 dump (0, "goto lossage;");
1538 dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1539 st_lower (sbc->name));
1540 dump (0, "lex_get ();");
1541 if (sbc->restriction)
1544 else if (sbc->type == SBC_DBL)
1546 dump (1, "if (!lex_force_num ())");
1547 dump (0, "goto lossage;");
1548 dump (-1, "p->n_%s = lex_double ();", st_lower (sbc->name));
1549 dump (0, "lex_get();");
1551 else if (sbc->type == SBC_INT)
1553 dump (1, "if (!lex_force_int ())");
1554 dump (0, "goto lossage;");
1555 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1556 dump (0, "lex_get();");
1558 else if (sbc->type == SBC_PINT)
1560 dump (0, "lex_match ('(');");
1561 dump (1, "if (!lex_force_int ())");
1562 dump (0, "goto lossage;");
1563 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1564 dump (0, "lex_match (')');");
1566 else if (sbc->type == SBC_CUSTOM)
1568 dump (1, "switch (%scustom_%s (p))",
1569 st_lower (prefix), st_lower (sbc->name));
1571 dump (1, "case 0:");
1572 dump (0, "goto lossage;");
1573 dump (-1, "case 1:");
1576 dump (-1, "case 2:");
1578 dump (0, "lex_error (NULL);");
1579 dump (0, "goto lossage;");
1580 dump (-1, "default:");
1582 dump (0, "assert (0);");
1588 /* Write out entire parser. */
1596 dump (0, "static int");
1597 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1598 make_identifier (cmdname));
1603 dump (1, "for (;;)");
1607 if (def && (def->type == SBC_VARLIST))
1609 if (def->type == SBC_VARLIST)
1610 dump (1, "if (token == T_ID "
1611 "&& dict_lookup_var (default_dict, tokid) != NULL "
1612 "&& lex_look_ahead () != '=')");
1615 dump (0, "if ((token == T_ID "
1616 "&& dict_lookup_var (default_dict, tokid) "
1617 "&& lex_look_ahead () != '=')");
1618 dump (1, " || token == T_ALL)");
1621 dump (0, "p->sbc_%s++;", st_lower (def->name));
1622 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1624 st_lower (def->prefix), st_lower (def->name),
1625 st_lower (def->prefix), st_lower (def->name));
1626 dump (0, "goto lossage;");
1631 else if (def && def->type == SBC_CUSTOM)
1633 dump (1, "switch (%scustom_%s (p))",
1634 st_lower (prefix), st_lower (def->name));
1636 dump (1, "case 0:");
1637 dump (0, "goto lossage;");
1638 dump (-1, "case 1:");
1640 dump (0, "p->sbc_%s++;", st_lower (def->name));
1641 dump (0, "continue;");
1642 dump (-1, "case 2:");
1645 dump (-1, "default:");
1647 dump (0, "assert (0);");
1655 for (sbc = subcommands; sbc; sbc = sbc->next)
1657 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1661 dump (0, "lex_match ('=');");
1662 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1665 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1667 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1669 dump (0, "goto lossage;");
1673 dump_subcommand (sbc);
1679 dump (1, "if (!lex_match ('/'))");
1684 dump (1, "if (token != '.')");
1686 dump (0, "lex_error (_(\"expecting end of command\"));");
1687 dump (0, "goto lossage;");
1690 dump (-1, "return 1;");
1692 dump (-1, "lossage:");
1694 dump (0, "free_%s (p);", make_identifier (cmdname));
1695 dump (0, "return 0;");
1700 /* Write the output file header. */
1709 curtime = time (NULL);
1710 loctime = localtime (&curtime);
1711 timep = asctime (loctime);
1712 timep[strlen (timep) - 1] = 0;
1713 dump (0, "/* %s", ofn);
1715 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1716 dump (0, " Do not modify!");
1721 /* Write out commands to free variable state. */
1731 for (sbc = subcommands; sbc; sbc = sbc->next)
1732 if (sbc->type == SBC_STRING)
1735 dump (0, "static void");
1736 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1737 make_identifier (cmdname), used ? "" : " unused");
1740 for (sbc = subcommands; sbc; sbc = sbc->next)
1741 if (sbc->type == SBC_STRING)
1742 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1747 /* Returns the name of a directive found on the current input line, if
1748 any, or a null pointer if none found. */
1750 recognize_directive (void)
1752 static char directive[16];
1756 if (strncmp (sp, "/*", 2))
1758 sp = skip_ws (sp + 2);
1763 ep = strchr (sp, ')');
1769 memcpy (directive, sp, ep - sp);
1770 directive[ep - sp] = '\0';
1775 main (int argc, char *argv[])
1779 fail ("Syntax: q2c input.q output.c");
1782 in = fopen (ifn, "r");
1784 fail ("%s: open: %s.", ifn, strerror (errno));
1787 out = fopen (ofn, "w");
1789 fail ("%s: open: %s.", ofn, strerror (errno));
1792 buf = xmalloc (MAX_LINE_LEN);
1793 tokstr = xmalloc (MAX_TOK_LEN);
1798 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1801 const char *directive = recognize_directive ();
1802 if (directive == NULL)
1804 dump (0, "%s", buf);
1808 dump (0, "#line %d \"%s\"", oln - 1, ofn);
1809 if (!strcmp (directive, "specification"))
1811 /* Skip leading slash-star line. */
1817 /* Skip trailing star-slash line. */
1820 else if (!strcmp (directive, "headers"))
1824 dump (0, "#include <assert.h>");
1825 dump (0, "#include <stdlib.h>");
1826 dump (0, "#include \"alloc.h\"");
1827 dump (0, "#include \"error.h\"");
1828 dump (0, "#include \"lexer.h\"");
1829 dump (0, "#include \"str.h\"");
1830 dump (0, "#include \"var.h\"");
1833 else if (!strcmp (directive, "declarations"))
1834 dump_declarations ();
1835 else if (!strcmp (directive, "functions"))
1841 error ("unknown directive `%s'", directive);
1843 dump (0, "#line %d \"%s\"", ln + 1, ifn);
1846 return EXIT_SUCCESS;