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
45 #include "misc/strerror.c"
49 #include "debug-print.h"
51 /* Max length of an input line. */
52 #define MAX_LINE_LEN 1024
54 /* Max token length. */
55 #define MAX_TOK_LEN 1024
60 /* Have the input and output files been opened yet? */
63 /* Input, output files. */
66 /* Input, output file names. */
69 /* Input, output file line number. */
72 /* Input line buffer, current position. */
78 T_STRING = 256, /* String literal. */
79 T_ID = 257 /* Identifier. */
82 /* Current token: either one of the above, or a single character. */
85 /* Token string value. */
88 /* Utility functions. */
92 /* Close all open files and delete the output file, on failure. */
101 if (remove (ofn) == -1)
102 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
105 void hcf (void) NO_RETURN;
107 /* Terminate unsuccessfully. */
115 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
116 int error (const char *, ...) PRINTF_FORMAT (1, 2);
118 /* Output an error message and terminate unsuccessfully. */
120 fail (const char *format, ...)
124 va_start (args, format);
125 fprintf (stderr, "%s: ", program_name);
126 vfprintf (stderr, format, args);
127 fprintf (stderr, "\n");
133 /* Output a context-dependent error message and terminate
136 error (const char *format,...)
140 va_start (args, format);
141 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
142 vfprintf (stderr, format, args);
143 fprintf (stderr, "\n");
149 #define VME "virtual memory exhausted"
151 /* Allocate a block of SIZE bytes and return a pointer to its
154 xmalloc (size_t size)
163 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
168 /* Make a dynamically allocated copy of string S and return a pointer
169 to the first character. */
171 xstrdup (const char *s)
177 size = strlen (s) + 1;
181 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
187 /* Returns a pointer to one of 8 static buffers. The buffers are used
192 static char b[8][256];
201 /* Copies a string to a static buffer, converting it to lowercase in
202 the process, and returns a pointer to the static buffer. */
204 st_lower (const char *s)
208 p = cp = get_buffer ();
210 *cp++ = tolower ((unsigned char) (*s++));
216 /* Copies a string to a static buffer, converting it to uppercase in
217 the process, and returns a pointer to the static buffer. */
219 st_upper (const char *s)
223 p = cp = get_buffer ();
225 *cp++ = toupper ((unsigned char) (*s++));
231 /* Returns the address of the first non-whitespace character in S, or
232 the address of the null terminator if none. */
234 skip_ws (const char *s)
236 while (isspace ((unsigned char) *s))
241 /* Read one line from the input file into buf. Lines having special
242 formats are handled specially. */
247 if (0 == fgets (buf, MAX_LINE_LEN, in))
250 fail ("%s: fgets: %s", ifn, strerror (errno));
254 cp = strchr (buf, '\n');
262 /* Symbol table manager. */
264 /* Symbol table entry. */
265 typedef struct symbol symbol;
268 symbol *next; /* Next symbol in symbol table. */
269 char *name; /* Symbol name. */
270 int unique; /* 1=Name must be unique in this file. */
271 int ln; /* Line number of definition. */
272 int value; /* Symbol value. */
278 /* Add a symbol to the symbol table having name NAME, uniqueness
279 UNIQUE, and value VALUE. If a symbol having the same name is found
280 in the symbol table, its sequence number is returned and the symbol
281 table is not modified. Otherwise, the symbol is added and the next
282 available sequence number is returned. */
284 add_symbol (const char *name, int unique, int value)
289 sym = xmalloc (sizeof *sym);
290 sym->name = xstrdup (name);
291 sym->unique = unique;
304 if (!strcmp (iter->name, name))
308 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
310 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
327 /* Finds the symbol having given sequence number X within the symbol
328 table, and returns the associated symbol structure. */
335 while (x > 1 && iter)
345 /* Writes a printable representation of the current token to
353 printf ("STRING\t\"%s\"\n", tokstr);
356 printf ("ID\t%s\n", tokstr);
359 printf ("PUNCT\t%c\n", token);
362 #endif /* DEBUGGING */
364 /* Reads a token from the input file. */
368 /* Skip whitespace and check for end of file. */
376 fail ("%s: Unexpected end of file.", ifn);
384 while (*cp != '"' && *cp)
390 error ("Unterminated string literal.");
398 error ("Unterminated string literal.");
401 else if (*cp == '_' || isalnum ((unsigned char) *cp))
405 while (*cp == '_' || isalnum ((unsigned char) *cp))
406 *dest++ = toupper ((unsigned char) (*cp++));
419 /* Force the current token to be an identifier token. */
424 error ("Identifier expected.");
427 /* Force the current token to be a string token. */
431 if (token != T_STRING)
432 error ("String expected.");
435 /* Checks whether the current token is the identifier S; if so, skips
436 the token and returns 1; otherwise, returns 0. */
438 match_id (const char *s)
440 if (token == T_ID && !strcmp (tokstr, s))
448 /* Checks whether the current token is T. If so, skips the token and
449 returns 1; otherwise, returns 0. */
461 /* Force the current token to be T, and skip it. */
466 error ("`%c' expected.", t);
472 /* Some specifiers have associated values. */
475 VAL_NONE, /* No value. */
476 VAL_INT, /* Integer value. */
477 VAL_DBL /* Floating point value. */
480 /* For those specifiers with values, the syntax of those values. */
483 VT_PLAIN, /* Unadorned value. */
484 VT_PAREN /* Value must be enclosed in parentheses. */
487 /* Forward definition. */
488 typedef struct specifier specifier;
490 /* A single setting. */
491 typedef struct setting setting;
494 specifier *parent; /* Owning specifier. */
495 setting *next; /* Next in the chain. */
496 char *specname; /* Name of the setting. */
497 int con; /* Sequence number. */
500 int valtype; /* One of VT_*. */
501 int value; /* One of VAL_*. */
502 int optvalue; /* 1=value is optional, 0=value is required. */
503 char *valname; /* Variable name for the value. */
504 char *restriction; /* !=NULL: expression specifying valid values. */
507 /* A single specifier. */
510 specifier *next; /* Next in the chain. */
511 char *varname; /* Variable name. */
512 setting *s; /* Associated settings. */
514 setting *def; /* Default setting. */
515 setting *omit_kw; /* Setting for which the keyword can be omitted. */
517 int index; /* Next array index. */
520 /* Subcommand types. */
523 SBC_PLAIN, /* The usual case. */
524 SBC_VARLIST, /* Variable list. */
525 SBC_INT, /* Integer value. */
526 SBC_PINT, /* Integer inside parentheses. */
527 SBC_DBL, /* Floating point value. */
528 SBC_INT_LIST, /* List of integers (?). */
529 SBC_DBL_LIST, /* List of floating points (?). */
530 SBC_CUSTOM, /* Custom. */
531 SBC_ARRAY, /* Array of boolean values. */
532 SBC_STRING, /* String value. */
533 SBC_VAR /* Single variable name. */
539 ARITY_ONCE_EXACTLY, /* must occur exactly once */
540 ARITY_ONCE_ONLY, /* zero or once */
541 ARITY_MANY /* 0, 1, ... , inf */
544 /* A single subcommand. */
545 typedef struct subcommand subcommand;
548 subcommand *next; /* Next in the chain. */
549 char *name; /* Subcommand name. */
550 subcommand_type type; /* One of SBC_*. */
551 subcommand_arity arity; /* How many times should the subcommand occur*/
552 int narray; /* Index of next array element. */
553 const char *prefix; /* Prefix for variable and constant names. */
554 specifier *spec; /* Array of specifiers. */
556 /* SBC_STRING and SBC_INT only. */
557 char *restriction; /* Expression restricting string length. */
558 char *message; /* Error message. */
559 int translatable; /* Error message is translatable */
562 /* Name of the command; i.e., DESCRIPTIVES. */
565 /* Short prefix for the command; i.e., `dsc_'. */
568 /* List of subcommands. */
569 subcommand *subcommands;
571 /* Default subcommand if any, or NULL. */
576 void parse_subcommands (void);
578 /* Parse an entire specification. */
582 /* Get the command name and prefix. */
583 if (token != T_STRING && token != T_ID)
584 error ("Command name expected.");
585 cmdname = xstrdup (tokstr);
589 prefix = xstrdup (tokstr);
594 /* Read all the subcommands. */
597 parse_subcommands ();
600 /* Parses a single setting into S, given subcommand information SBC
601 and specifier information SPEC. */
603 parse_setting (setting *s, specifier *spec)
607 if (match_token ('*'))
610 error ("Cannot have two settings with omittable keywords.");
615 if (match_token ('!'))
618 error ("Cannot have two default settings.");
624 s->specname = xstrdup (tokstr);
625 s->con = add_symbol (s->specname, 0, 0);
630 /* Parse setting value info if necessary. */
631 if (token != '/' && token != ';' && token != '.' && token != ',')
635 s->valtype = VT_PAREN;
639 s->valtype = VT_PLAIN;
641 s->optvalue = match_token ('*');
645 else if (match_id ("D"))
648 error ("`n' or `d' expected.");
653 s->valname = xstrdup (tokstr);
660 s->restriction = xstrdup (tokstr);
664 s->restriction = NULL;
666 if (s->valtype == VT_PAREN)
671 /* Parse a single specifier into SPEC, given subcommand information
674 parse_specifier (specifier *spec, subcommand *sbc)
679 spec->omit_kw = NULL;
680 spec->varname = NULL;
684 spec->varname = xstrdup (st_lower (tokstr));
688 /* Handle array elements. */
691 spec->index = sbc->narray;
692 if (sbc->type == SBC_ARRAY)
704 if ( sbc->type == SBC_ARRAY && token == T_ID )
706 spec->varname = xstrdup (st_lower (tokstr));
707 spec->index = sbc->narray;
713 /* Parse all the settings. */
715 setting **s = &spec->s;
719 *s = xmalloc (sizeof **s);
720 parse_setting (*s, spec);
721 if (token == ',' || token == ';' || token == '.')
730 /* Parse a list of specifiers for subcommand SBC. */
732 parse_specifiers (subcommand *sbc)
734 specifier **spec = &sbc->spec;
736 if (token == ';' || token == '.')
744 *spec = xmalloc (sizeof **spec);
745 parse_specifier (*spec, sbc);
746 if (token == ';' || token == '.')
749 spec = &(*spec)->next;
751 (*spec)->next = NULL;
754 /* Parse a subcommand into SBC. */
756 parse_subcommand (subcommand *sbc)
758 sbc->arity = ARITY_MANY;
760 if (match_token ('*'))
763 error ("Multiple default subcommands.");
767 if ( match_token('+'))
768 sbc->arity = ARITY_ONCE_ONLY ;
769 else if (match_token('^'))
770 sbc->arity = ARITY_ONCE_EXACTLY ;
774 sbc->name = xstrdup (tokstr);
778 sbc->type = SBC_PLAIN;
780 sbc->translatable = 0;
782 if (match_token ('['))
785 sbc->prefix = xstrdup (st_lower (tokstr));
791 sbc->type = SBC_ARRAY;
792 parse_specifiers (sbc);
797 if (match_token ('('))
800 sbc->prefix = xstrdup (st_lower (tokstr));
810 if (match_id ("VAR"))
812 if (match_id ("VARLIST"))
814 if (match_token ('('))
817 sbc->message = xstrdup (tokstr);
822 else sbc->message = NULL;
824 sbc->type = SBC_VARLIST;
826 else if (match_id ("INTEGER"))
828 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
829 if ( token == T_STRING)
831 sbc->restriction = xstrdup (tokstr);
833 if ( match_id("N_") )
839 sbc->translatable = 1;
845 sbc->message = xstrdup (tokstr);
848 sbc->restriction = NULL;
850 else if (match_id ("PINT"))
851 sbc->type = SBC_PINT;
852 else if (match_id ("DOUBLE"))
854 if ( match_id ("LIST") )
855 sbc->type = SBC_DBL_LIST;
859 else if (match_id ("STRING"))
861 sbc->type = SBC_STRING;
862 if (token == T_STRING)
864 sbc->restriction = xstrdup (tokstr);
867 sbc->message = xstrdup (tokstr);
871 sbc->restriction = NULL;
873 else if (match_id ("CUSTOM"))
874 sbc->type = SBC_CUSTOM;
876 parse_specifiers (sbc);
880 /* Parse all the subcommands. */
882 parse_subcommands (void)
884 subcommand **sbc = &subcommands;
888 *sbc = xmalloc (sizeof **sbc);
891 parse_subcommand (*sbc);
903 #define BASE_INDENT 2 /* Starting indent. */
904 #define INC_INDENT 2 /* Indent increment. */
906 /* Increment the indent. */
907 #define indent() indent += INC_INDENT
908 #define outdent() indent -= INC_INDENT
910 /* Size of the indent from the left margin. */
913 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
915 /* Write line FORMAT to the output file, formatted as with printf,
916 indented `indent' characters from the left margin. If INDENTION is
917 greater than 0, indents BASE_INDENT * INDENTION characters after
918 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
919 * INDENTION characters _before_ writing the line. */
921 dump (int indention, const char *format, ...)
927 indent += BASE_INDENT * indention;
930 va_start (args, format);
931 for (i = 0; i < indent; i++)
933 vfprintf (out, format, args);
938 indent += BASE_INDENT * indention;
941 /* Write the structure members for specifier SPEC to the output file.
942 SBC is the including subcommand. */
944 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
947 dump (0, "long %s%s;", sbc->prefix, spec->varname);
952 for (s = spec->s; s; s = s->next)
954 if (s->value != VAL_NONE)
956 const char *typename;
958 assert (s->value == VAL_INT || s->value == VAL_DBL);
959 typename = s->value == VAL_INT ? "long" : "double";
961 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
967 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
969 is_keyword (const char *t)
971 static const char *kw[] =
973 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
974 "NE", "ALL", "BY", "TO", "WITH", 0,
978 for (cp = kw; *cp; cp++)
979 if (!strcmp (t, *cp))
984 /* Transforms a string NAME into a valid C identifier: makes
985 everything lowercase and maps nonalphabetic characters to
986 underscores. Returns a pointer to a static buffer. */
988 make_identifier (const char *name)
990 char *p = get_buffer ();
993 for (cp = p; *name; name++)
994 if (isalpha ((unsigned char) *name))
995 *cp++ = tolower ((unsigned char) (*name));
1003 /* Writes the struct and enum declarations for the parser. */
1005 dump_declarations (void)
1009 /* Write out enums for all the identifiers in the symbol table. */
1015 /* Note the squirmings necessary to make sure that the last enum
1016 is not followed by a comma, as mandated by ANSI C89. */
1017 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1018 if (!sym->unique && !is_keyword (sym->name))
1022 dump (0, "/* Settings for subcommand specifiers. */");
1029 buf = xmalloc (1024);
1034 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1038 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1043 buf[strlen (buf) - 1] = 0;
1054 /* Write out some type definitions */
1056 dump (0, "#define MAXLISTS 10");
1060 /* For every array subcommand, write out the associated enumerated
1065 for (sbc = subcommands; sbc; sbc = sbc->next)
1066 if (sbc->type == SBC_ARRAY && sbc->narray)
1068 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1076 for (spec = sbc->spec; spec; spec = spec->next)
1077 dump (0, "%s%s%s = %d,",
1078 st_upper (prefix), st_upper (sbc->prefix),
1079 st_upper (spec->varname), spec->index);
1081 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1089 /* Write out structure declaration. */
1093 dump (0, "/* %s structure. */", cmdname);
1094 dump (1, "struct cmd_%s", make_identifier (cmdname));
1096 for (sbc = subcommands; sbc; sbc = sbc->next)
1100 if (sbc != subcommands)
1103 dump (0, "/* %s subcommand. */", sbc->name);
1104 dump (0, "int sbc_%s;", st_lower (sbc->name));
1113 for (spec = sbc->spec; spec; spec = spec->next)
1117 if (sbc->type == SBC_PLAIN)
1118 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1122 dump (0, "int a_%s[%s%scount];",
1123 st_lower (sbc->name),
1125 st_upper (sbc->prefix)
1132 dump_specifier_vars (spec, sbc);
1138 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1139 st_lower (sbc->name));
1140 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1141 st_lower (sbc->name));
1145 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1146 st_lower (sbc->name));
1150 dump (0, "char *s_%s;", st_lower (sbc->name));
1155 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1159 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1163 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1164 st_lower(sbc->name));
1168 dump (0, "subc_list_int il_%s[MAXLISTS];",
1169 st_lower(sbc->name));
1182 /* Write out prototypes for custom_*() functions as necessary. */
1187 for (sbc = subcommands; sbc; sbc = sbc->next)
1188 if (sbc->type == SBC_CUSTOM)
1193 dump (0, "/* Prototype for custom subcommands of %s. */",
1196 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1197 st_lower (prefix), st_lower (sbc->name),
1198 make_identifier (cmdname));
1205 /* Prototypes for parsing and freeing functions. */
1207 dump (0, "/* Command parsing functions. */");
1208 dump (0, "static int parse_%s (struct cmd_%s *);",
1209 make_identifier (cmdname), make_identifier (cmdname));
1210 dump (0, "static void free_%s (struct cmd_%s *);",
1211 make_identifier (cmdname), make_identifier (cmdname));
1216 /* Writes out code to initialize all the variables that need
1217 initialization for particular specifier SPEC inside subcommand SBC. */
1219 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1227 st_upper (prefix), find_symbol (spec->def->con)->name);
1230 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1236 for (s = spec->s; s; s = s->next)
1238 if (s->value != VAL_NONE)
1242 assert (s->value == VAL_INT || s->value == VAL_DBL);
1243 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1245 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1251 /* Write code to initialize all variables. */
1253 dump_vars_init (int persistent)
1255 /* Loop through all the subcommands. */
1259 for (sbc = subcommands; sbc; sbc = sbc->next)
1263 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1274 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1275 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1276 st_lower (sbc->name)
1284 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1285 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1298 for (spec = sbc->spec; spec; spec = spec->next)
1299 if (spec->s == NULL)
1301 if (sbc->type == SBC_PLAIN)
1302 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1305 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1306 st_lower (sbc->name), st_lower (sbc->name));
1311 dump_specifier_init (spec, sbc);
1316 dump (0, "p->%sn_%s = 0;",
1317 st_lower (sbc->prefix), st_lower (sbc->name));
1318 dump (0, "p->%sv_%s = NULL;",
1319 st_lower (sbc->prefix), st_lower (sbc->name));
1323 dump (0, "p->%sv_%s = NULL;",
1324 st_lower (sbc->prefix), st_lower (sbc->name));
1328 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1335 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1336 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1348 /* Return a pointer to a static buffer containing an expression that
1349 will match token T. */
1351 make_match (const char *t)
1361 sprintf (s, "lex_match (T_%s)", t);
1362 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1363 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1364 "|| lex_match_id (\"TRUE\"))");
1365 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1366 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1367 "|| lex_match_id (\"FALSE\"))");
1368 else if (isdigit ((unsigned char) t[0]))
1369 sprintf (s, "lex_match_int (%s)", t);
1371 sprintf (s, "lex_match_id (\"%s\")", t);
1376 /* Write out the parsing code for specifier SPEC within subcommand
1379 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1383 if (spec->omit_kw && spec->omit_kw->next)
1384 error ("Omittable setting is not last setting in `%s' specifier.",
1386 if (spec->omit_kw && spec->omit_kw->parent->next)
1387 error ("Default specifier is not in last specifier in `%s' "
1388 "subcommand.", sbc->name);
1390 for (s = spec->s; s; s = s->next)
1392 int first = spec == sbc->spec && s == spec->s;
1394 /* Match the setting's keyword. */
1395 if (spec->omit_kw == s)
1402 dump (1, "%s;", make_match (s->specname));
1405 dump (1, "%sif (%s)", first ? "" : "else ",
1406 make_match (s->specname));
1409 /* Handle values. */
1410 if (s->value == VAL_NONE)
1411 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1412 st_upper (prefix), find_symbol (s->con)->name);
1415 if (spec->omit_kw != s)
1420 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1421 st_upper (prefix), find_symbol (s->con)->name);
1423 if ( sbc->type == SBC_ARRAY )
1424 dump (0, "p->a_%s[%s%s%s] = 1;",
1425 st_lower (sbc->name),
1426 st_upper (prefix), st_upper (sbc->prefix),
1427 st_upper (spec->varname));
1431 if (s->valtype == VT_PAREN)
1435 dump (1, "if (lex_match ('('))");
1440 dump (1, "if (!lex_match ('('))");
1442 dump (0, "msg (SE, _(\"`(' expected after %s "
1443 "specifier of %s subcommand.\"));",
1444 s->specname, sbc->name);
1445 dump (0, "goto lossage;");
1451 if (s->value == VAL_INT)
1453 dump (1, "if (!lex_is_integer ())");
1455 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1456 "requires an integer argument.\"));",
1457 s->specname, sbc->name);
1458 dump (0, "goto lossage;");
1460 dump (-1, "p->%s%s = lex_integer ();",
1461 sbc->prefix, st_lower (s->valname));
1465 dump (1, "if (!lex_is_number ())");
1467 dump (0, "msg (SE, _(\"Number expected after %s "
1468 "specifier of %s subcommand.\"));",
1469 s->specname, sbc->name);
1470 dump (0, "goto lossage;");
1472 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1473 st_lower (s->valname));
1480 str = xmalloc (MAX_TOK_LEN);
1481 str2 = xmalloc (MAX_TOK_LEN);
1482 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1483 sprintf (str, s->restriction, str2, str2, str2, str2,
1484 str2, str2, str2, str2);
1485 dump (1, "if (!(%s))", str);
1491 dump (0, "msg (SE, _(\"Bad argument for %s "
1492 "specifier of %s subcommand.\"));",
1493 s->specname, sbc->name);
1494 dump (0, "goto lossage;");
1499 dump (0, "lex_get ();");
1501 if (s->valtype == VT_PAREN)
1503 dump (1, "if (!lex_match (')'))");
1505 dump (0, "msg (SE, _(\"`)' expected after argument for "
1506 "%s specifier of %s.\"));",
1507 s->specname, sbc->name);
1508 dump (0, "goto lossage;");
1518 if (s != spec->omit_kw)
1522 if (s == spec->omit_kw)
1531 /* Write out the code to parse subcommand SBC. */
1533 dump_subcommand (const subcommand *sbc)
1535 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1539 dump (1, "while (token != '/' && token != '.')");
1545 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1548 dump_specifier_parse (spec, sbc);
1552 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1553 make_match (st_upper (spec->varname)));
1554 if (sbc->type == SBC_PLAIN)
1555 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1558 dump (0, "p->a_%s[%s%s%s] = 1;",
1559 st_lower (sbc->name),
1560 st_upper (prefix), st_upper (sbc->prefix),
1561 st_upper (spec->varname));
1571 /* This code first finds the last specifier in sbc. Then it
1572 finds the last setting within that last specifier. Either
1573 or both might be NULL. */
1586 if (spec && (!spec->s || !spec->omit_kw))
1590 dump (0, "lex_error (NULL);");
1591 dump (0, "goto lossage;");
1597 dump (0, "lex_match (',');");
1601 else if (sbc->type == SBC_VARLIST)
1603 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1605 st_lower (sbc->prefix), st_lower (sbc->name),
1606 st_lower (sbc->prefix), st_lower (sbc->name),
1607 sbc->message ? " |" : "",
1608 sbc->message ? sbc->message : "");
1609 dump (0, "goto lossage;");
1612 else if (sbc->type == SBC_VAR)
1614 dump (0, "p->%sv_%s = parse_variable ();",
1615 st_lower (sbc->prefix), st_lower (sbc->name));
1616 dump (1, "if (!p->%sv_%s)",
1617 st_lower (sbc->prefix), st_lower (sbc->name));
1618 dump (0, "goto lossage;");
1621 else if (sbc->type == SBC_STRING)
1623 if (sbc->restriction)
1628 dump (1, "if (!lex_force_string ())");
1629 dump (0, "return 0;");
1631 if (sbc->restriction)
1633 dump (0, "x = ds_length (&tokstr);");
1634 dump (1, "if (!(%s))", sbc->restriction);
1636 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1637 sbc->name, sbc->message);
1638 dump (0, "goto lossage;");
1642 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1643 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1644 st_lower (sbc->name));
1645 dump (0, "lex_get ();");
1646 if (sbc->restriction)
1649 else if (sbc->type == SBC_DBL)
1651 dump (1, "if (!lex_force_num ())");
1652 dump (0, "goto lossage;");
1653 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1654 st_lower (sbc->name), st_lower (sbc->name) );
1655 dump (0, "lex_get();");
1657 else if (sbc->type == SBC_INT)
1661 dump (1, "if (!lex_force_int ())");
1662 dump (0, "goto lossage;");
1663 dump (-1, "x = lex_integer ();");
1664 dump (0, "lex_get();");
1665 if (sbc->restriction)
1668 dump (1, "if (!(%s))", sbc->restriction);
1670 sprintf(buf,sbc->message,sbc->name);
1671 if ( sbc->translatable )
1672 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1674 dump (0, "msg (SE, \"%s\");",buf);
1675 dump (0, "goto lossage;");
1678 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1681 else if (sbc->type == SBC_PINT)
1683 dump (0, "lex_match ('(');");
1684 dump (1, "if (!lex_force_int ())");
1685 dump (0, "goto lossage;");
1686 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1687 dump (0, "lex_match (')');");
1689 else if (sbc->type == SBC_DBL_LIST)
1691 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1693 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1694 dump (0, "goto lossage;");
1697 dump (1, "while (token != '/' && token != '.')");
1699 dump (0, "lex_match(',');");
1700 dump (0, "if (!lex_force_num ())");
1702 dump (0, "goto lossage;");
1705 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1706 st_lower (sbc->name),st_lower (sbc->name)
1709 dump (0, "lex_get();");
1713 else if (sbc->type == SBC_CUSTOM)
1715 dump (1, "switch (%scustom_%s (p))",
1716 st_lower (prefix), st_lower (sbc->name));
1718 dump (1, "case 0:");
1719 dump (0, "goto lossage;");
1720 dump (-1, "case 1:");
1723 dump (-1, "case 2:");
1725 dump (0, "lex_error (NULL);");
1726 dump (0, "goto lossage;");
1727 dump (-1, "default:");
1729 dump (0, "assert (0);");
1735 /* Write out entire parser. */
1737 dump_parser (int persistent)
1743 dump (0, "static int");
1744 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1745 make_identifier (cmdname));
1748 dump_vars_init (persistent);
1750 dump (1, "for (;;)");
1754 if (def && (def->type == SBC_VARLIST))
1756 if (def->type == SBC_VARLIST)
1757 dump (1, "if (token == T_ID "
1758 "&& dict_lookup_var (default_dict, tokid) != NULL "
1759 "&& lex_look_ahead () != '=')");
1762 dump (0, "if ((token == T_ID "
1763 "&& dict_lookup_var (default_dict, tokid) "
1764 "&& lex_look_ahead () != '=')");
1765 dump (1, " || token == T_ALL)");
1768 dump (0, "p->sbc_%s++;", st_lower (def->name));
1769 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1771 st_lower (def->prefix), st_lower (def->name),
1772 st_lower (def->prefix), st_lower (def->name));
1773 dump (0, "goto lossage;");
1778 else if (def && def->type == SBC_CUSTOM)
1780 dump (1, "switch (%scustom_%s (p))",
1781 st_lower (prefix), st_lower (def->name));
1783 dump (1, "case 0:");
1784 dump (0, "goto lossage;");
1785 dump (-1, "case 1:");
1787 dump (0, "p->sbc_%s++;", st_lower (def->name));
1788 dump (0, "continue;");
1789 dump (-1, "case 2:");
1792 dump (-1, "default:");
1794 dump (0, "assert (0);");
1802 for (sbc = subcommands; sbc; sbc = sbc->next)
1804 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1808 dump (0, "lex_match ('=');");
1809 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1810 if (sbc->arity != ARITY_MANY)
1812 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1814 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1816 dump (0, "goto lossage;");
1820 dump_subcommand (sbc);
1827 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1828 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1831 dump (0, "lex_match ('=');");
1833 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1834 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1836 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1837 dump(0,"set_cmd_algorithm(ENHANCED);");
1844 dump (1, "if (!lex_match ('/'))");
1849 dump (1, "if (token != '.')");
1851 dump (0, "lex_error (_(\"expecting end of command\"));");
1852 dump (0, "goto lossage;");
1859 /* Check that mandatory subcommands have been specified */
1862 for (sbc = subcommands; sbc; sbc = sbc->next)
1865 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1867 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1869 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1871 dump (0, "goto lossage;");
1878 dump (-1, "return 1;");
1880 dump (-1, "lossage:");
1882 dump (0, "free_%s (p);", make_identifier (cmdname));
1883 dump (0, "return 0;");
1889 /* Write the output file header. */
1898 curtime = time (NULL);
1899 loctime = localtime (&curtime);
1900 timep = asctime (loctime);
1901 timep[strlen (timep) - 1] = 0;
1902 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1904 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1905 dump (0, " Do not modify!");
1909 /* Write out commands to free variable state. */
1911 dump_free (int persistent)
1921 for (sbc = subcommands; sbc; sbc = sbc->next)
1923 if (sbc->type == SBC_STRING)
1925 if (sbc->type == SBC_DBL_LIST)
1931 dump (0, "static void");
1932 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1933 make_identifier (cmdname), used ? "" : " UNUSED");
1939 for (sbc = subcommands; sbc; sbc = sbc->next)
1944 dump (0, "free (p->v_variables);");
1947 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1951 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
1952 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1967 /* Returns the name of a directive found on the current input line, if
1968 any, or a null pointer if none found. */
1970 recognize_directive (void)
1972 static char directive[16];
1976 if (strncmp (sp, "/*", 2))
1978 sp = skip_ws (sp + 2);
1983 ep = strchr (sp, ')');
1989 memcpy (directive, sp, ep - sp);
1990 directive[ep - sp] = '\0';
1995 main (int argc, char *argv[])
1997 program_name = argv[0];
1999 fail ("Syntax: q2c input.q output.c");
2002 in = fopen (ifn, "r");
2004 fail ("%s: open: %s.", ifn, strerror (errno));
2007 out = fopen (ofn, "w");
2009 fail ("%s: open: %s.", ofn, strerror (errno));
2012 buf = xmalloc (MAX_LINE_LEN);
2013 tokstr = xmalloc (MAX_TOK_LEN);
2019 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2022 const char *directive = recognize_directive ();
2023 if (directive == NULL)
2025 dump (0, "%s", buf);
2029 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2030 if (!strcmp (directive, "specification"))
2032 /* Skip leading slash-star line. */
2038 /* Skip trailing star-slash line. */
2041 else if (!strcmp (directive, "headers"))
2045 dump (0, "#include <stdlib.h>");
2046 dump (0, "#include \"alloc.h\"");
2047 dump (0, "#include \"message.h\"");
2048 dump (0, "#include \"lexer.h\"");
2049 dump (0, "#include \"settings.h\"");
2050 dump (0, "#include \"str.h\"");
2051 dump (0, "#include \"subcommand-list.h\"");
2052 dump (0, "#include \"variable.h\"");
2055 dump (0, "#include \"gettext.h\"");
2056 dump (0, "#define _(msgid) gettext (msgid)");
2059 else if (!strcmp (directive, "declarations"))
2060 dump_declarations ();
2061 else if (!strcmp (directive, "functions"))
2066 else if (!strcmp (directive, "_functions"))
2072 error ("unknown directive `%s'", directive);
2074 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2079 return EXIT_SUCCESS;