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., 51 Franklin Street, Fifth Floor, Boston, MA
36 #define EXIT_SUCCESS 0
40 #define EXIT_FAILURE 1
44 #include "misc/strerror.c"
47 #include "debug-print.h"
49 /* Max length of an input line. */
50 #define MAX_LINE_LEN 1024
52 /* Max token length. */
53 #define MAX_TOK_LEN 1024
58 /* Have the input and output files been opened yet? */
61 /* Input, output files. */
64 /* Input, output file names. */
67 /* Input, output file line number. */
70 /* Input line buffer, current position. */
76 T_STRING = 256, /* String literal. */
77 T_ID = 257 /* Identifier. */
80 /* Current token: either one of the above, or a single character. */
83 /* Token string value. */
86 /* Utility functions. */
90 /* Close all open files and delete the output file, on failure. */
99 if (remove (ofn) == -1)
100 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
103 void hcf (void) NO_RETURN;
105 /* Terminate unsuccessfully. */
113 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
114 int error (const char *, ...) PRINTF_FORMAT (1, 2);
116 /* Output an error message and terminate unsuccessfully. */
118 fail (const char *format, ...)
122 va_start (args, format);
123 fprintf (stderr, "%s: ", program_name);
124 vfprintf (stderr, format, args);
125 fprintf (stderr, "\n");
131 /* Output a context-dependent error message and terminate
134 error (const char *format,...)
138 va_start (args, format);
139 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
140 vfprintf (stderr, format, args);
141 fprintf (stderr, "\n");
147 #define VME "virtual memory exhausted"
149 /* Allocate a block of SIZE bytes and return a pointer to its
152 xmalloc (size_t size)
161 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
166 /* Make a dynamically allocated copy of string S and return a pointer
167 to the first character. */
169 xstrdup (const char *s)
175 size = strlen (s) + 1;
179 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
185 /* Returns a pointer to one of 8 static buffers. The buffers are used
190 static char b[8][256];
199 /* Copies a string to a static buffer, converting it to lowercase in
200 the process, and returns a pointer to the static buffer. */
202 st_lower (const char *s)
206 p = cp = get_buffer ();
208 *cp++ = tolower ((unsigned char) (*s++));
214 /* Copies a string to a static buffer, converting it to uppercase in
215 the process, and returns a pointer to the static buffer. */
217 st_upper (const char *s)
221 p = cp = get_buffer ();
223 *cp++ = toupper ((unsigned char) (*s++));
229 /* Returns the address of the first non-whitespace character in S, or
230 the address of the null terminator if none. */
232 skip_ws (const char *s)
234 while (isspace ((unsigned char) *s))
239 /* Read one line from the input file into buf. Lines having special
240 formats are handled specially. */
245 if (0 == fgets (buf, MAX_LINE_LEN, in))
248 fail ("%s: fgets: %s", ifn, strerror (errno));
252 cp = strchr (buf, '\n');
260 /* Symbol table manager. */
262 /* Symbol table entry. */
263 typedef struct symbol symbol;
266 symbol *next; /* Next symbol in symbol table. */
267 char *name; /* Symbol name. */
268 int unique; /* 1=Name must be unique in this file. */
269 int ln; /* Line number of definition. */
270 int value; /* Symbol value. */
276 /* Add a symbol to the symbol table having name NAME, uniqueness
277 UNIQUE, and value VALUE. If a symbol having the same name is found
278 in the symbol table, its sequence number is returned and the symbol
279 table is not modified. Otherwise, the symbol is added and the next
280 available sequence number is returned. */
282 add_symbol (const char *name, int unique, int value)
287 sym = xmalloc (sizeof *sym);
288 sym->name = xstrdup (name);
289 sym->unique = unique;
302 if (!strcmp (iter->name, name))
306 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
308 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
325 /* Finds the symbol having given sequence number X within the symbol
326 table, and returns the associated symbol structure. */
333 while (x > 1 && iter)
343 /* Writes a printable representation of the current token to
351 printf ("STRING\t\"%s\"\n", tokstr);
354 printf ("ID\t%s\n", tokstr);
357 printf ("PUNCT\t%c\n", token);
360 #endif /* DEBUGGING */
362 /* Reads a token from the input file. */
366 /* Skip whitespace and check for end of file. */
374 fail ("%s: Unexpected end of file.", ifn);
382 while (*cp != '"' && *cp)
388 error ("Unterminated string literal.");
396 error ("Unterminated string literal.");
399 else if (*cp == '_' || isalnum ((unsigned char) *cp))
403 while (*cp == '_' || isalnum ((unsigned char) *cp))
404 *dest++ = toupper ((unsigned char) (*cp++));
417 /* Force the current token to be an identifier token. */
422 error ("Identifier expected.");
425 /* Force the current token to be a string token. */
429 if (token != T_STRING)
430 error ("String expected.");
433 /* Checks whether the current token is the identifier S; if so, skips
434 the token and returns 1; otherwise, returns 0. */
436 match_id (const char *s)
438 if (token == T_ID && !strcmp (tokstr, s))
446 /* Checks whether the current token is T. If so, skips the token and
447 returns 1; otherwise, returns 0. */
459 /* Force the current token to be T, and skip it. */
464 error ("`%c' expected.", t);
470 /* Some specifiers have associated values. */
473 VAL_NONE, /* No value. */
474 VAL_INT, /* Integer value. */
475 VAL_DBL /* Floating point value. */
478 /* For those specifiers with values, the syntax of those values. */
481 VT_PLAIN, /* Unadorned value. */
482 VT_PAREN /* Value must be enclosed in parentheses. */
485 /* Forward definition. */
486 typedef struct specifier specifier;
488 /* A single setting. */
489 typedef struct setting setting;
492 specifier *parent; /* Owning specifier. */
493 setting *next; /* Next in the chain. */
494 char *specname; /* Name of the setting. */
495 int con; /* Sequence number. */
498 int valtype; /* One of VT_*. */
499 int value; /* One of VAL_*. */
500 int optvalue; /* 1=value is optional, 0=value is required. */
501 char *valname; /* Variable name for the value. */
502 char *restriction; /* !=NULL: expression specifying valid values. */
505 /* A single specifier. */
508 specifier *next; /* Next in the chain. */
509 char *varname; /* Variable name. */
510 setting *s; /* Associated settings. */
512 setting *def; /* Default setting. */
513 setting *omit_kw; /* Setting for which the keyword can be omitted. */
515 int index; /* Next array index. */
518 /* Subcommand types. */
521 SBC_PLAIN, /* The usual case. */
522 SBC_VARLIST, /* Variable list. */
523 SBC_INT, /* Integer value. */
524 SBC_PINT, /* Integer inside parentheses. */
525 SBC_DBL, /* Floating point value. */
526 SBC_INT_LIST, /* List of integers (?). */
527 SBC_DBL_LIST, /* List of floating points (?). */
528 SBC_CUSTOM, /* Custom. */
529 SBC_ARRAY, /* Array of boolean values. */
530 SBC_STRING, /* String value. */
531 SBC_VAR /* Single variable name. */
537 ARITY_ONCE_EXACTLY, /* must occur exactly once */
538 ARITY_ONCE_ONLY, /* zero or once */
539 ARITY_MANY /* 0, 1, ... , inf */
542 /* A single subcommand. */
543 typedef struct subcommand subcommand;
546 subcommand *next; /* Next in the chain. */
547 char *name; /* Subcommand name. */
548 subcommand_type type; /* One of SBC_*. */
549 subcommand_arity arity; /* How many times should the subcommand occur*/
550 int narray; /* Index of next array element. */
551 const char *prefix; /* Prefix for variable and constant names. */
552 specifier *spec; /* Array of specifiers. */
554 /* SBC_STRING and SBC_INT only. */
555 char *restriction; /* Expression restricting string length. */
556 char *message; /* Error message. */
557 int translatable; /* Error message is translatable */
560 /* Name of the command; i.e., DESCRIPTIVES. */
563 /* Short prefix for the command; i.e., `dsc_'. */
566 /* List of subcommands. */
567 subcommand *subcommands;
569 /* Default subcommand if any, or NULL. */
574 void parse_subcommands (void);
576 /* Parse an entire specification. */
580 /* Get the command name and prefix. */
581 if (token != T_STRING && token != T_ID)
582 error ("Command name expected.");
583 cmdname = xstrdup (tokstr);
587 prefix = xstrdup (tokstr);
592 /* Read all the subcommands. */
595 parse_subcommands ();
598 /* Parses a single setting into S, given subcommand information SBC
599 and specifier information SPEC. */
601 parse_setting (setting *s, specifier *spec)
605 if (match_token ('*'))
608 error ("Cannot have two settings with omittable keywords.");
613 if (match_token ('!'))
616 error ("Cannot have two default settings.");
622 s->specname = xstrdup (tokstr);
623 s->con = add_symbol (s->specname, 0, 0);
628 /* Parse setting value info if necessary. */
629 if (token != '/' && token != ';' && token != '.' && token != ',')
633 s->valtype = VT_PAREN;
637 s->valtype = VT_PLAIN;
639 s->optvalue = match_token ('*');
643 else if (match_id ("D"))
646 error ("`n' or `d' expected.");
651 s->valname = xstrdup (tokstr);
658 s->restriction = xstrdup (tokstr);
662 s->restriction = NULL;
664 if (s->valtype == VT_PAREN)
669 /* Parse a single specifier into SPEC, given subcommand information
672 parse_specifier (specifier *spec, subcommand *sbc)
677 spec->omit_kw = NULL;
678 spec->varname = NULL;
682 spec->varname = xstrdup (st_lower (tokstr));
686 /* Handle array elements. */
689 spec->index = sbc->narray;
690 if (sbc->type == SBC_ARRAY)
702 if ( sbc->type == SBC_ARRAY && token == T_ID )
704 spec->varname = xstrdup (st_lower (tokstr));
705 spec->index = sbc->narray;
711 /* Parse all the settings. */
713 setting **s = &spec->s;
717 *s = xmalloc (sizeof **s);
718 parse_setting (*s, spec);
719 if (token == ',' || token == ';' || token == '.')
728 /* Parse a list of specifiers for subcommand SBC. */
730 parse_specifiers (subcommand *sbc)
732 specifier **spec = &sbc->spec;
734 if (token == ';' || token == '.')
742 *spec = xmalloc (sizeof **spec);
743 parse_specifier (*spec, sbc);
744 if (token == ';' || token == '.')
747 spec = &(*spec)->next;
749 (*spec)->next = NULL;
752 /* Parse a subcommand into SBC. */
754 parse_subcommand (subcommand *sbc)
756 sbc->arity = ARITY_MANY;
758 if (match_token ('*'))
761 error ("Multiple default subcommands.");
765 if ( match_token('+'))
766 sbc->arity = ARITY_ONCE_ONLY ;
767 else if (match_token('^'))
768 sbc->arity = ARITY_ONCE_EXACTLY ;
772 sbc->name = xstrdup (tokstr);
776 sbc->type = SBC_PLAIN;
778 sbc->translatable = 0;
780 if (match_token ('['))
783 sbc->prefix = xstrdup (st_lower (tokstr));
789 sbc->type = SBC_ARRAY;
790 parse_specifiers (sbc);
795 if (match_token ('('))
798 sbc->prefix = xstrdup (st_lower (tokstr));
808 if (match_id ("VAR"))
810 if (match_id ("VARLIST"))
812 if (match_token ('('))
815 sbc->message = xstrdup (tokstr);
820 else sbc->message = NULL;
822 sbc->type = SBC_VARLIST;
824 else if (match_id ("INTEGER"))
826 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
827 if ( token == T_STRING)
829 sbc->restriction = xstrdup (tokstr);
831 if ( match_id("N_") )
837 sbc->translatable = 1;
843 sbc->message = xstrdup (tokstr);
846 sbc->restriction = NULL;
848 else if (match_id ("PINT"))
849 sbc->type = SBC_PINT;
850 else if (match_id ("DOUBLE"))
852 if ( match_id ("LIST") )
853 sbc->type = SBC_DBL_LIST;
857 else if (match_id ("STRING"))
859 sbc->type = SBC_STRING;
860 if (token == T_STRING)
862 sbc->restriction = xstrdup (tokstr);
865 sbc->message = xstrdup (tokstr);
869 sbc->restriction = NULL;
871 else if (match_id ("CUSTOM"))
872 sbc->type = SBC_CUSTOM;
874 parse_specifiers (sbc);
878 /* Parse all the subcommands. */
880 parse_subcommands (void)
882 subcommand **sbc = &subcommands;
886 *sbc = xmalloc (sizeof **sbc);
889 parse_subcommand (*sbc);
901 #define BASE_INDENT 2 /* Starting indent. */
902 #define INC_INDENT 2 /* Indent increment. */
904 /* Increment the indent. */
905 #define indent() indent += INC_INDENT
906 #define outdent() indent -= INC_INDENT
908 /* Size of the indent from the left margin. */
911 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
913 /* Write line FORMAT to the output file, formatted as with printf,
914 indented `indent' characters from the left margin. If INDENTION is
915 greater than 0, indents BASE_INDENT * INDENTION characters after
916 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
917 * INDENTION characters _before_ writing the line. */
919 dump (int indention, const char *format, ...)
925 indent += BASE_INDENT * indention;
928 va_start (args, format);
929 for (i = 0; i < indent; i++)
931 vfprintf (out, format, args);
936 indent += BASE_INDENT * indention;
939 /* Write the structure members for specifier SPEC to the output file.
940 SBC is the including subcommand. */
942 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
945 dump (0, "long %s%s;", sbc->prefix, spec->varname);
950 for (s = spec->s; s; s = s->next)
952 if (s->value != VAL_NONE)
954 const char *typename;
956 assert (s->value == VAL_INT || s->value == VAL_DBL);
957 typename = s->value == VAL_INT ? "long" : "double";
959 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
965 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
967 is_keyword (const char *t)
969 static const char *kw[] =
971 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
972 "NE", "ALL", "BY", "TO", "WITH", 0,
976 for (cp = kw; *cp; cp++)
977 if (!strcmp (t, *cp))
982 /* Transforms a string NAME into a valid C identifier: makes
983 everything lowercase and maps nonalphabetic characters to
984 underscores. Returns a pointer to a static buffer. */
986 make_identifier (const char *name)
988 char *p = get_buffer ();
991 for (cp = p; *name; name++)
992 if (isalpha ((unsigned char) *name))
993 *cp++ = tolower ((unsigned char) (*name));
1001 /* Writes the struct and enum declarations for the parser. */
1003 dump_declarations (void)
1007 /* Write out enums for all the identifiers in the symbol table. */
1013 /* Note the squirmings necessary to make sure that the last enum
1014 is not followed by a comma, as mandated by ANSI C89. */
1015 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1016 if (!sym->unique && !is_keyword (sym->name))
1020 dump (0, "/* Settings for subcommand specifiers. */");
1027 buf = xmalloc (1024);
1032 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1036 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1041 buf[strlen (buf) - 1] = 0;
1052 /* Write out some type definitions */
1054 dump (0, "#define MAXLISTS 10");
1058 /* For every array subcommand, write out the associated enumerated
1063 for (sbc = subcommands; sbc; sbc = sbc->next)
1064 if (sbc->type == SBC_ARRAY && sbc->narray)
1066 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1074 for (spec = sbc->spec; spec; spec = spec->next)
1075 dump (0, "%s%s%s = %d,",
1076 st_upper (prefix), st_upper (sbc->prefix),
1077 st_upper (spec->varname), spec->index);
1079 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1087 /* Write out structure declaration. */
1091 dump (0, "/* %s structure. */", cmdname);
1092 dump (1, "struct cmd_%s", make_identifier (cmdname));
1094 for (sbc = subcommands; sbc; sbc = sbc->next)
1098 if (sbc != subcommands)
1101 dump (0, "/* %s subcommand. */", sbc->name);
1102 dump (0, "int sbc_%s;", st_lower (sbc->name));
1111 for (spec = sbc->spec; spec; spec = spec->next)
1115 if (sbc->type == SBC_PLAIN)
1116 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1120 dump (0, "int a_%s[%s%scount];",
1121 st_lower (sbc->name),
1123 st_upper (sbc->prefix)
1130 dump_specifier_vars (spec, sbc);
1136 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1137 st_lower (sbc->name));
1138 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1139 st_lower (sbc->name));
1143 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1144 st_lower (sbc->name));
1148 dump (0, "char *s_%s;", st_lower (sbc->name));
1153 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1157 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1161 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1162 st_lower(sbc->name));
1166 dump (0, "subc_list_int il_%s[MAXLISTS];",
1167 st_lower(sbc->name));
1180 /* Write out prototypes for custom_*() functions as necessary. */
1185 for (sbc = subcommands; sbc; sbc = sbc->next)
1186 if (sbc->type == SBC_CUSTOM)
1191 dump (0, "/* Prototype for custom subcommands of %s. */",
1194 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1195 st_lower (prefix), st_lower (sbc->name),
1196 make_identifier (cmdname));
1203 /* Prototypes for parsing and freeing functions. */
1205 dump (0, "/* Command parsing functions. */");
1206 dump (0, "static int parse_%s (struct cmd_%s *);",
1207 make_identifier (cmdname), make_identifier (cmdname));
1208 dump (0, "static void free_%s (struct cmd_%s *);",
1209 make_identifier (cmdname), make_identifier (cmdname));
1214 /* Writes out code to initialize all the variables that need
1215 initialization for particular specifier SPEC inside subcommand SBC. */
1217 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1225 st_upper (prefix), find_symbol (spec->def->con)->name);
1228 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1234 for (s = spec->s; s; s = s->next)
1236 if (s->value != VAL_NONE)
1240 assert (s->value == VAL_INT || s->value == VAL_DBL);
1241 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1243 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1249 /* Write code to initialize all variables. */
1251 dump_vars_init (int persistent)
1253 /* Loop through all the subcommands. */
1257 for (sbc = subcommands; sbc; sbc = sbc->next)
1261 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1272 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1273 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1274 st_lower (sbc->name)
1282 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1283 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1296 for (spec = sbc->spec; spec; spec = spec->next)
1297 if (spec->s == NULL)
1299 if (sbc->type == SBC_PLAIN)
1300 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1303 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1304 st_lower (sbc->name), st_lower (sbc->name));
1309 dump_specifier_init (spec, sbc);
1314 dump (0, "p->%sn_%s = 0;",
1315 st_lower (sbc->prefix), st_lower (sbc->name));
1316 dump (0, "p->%sv_%s = NULL;",
1317 st_lower (sbc->prefix), st_lower (sbc->name));
1321 dump (0, "p->%sv_%s = NULL;",
1322 st_lower (sbc->prefix), st_lower (sbc->name));
1326 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1333 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1334 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1346 /* Return a pointer to a static buffer containing an expression that
1347 will match token T. */
1349 make_match (const char *t)
1359 sprintf (s, "lex_match (T_%s)", t);
1360 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1361 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1362 "|| lex_match_id (\"TRUE\"))");
1363 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1364 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1365 "|| lex_match_id (\"FALSE\"))");
1366 else if (isdigit ((unsigned char) t[0]))
1367 sprintf (s, "lex_match_int (%s)", t);
1369 sprintf (s, "lex_match_id (\"%s\")", t);
1374 /* Write out the parsing code for specifier SPEC within subcommand
1377 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1381 if (spec->omit_kw && spec->omit_kw->next)
1382 error ("Omittable setting is not last setting in `%s' specifier.",
1384 if (spec->omit_kw && spec->omit_kw->parent->next)
1385 error ("Default specifier is not in last specifier in `%s' "
1386 "subcommand.", sbc->name);
1388 for (s = spec->s; s; s = s->next)
1390 int first = spec == sbc->spec && s == spec->s;
1392 /* Match the setting's keyword. */
1393 if (spec->omit_kw == s)
1400 dump (1, "%s;", make_match (s->specname));
1403 dump (1, "%sif (%s)", first ? "" : "else ",
1404 make_match (s->specname));
1407 /* Handle values. */
1408 if (s->value == VAL_NONE)
1409 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1410 st_upper (prefix), find_symbol (s->con)->name);
1413 if (spec->omit_kw != s)
1418 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1419 st_upper (prefix), find_symbol (s->con)->name);
1421 if ( sbc->type == SBC_ARRAY )
1422 dump (0, "p->a_%s[%s%s%s] = 1;",
1423 st_lower (sbc->name),
1424 st_upper (prefix), st_upper (sbc->prefix),
1425 st_upper (spec->varname));
1429 if (s->valtype == VT_PAREN)
1433 dump (1, "if (lex_match ('('))");
1438 dump (1, "if (!lex_match ('('))");
1440 dump (0, "msg (SE, _(\"`(' expected after %s "
1441 "specifier of %s subcommand.\"));",
1442 s->specname, sbc->name);
1443 dump (0, "goto lossage;");
1449 if (s->value == VAL_INT)
1451 dump (1, "if (!lex_is_integer ())");
1453 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1454 "requires an integer argument.\"));",
1455 s->specname, sbc->name);
1456 dump (0, "goto lossage;");
1458 dump (-1, "p->%s%s = lex_integer ();",
1459 sbc->prefix, st_lower (s->valname));
1463 dump (1, "if (!lex_is_number ())");
1465 dump (0, "msg (SE, _(\"Number expected after %s "
1466 "specifier of %s subcommand.\"));",
1467 s->specname, sbc->name);
1468 dump (0, "goto lossage;");
1470 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1471 st_lower (s->valname));
1478 str = xmalloc (MAX_TOK_LEN);
1479 str2 = xmalloc (MAX_TOK_LEN);
1480 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1481 sprintf (str, s->restriction, str2, str2, str2, str2,
1482 str2, str2, str2, str2);
1483 dump (1, "if (!(%s))", str);
1489 dump (0, "msg (SE, _(\"Bad argument for %s "
1490 "specifier of %s subcommand.\"));",
1491 s->specname, sbc->name);
1492 dump (0, "goto lossage;");
1497 dump (0, "lex_get ();");
1499 if (s->valtype == VT_PAREN)
1501 dump (1, "if (!lex_match (')'))");
1503 dump (0, "msg (SE, _(\"`)' expected after argument for "
1504 "%s specifier of %s.\"));",
1505 s->specname, sbc->name);
1506 dump (0, "goto lossage;");
1516 if (s != spec->omit_kw)
1520 if (s == spec->omit_kw)
1529 /* Write out the code to parse subcommand SBC. */
1531 dump_subcommand (const subcommand *sbc)
1533 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1537 dump (1, "while (token != '/' && token != '.')");
1543 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1546 dump_specifier_parse (spec, sbc);
1550 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1551 make_match (st_upper (spec->varname)));
1552 if (sbc->type == SBC_PLAIN)
1553 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1556 dump (0, "p->a_%s[%s%s%s] = 1;",
1557 st_lower (sbc->name),
1558 st_upper (prefix), st_upper (sbc->prefix),
1559 st_upper (spec->varname));
1569 /* This code first finds the last specifier in sbc. Then it
1570 finds the last setting within that last specifier. Either
1571 or both might be NULL. */
1584 if (spec && (!spec->s || !spec->omit_kw))
1588 dump (0, "lex_error (NULL);");
1589 dump (0, "goto lossage;");
1595 dump (0, "lex_match (',');");
1599 else if (sbc->type == SBC_VARLIST)
1601 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1603 st_lower (sbc->prefix), st_lower (sbc->name),
1604 st_lower (sbc->prefix), st_lower (sbc->name),
1605 sbc->message ? " |" : "",
1606 sbc->message ? sbc->message : "");
1607 dump (0, "goto lossage;");
1610 else if (sbc->type == SBC_VAR)
1612 dump (0, "p->%sv_%s = parse_variable ();",
1613 st_lower (sbc->prefix), st_lower (sbc->name));
1614 dump (1, "if (!p->%sv_%s)",
1615 st_lower (sbc->prefix), st_lower (sbc->name));
1616 dump (0, "goto lossage;");
1619 else if (sbc->type == SBC_STRING)
1621 if (sbc->restriction)
1626 dump (1, "if (!lex_force_string ())");
1627 dump (0, "return 0;");
1629 if (sbc->restriction)
1631 dump (0, "x = ds_length (&tokstr);");
1632 dump (1, "if (!(%s))", sbc->restriction);
1634 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1635 sbc->name, sbc->message);
1636 dump (0, "goto lossage;");
1640 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1641 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1642 st_lower (sbc->name));
1643 dump (0, "lex_get ();");
1644 if (sbc->restriction)
1647 else if (sbc->type == SBC_DBL)
1649 dump (1, "if (!lex_force_num ())");
1650 dump (0, "goto lossage;");
1651 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1652 st_lower (sbc->name), st_lower (sbc->name) );
1653 dump (0, "lex_get();");
1655 else if (sbc->type == SBC_INT)
1659 dump (1, "if (!lex_force_int ())");
1660 dump (0, "goto lossage;");
1661 dump (-1, "x = lex_integer ();");
1662 dump (0, "lex_get();");
1663 if (sbc->restriction)
1666 dump (1, "if (!(%s))", sbc->restriction);
1668 sprintf(buf,sbc->message,sbc->name);
1669 if ( sbc->translatable )
1670 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1672 dump (0, "msg (SE, \"%s\");",buf);
1673 dump (0, "goto lossage;");
1676 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1679 else if (sbc->type == SBC_PINT)
1681 dump (0, "lex_match ('(');");
1682 dump (1, "if (!lex_force_int ())");
1683 dump (0, "goto lossage;");
1684 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1685 dump (0, "lex_match (')');");
1687 else if (sbc->type == SBC_DBL_LIST)
1689 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1691 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1692 dump (0, "goto lossage;");
1695 dump (1, "while (token != '/' && token != '.')");
1697 dump (0, "lex_match(',');");
1698 dump (0, "if (!lex_force_num ())");
1700 dump (0, "goto lossage;");
1703 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1704 st_lower (sbc->name),st_lower (sbc->name)
1707 dump (0, "lex_get();");
1711 else if (sbc->type == SBC_CUSTOM)
1713 dump (1, "switch (%scustom_%s (p))",
1714 st_lower (prefix), st_lower (sbc->name));
1716 dump (1, "case 0:");
1717 dump (0, "goto lossage;");
1718 dump (-1, "case 1:");
1721 dump (-1, "case 2:");
1723 dump (0, "lex_error (NULL);");
1724 dump (0, "goto lossage;");
1725 dump (-1, "default:");
1727 dump (0, "assert (0);");
1733 /* Write out entire parser. */
1735 dump_parser (int persistent)
1741 dump (0, "static int");
1742 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1743 make_identifier (cmdname));
1746 dump_vars_init (persistent);
1748 dump (1, "for (;;)");
1752 if (def && (def->type == SBC_VARLIST))
1754 if (def->type == SBC_VARLIST)
1755 dump (1, "if (token == T_ID "
1756 "&& dict_lookup_var (default_dict, tokid) != NULL "
1757 "&& lex_look_ahead () != '=')");
1760 dump (0, "if ((token == T_ID "
1761 "&& dict_lookup_var (default_dict, tokid) "
1762 "&& lex_look_ahead () != '=')");
1763 dump (1, " || token == T_ALL)");
1766 dump (0, "p->sbc_%s++;", st_lower (def->name));
1767 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1769 st_lower (def->prefix), st_lower (def->name),
1770 st_lower (def->prefix), st_lower (def->name));
1771 dump (0, "goto lossage;");
1776 else if (def && def->type == SBC_CUSTOM)
1778 dump (1, "switch (%scustom_%s (p))",
1779 st_lower (prefix), st_lower (def->name));
1781 dump (1, "case 0:");
1782 dump (0, "goto lossage;");
1783 dump (-1, "case 1:");
1785 dump (0, "p->sbc_%s++;", st_lower (def->name));
1786 dump (0, "continue;");
1787 dump (-1, "case 2:");
1790 dump (-1, "default:");
1792 dump (0, "assert (0);");
1800 for (sbc = subcommands; sbc; sbc = sbc->next)
1802 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1806 dump (0, "lex_match ('=');");
1807 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1808 if (sbc->arity != ARITY_MANY)
1810 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1812 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1814 dump (0, "goto lossage;");
1818 dump_subcommand (sbc);
1825 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1826 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1829 dump (0, "lex_match ('=');");
1831 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1832 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1834 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1835 dump(0,"set_cmd_algorithm(ENHANCED);");
1842 dump (1, "if (!lex_match ('/'))");
1847 dump (1, "if (token != '.')");
1849 dump (0, "lex_error (_(\"expecting end of command\"));");
1850 dump (0, "goto lossage;");
1857 /* Check that mandatory subcommands have been specified */
1860 for (sbc = subcommands; sbc; sbc = sbc->next)
1863 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1865 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1867 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1869 dump (0, "goto lossage;");
1876 dump (-1, "return 1;");
1878 dump (-1, "lossage:");
1880 dump (0, "free_%s (p);", make_identifier (cmdname));
1881 dump (0, "return 0;");
1887 /* Write the output file header. */
1896 curtime = time (NULL);
1897 loctime = localtime (&curtime);
1898 timep = asctime (loctime);
1899 timep[strlen (timep) - 1] = 0;
1900 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1902 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1903 dump (0, " Do not modify!");
1907 /* Write out commands to free variable state. */
1909 dump_free (int persistent)
1919 for (sbc = subcommands; sbc; sbc = sbc->next)
1921 if (sbc->type == SBC_STRING)
1923 if (sbc->type == SBC_DBL_LIST)
1929 dump (0, "static void");
1930 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1931 make_identifier (cmdname), used ? "" : " UNUSED");
1937 for (sbc = subcommands; sbc; sbc = sbc->next)
1942 dump (0, "free (p->v_variables);");
1945 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1949 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
1950 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1965 /* Returns the name of a directive found on the current input line, if
1966 any, or a null pointer if none found. */
1968 recognize_directive (void)
1970 static char directive[16];
1974 if (strncmp (sp, "/*", 2))
1976 sp = skip_ws (sp + 2);
1981 ep = strchr (sp, ')');
1987 memcpy (directive, sp, ep - sp);
1988 directive[ep - sp] = '\0';
1993 main (int argc, char *argv[])
1995 program_name = argv[0];
1997 fail ("Syntax: q2c input.q output.c");
2000 in = fopen (ifn, "r");
2002 fail ("%s: open: %s.", ifn, strerror (errno));
2005 out = fopen (ofn, "w");
2007 fail ("%s: open: %s.", ofn, strerror (errno));
2010 buf = xmalloc (MAX_LINE_LEN);
2011 tokstr = xmalloc (MAX_TOK_LEN);
2017 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2020 const char *directive = recognize_directive ();
2021 if (directive == NULL)
2023 dump (0, "%s", buf);
2027 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2028 if (!strcmp (directive, "specification"))
2030 /* Skip leading slash-star line. */
2036 /* Skip trailing star-slash line. */
2039 else if (!strcmp (directive, "headers"))
2043 dump (0, "#include <stdlib.h>");
2044 dump (0, "#include \"alloc.h\"");
2045 dump (0, "#include \"error.h\"");
2046 dump (0, "#include \"lexer.h\"");
2047 dump (0, "#include \"settings.h\"");
2048 dump (0, "#include \"str.h\"");
2049 dump (0, "#include \"subclist.h\"");
2050 dump (0, "#include \"var.h\"");
2053 dump (0, "#include \"gettext.h\"");
2054 dump (0, "#define _(msgid) gettext (msgid)");
2057 else if (!strcmp (directive, "declarations"))
2058 dump_declarations ();
2059 else if (!strcmp (directive, "functions"))
2064 else if (!strcmp (directive, "_functions"))
2070 error ("unknown directive `%s'", directive);
2072 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2077 return EXIT_SUCCESS;