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
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", pgmname, 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: ", pgmname);
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 (symbol));
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 ("TR_STRING\t\"%s\"\n", tokstr);
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);
385 while (*cp != '"' && *cp)
391 error ("Unterminated string literal.");
399 error ("Unterminated string literal.");
402 else if (*cp == '_' || isalnum ((unsigned char) *cp))
406 while (*cp == '_' || isalnum ((unsigned char) *cp))
407 *dest++ = toupper ((unsigned char) (*cp++));
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 and SBC_INT only. */
551 char *restriction; /* Expression restricting string length. */
552 char *message; /* Error message. */
553 int translatable; /* Error message is translatable */
556 typedef struct aux_subcommand aux_subcommand;
557 struct aux_subcommand
559 aux_subcommand *next; /* Next in the chain. */
560 char *name; /* Subcommand name. */
561 char *value; /* Subcommand value */
564 static aux_subcommand *aux_subcommands ;
566 /* Name of the command; i.e., DESCRIPTIVES. */
569 /* Short prefix for the command; i.e., `dsc_'. */
572 /* List of subcommands. */
573 subcommand *subcommands;
575 /* Default subcommand if any, or NULL. */
580 void parse_subcommands (void);
582 /* Parse an entire specification. */
586 /* Get the command name and prefix. */
587 if (token != T_STRING && token != T_ID)
588 error ("Command name expected.");
589 cmdname = xstrdup (tokstr);
593 prefix = xstrdup (tokstr);
598 /* Read all the subcommands. */
601 parse_subcommands ();
604 /* Parses a single setting into S, given subcommand information SBC
605 and specifier information SPEC. */
607 parse_setting (setting *s, specifier *spec)
611 if (match_token ('*'))
614 error ("Cannot have two settings with omittable keywords.");
619 if (match_token ('!'))
622 error ("Cannot have two default settings.");
628 s->specname = xstrdup (tokstr);
629 s->con = add_symbol (s->specname, 0, 0);
634 /* Parse setting value info if necessary. */
635 if (token != '/' && token != ';' && token != '.' && token != ',')
639 s->valtype = VT_PAREN;
643 s->valtype = VT_PLAIN;
645 s->optvalue = match_token ('*');
649 else if (match_id ("D"))
652 error ("`n' or `d' expected.");
657 s->valname = xstrdup (tokstr);
664 s->restriction = xstrdup (tokstr);
668 s->restriction = NULL;
670 if (s->valtype == VT_PAREN)
675 /* Parse a single specifier into SPEC, given subcommand information
678 parse_specifier (specifier *spec, subcommand *sbc)
683 spec->omit_kw = NULL;
684 spec->varname = NULL;
688 spec->varname = xstrdup (st_lower (tokstr));
692 /* Handle array elements. */
695 spec->index = sbc->narray;
696 if (sbc->type == SBC_ARRAY)
708 /* Parse all the settings. */
710 setting **s = &spec->s;
714 *s = xmalloc (sizeof (setting));
715 parse_setting (*s, spec);
716 if (token == ',' || token == ';' || token == '.')
725 /* Parse a list of specifiers for subcommand SBC. */
727 parse_specifiers (subcommand *sbc)
729 specifier **spec = &sbc->spec;
731 if (token == ';' || token == '.')
739 *spec = xmalloc (sizeof (specifier));
740 parse_specifier (*spec, sbc);
741 if (token == ';' || token == '.')
744 spec = &(*spec)->next;
746 (*spec)->next = NULL;
749 /* Parse a subcommand into SBC. */
751 parse_subcommand (subcommand *sbc)
753 if (match_token ('*'))
756 error ("Multiple default subcommands.");
760 sbc->once = match_token ('+');
763 sbc->name = xstrdup (tokstr);
767 sbc->type = SBC_PLAIN;
769 sbc->translatable = 0;
771 if (match_token ('['))
774 sbc->prefix = xstrdup (st_lower (tokstr));
780 sbc->type = SBC_ARRAY;
781 parse_specifiers (sbc);
785 if (match_token ('('))
788 sbc->prefix = xstrdup (st_lower (tokstr));
798 if (match_id ("VAR"))
800 if (match_id ("VARLIST"))
802 if (match_token ('('))
805 sbc->message = xstrdup (tokstr);
810 else sbc->message = NULL;
812 sbc->type = SBC_VARLIST;
814 else if (match_id ("INTEGER"))
816 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
817 if ( token == T_STRING)
819 sbc->restriction = xstrdup (tokstr);
821 if ( match_id("N_") )
827 sbc->translatable = 1;
833 sbc->message = xstrdup (tokstr);
836 sbc->restriction = NULL;
838 else if (match_id ("PINT"))
839 sbc->type = SBC_PINT;
840 else if (match_id ("DOUBLE"))
842 if ( match_id ("LIST") )
843 sbc->type = SBC_DBL_LIST;
847 else if (match_id ("STRING"))
849 sbc->type = SBC_STRING;
850 if (token == T_STRING)
852 sbc->restriction = xstrdup (tokstr);
855 sbc->message = xstrdup (tokstr);
859 sbc->restriction = NULL;
861 else if (match_id ("CUSTOM"))
862 sbc->type = SBC_CUSTOM;
864 parse_specifiers (sbc);
868 /* Parse all the subcommands. */
870 parse_subcommands (void)
872 subcommand **sbc = &subcommands;
876 *sbc = xmalloc (sizeof (subcommand));
879 parse_subcommand (*sbc);
891 #define BASE_INDENT 2 /* Starting indent. */
892 #define INC_INDENT 2 /* Indent increment. */
894 /* Increment the indent. */
895 #define indent() indent += INC_INDENT
896 #define outdent() indent -= INC_INDENT
898 /* Size of the indent from the left margin. */
901 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
903 /* Write line FORMAT to the output file, formatted as with printf,
904 indented `indent' characters from the left margin. If INDENTION is
905 greater than 0, indents BASE_INDENT * INDENTION characters after
906 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
907 * INDENTION characters _before_ writing the line. */
909 dump (int indention, const char *format, ...)
915 indent += BASE_INDENT * indention;
918 va_start (args, format);
919 for (i = 0; i < indent; i++)
921 vfprintf (out, format, args);
926 indent += BASE_INDENT * indention;
929 /* Write the structure members for specifier SPEC to the output file.
930 SBC is the including subcommand. */
932 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
935 dump (0, "long %s%s;", sbc->prefix, spec->varname);
940 for (s = spec->s; s; s = s->next)
942 if (s->value != VAL_NONE)
944 const char *typename;
946 assert (s->value == VAL_INT || s->value == VAL_DBL);
947 typename = s->value == VAL_INT ? "long" : "double";
949 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
955 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
957 is_keyword (const char *t)
959 static const char *kw[] =
961 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
962 "NE", "ALL", "BY", "TO", "WITH", 0,
966 for (cp = kw; *cp; cp++)
967 if (!strcmp (t, *cp))
972 /* Transforms a string NAME into a valid C identifier: makes
973 everything lowercase and maps nonalphabetic characters to
974 underscores. Returns a pointer to a static buffer. */
976 make_identifier (const char *name)
978 char *p = get_buffer ();
981 for (cp = p; *name; name++)
982 if (isalpha ((unsigned char) *name))
983 *cp++ = tolower ((unsigned char) (*name));
991 /* Writes the struct and enum declarations for the parser. */
993 dump_declarations (void)
997 /* Write out enums for all the identifiers in the symbol table. */
1003 /* Note the squirmings necessary to make sure that the last enum
1004 is not followed by a comma, as mandated by ANSI C89. */
1005 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1006 if (!sym->unique && !is_keyword (sym->name))
1010 dump (0, "/* Settings for subcommand specifiers. */");
1017 buf = xmalloc (1024);
1022 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1026 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1031 buf[strlen (buf) - 1] = 0;
1042 /* Write out some type definitions */
1044 dump (0, "#define MAXLISTS 10");
1048 /* For every array subcommand, write out the associated enumerated
1053 for (sbc = subcommands; sbc; sbc = sbc->next)
1054 if (sbc->type == SBC_ARRAY && sbc->narray)
1056 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1064 for (spec = sbc->spec; spec; spec = spec->next)
1066 dump (0, "%s%s%s = %d,",
1067 st_upper (prefix), st_upper (sbc->prefix),
1068 st_upper (spec->varname), spec->index);
1070 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1078 /* Write out structure declaration. */
1082 dump (0, "/* %s structure. */", cmdname);
1083 dump (1, "struct cmd_%s", make_identifier (cmdname));
1085 for (sbc = subcommands; sbc; sbc = sbc->next)
1089 if (sbc != subcommands)
1092 dump (0, "/* %s subcommand. */", sbc->name);
1093 dump (0, "int sbc_%s;", st_lower (sbc->name));
1102 for (spec = sbc->spec; spec; spec = spec->next)
1106 if (sbc->type == SBC_PLAIN)
1107 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1111 dump (0, "int a_%s[%d];",
1112 st_lower (sbc->name), sbc->narray);
1117 dump_specifier_vars (spec, sbc);
1123 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1124 st_lower (sbc->name));
1125 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1126 st_lower (sbc->name));
1130 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1131 st_lower (sbc->name));
1135 dump (0, "char *s_%s;", st_lower (sbc->name));
1140 dump (0, "long n_%s;", st_lower (sbc->name));
1144 dump (0, "double n_%s;", st_lower (sbc->name));
1148 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1149 st_lower(sbc->name));
1153 dump (0, "subc_list_int il_%s[MAXLISTS];",
1154 st_lower(sbc->name));
1167 /* Write out prototypes for custom_*() functions as necessary. */
1172 for (sbc = subcommands; sbc; sbc = sbc->next)
1173 if (sbc->type == SBC_CUSTOM)
1178 dump (0, "/* Prototype for custom subcommands of %s. */",
1181 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1182 st_lower (prefix), st_lower (sbc->name),
1183 make_identifier (cmdname));
1190 /* Prototypes for parsing and freeing functions. */
1192 dump (0, "/* Command parsing functions. */");
1193 dump (0, "static int parse_%s (struct cmd_%s *);",
1194 make_identifier (cmdname), make_identifier (cmdname));
1195 dump (0, "static void free_%s (struct cmd_%s *);",
1196 make_identifier (cmdname), make_identifier (cmdname));
1201 /* Writes out code to initialize all the variables that need
1202 initialization for particular specifier SPEC inside subcommand SBC. */
1204 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1212 st_upper (prefix), find_symbol (spec->def->con)->name);
1215 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1221 for (s = spec->s; s; s = s->next)
1223 if (s->value != VAL_NONE)
1227 assert (s->value == VAL_INT || s->value == VAL_DBL);
1228 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1230 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1236 /* Write code to initialize all variables. */
1238 dump_vars_init (int persistent)
1240 /* Loop through all the subcommands. */
1244 for (sbc = subcommands; sbc; sbc = sbc->next)
1248 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1258 dump (0, "for (i = 0; i < MAXLISTS; ++i)");
1260 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1261 st_lower (sbc->name)
1276 for (spec = sbc->spec; spec; spec = spec->next)
1277 if (spec->s == NULL)
1279 if (sbc->type == SBC_PLAIN)
1280 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1283 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1284 st_lower (sbc->name), st_lower (sbc->name));
1289 dump_specifier_init (spec, sbc);
1294 dump (0, "p->%sn_%s = 0;",
1295 st_lower (sbc->prefix), st_lower (sbc->name));
1296 dump (0, "p->%sv_%s = NULL;",
1297 st_lower (sbc->prefix), st_lower (sbc->name));
1301 dump (0, "p->%sv_%s = NULL;",
1302 st_lower (sbc->prefix), st_lower (sbc->name));
1306 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1311 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1322 /* Return a pointer to a static buffer containing an expression that
1323 will match token T. */
1325 make_match (const char *t)
1335 sprintf (s, "lex_match (T_%s)", t);
1336 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1337 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1338 "|| lex_match_id (\"TRUE\"))");
1339 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1340 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1341 "|| lex_match_id (\"FALSE\"))");
1342 else if (isdigit ((unsigned char) t[0]))
1343 sprintf (s, "lex_match_int (%s)", t);
1345 sprintf (s, "lex_match_id (\"%s\")", t);
1350 /* Write out the parsing code for specifier SPEC within subcommand
1353 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1357 if (spec->omit_kw && spec->omit_kw->next)
1358 error ("Omittable setting is not last setting in `%s' specifier.",
1360 if (spec->omit_kw && spec->omit_kw->parent->next)
1361 error ("Default specifier is not in last specifier in `%s' "
1362 "subcommand.", sbc->name);
1364 for (s = spec->s; s; s = s->next)
1366 int first = spec == sbc->spec && s == spec->s;
1368 /* Match the setting's keyword. */
1369 if (spec->omit_kw == s)
1376 dump (1, "%s;", make_match (s->specname));
1379 dump (1, "%sif (%s)", first ? "" : "else ",
1380 make_match (s->specname));
1382 /* Handle values. */
1383 if (s->value == VAL_NONE)
1384 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1385 st_upper (prefix), find_symbol (s->con)->name);
1388 if (spec->omit_kw != s)
1392 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1393 st_upper (prefix), find_symbol (s->con)->name);
1395 if (s->valtype == VT_PAREN)
1399 dump (1, "if (lex_match ('('))");
1404 dump (1, "if (!lex_match ('('))");
1406 dump (0, "msg (SE, _(\"`(' expected after %s "
1407 "specifier of %s subcommand.\"));",
1408 s->specname, sbc->name);
1409 dump (0, "goto lossage;");
1415 if (s->value == VAL_INT)
1417 dump (1, "if (!lex_integer_p ())");
1419 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1420 "requires an integer argument.\"));",
1421 s->specname, sbc->name);
1422 dump (0, "goto lossage;");
1424 dump (-1, "p->%s%s = lex_integer ();",
1425 sbc->prefix, st_lower (s->valname));
1429 dump (1, "if (token != T_NUM)");
1431 dump (0, "msg (SE, _(\"Number expected after %s "
1432 "specifier of %s subcommand.\"));",
1433 s->specname, sbc->name);
1434 dump (0, "goto lossage;");
1436 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1437 st_lower (s->valname));
1444 str = xmalloc (MAX_TOK_LEN);
1445 str2 = xmalloc (MAX_TOK_LEN);
1446 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1447 sprintf (str, s->restriction, str2, str2, str2, str2,
1448 str2, str2, str2, str2);
1449 dump (1, "if (!(%s))", str);
1455 dump (0, "msg (SE, _(\"Bad argument for %s "
1456 "specifier of %s subcommand.\"));",
1457 s->specname, sbc->name);
1458 dump (0, "goto lossage;");
1463 dump (0, "lex_get ();");
1465 if (s->valtype == VT_PAREN)
1467 dump (1, "if (!lex_match (')'))");
1469 dump (0, "msg (SE, _(\"`)' expected after argument for "
1470 "%s specifier of %s.\"));",
1471 s->specname, sbc->name);
1472 dump (0, "goto lossage;");
1482 if (s != spec->omit_kw)
1486 if (s == spec->omit_kw)
1495 /* Write out the code to parse subcommand SBC. */
1497 dump_subcommand (const subcommand *sbc)
1499 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1503 dump (1, "while (token != '/' && token != '.')");
1509 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1512 dump_specifier_parse (spec, sbc);
1516 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1517 make_match (st_upper (spec->varname)));
1518 if (sbc->type == SBC_PLAIN)
1519 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1522 dump (0, "p->a_%s[%s%s%s] = 1;",
1523 st_lower (sbc->name),
1524 st_upper (prefix), st_upper (sbc->prefix),
1525 st_upper (spec->varname));
1535 /* This code first finds the last specifier in sbc. Then it
1536 finds the last setting within that last specifier. Either
1537 or both might be NULL. */
1550 if (spec && (!spec->s || !spec->omit_kw))
1554 dump (0, "lex_error (NULL);");
1555 dump (0, "goto lossage;");
1561 dump (0, "lex_match (',');");
1565 else if (sbc->type == SBC_VARLIST)
1567 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1569 st_lower (sbc->prefix), st_lower (sbc->name),
1570 st_lower (sbc->prefix), st_lower (sbc->name),
1571 sbc->message ? " |" : "",
1572 sbc->message ? sbc->message : "");
1573 dump (0, "goto lossage;");
1576 else if (sbc->type == SBC_VAR)
1578 dump (0, "p->%sv_%s = parse_variable ();",
1579 st_lower (sbc->prefix), st_lower (sbc->name));
1580 dump (1, "if (p->%sv_%s)",
1581 st_lower (sbc->prefix), st_lower (sbc->name));
1582 dump (0, "goto lossage;");
1585 else if (sbc->type == SBC_STRING)
1587 if (sbc->restriction)
1592 dump (1, "if (!lex_force_string ())");
1593 dump (0, "return 0;");
1595 if (sbc->restriction)
1597 dump (0, "x = ds_length (&tokstr);");
1598 dump (1, "if (!(%s))", sbc->restriction);
1600 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1601 sbc->name, sbc->message);
1602 dump (0, "goto lossage;");
1606 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1607 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1608 st_lower (sbc->name));
1609 dump (0, "lex_get ();");
1610 if (sbc->restriction)
1613 else if (sbc->type == SBC_DBL)
1615 dump (1, "if (!lex_force_num ())");
1616 dump (0, "goto lossage;");
1617 dump (-1, "p->n_%s = lex_double ();", st_lower (sbc->name));
1618 dump (0, "lex_get();");
1620 else if (sbc->type == SBC_INT)
1624 dump (1, "if (!lex_force_int ())");
1625 dump (0, "goto lossage;");
1626 dump (-1, "x = lex_integer ();");
1627 dump (0, "lex_get();");
1628 if (sbc->restriction)
1631 dump (1, "if (!(%s))", sbc->restriction);
1633 sprintf(buf,sbc->message,sbc->name);
1634 if ( sbc->translatable )
1635 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1637 dump (0, "msg (SE, \"%s\");",buf);
1638 dump (0, "goto lossage;");
1641 dump (-1, "p->n_%s = x;", st_lower (sbc->name));
1644 else if (sbc->type == SBC_PINT)
1646 dump (0, "lex_match ('(');");
1647 dump (1, "if (!lex_force_int ())");
1648 dump (0, "goto lossage;");
1649 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1650 dump (0, "lex_match (')');");
1652 else if (sbc->type == SBC_DBL_LIST)
1654 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1656 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1657 dump (0, "goto lossage;");
1660 dump (1, "while (token != '/' && token != '.')");
1662 dump (0, "lex_match(',');");
1663 dump (0, "if (!lex_force_num ())");
1665 dump (0, "goto lossage;");
1668 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_double ());",
1669 st_lower (sbc->name),st_lower (sbc->name)
1672 dump (0, "lex_get();");
1676 else if (sbc->type == SBC_CUSTOM)
1678 dump (1, "switch (%scustom_%s (p))",
1679 st_lower (prefix), st_lower (sbc->name));
1681 dump (1, "case 0:");
1682 dump (0, "goto lossage;");
1683 dump (-1, "case 1:");
1686 dump (-1, "case 2:");
1688 dump (0, "lex_error (NULL);");
1689 dump (0, "goto lossage;");
1690 dump (-1, "default:");
1692 dump (0, "assert (0);");
1698 /* Write out entire parser. */
1700 dump_parser (int persistent)
1706 dump (0, "static int");
1707 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1708 make_identifier (cmdname));
1711 dump_vars_init (persistent);
1713 dump (1, "for (;;)");
1717 if (def && (def->type == SBC_VARLIST))
1719 if (def->type == SBC_VARLIST)
1720 dump (1, "if (token == T_ID "
1721 "&& dict_lookup_var (default_dict, tokid) != NULL "
1722 "&& lex_look_ahead () != '=')");
1725 dump (0, "if ((token == T_ID "
1726 "&& dict_lookup_var (default_dict, tokid) "
1727 "&& lex_look_ahead () != '=')");
1728 dump (1, " || token == T_ALL)");
1731 dump (0, "p->sbc_%s++;", st_lower (def->name));
1732 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1734 st_lower (def->prefix), st_lower (def->name),
1735 st_lower (def->prefix), st_lower (def->name));
1736 dump (0, "goto lossage;");
1741 else if (def && def->type == SBC_CUSTOM)
1743 dump (1, "switch (%scustom_%s (p))",
1744 st_lower (prefix), st_lower (def->name));
1746 dump (1, "case 0:");
1747 dump (0, "goto lossage;");
1748 dump (-1, "case 1:");
1750 dump (0, "p->sbc_%s++;", st_lower (def->name));
1751 dump (0, "continue;");
1752 dump (-1, "case 2:");
1755 dump (-1, "default:");
1757 dump (0, "assert (0);");
1765 for (sbc = subcommands; sbc; sbc = sbc->next)
1767 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1771 dump (0, "lex_match ('=');");
1772 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1775 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1777 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1779 dump (0, "goto lossage;");
1783 dump_subcommand (sbc);
1788 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1789 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1792 dump (0, "lex_match ('=');");
1794 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1795 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1797 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1798 dump(0,"set_cmd_algorithm(ENHANCED);");
1804 dump (1, "if (!lex_match ('/'))");
1809 dump (1, "if (token != '.')");
1811 dump (0, "lex_error (_(\"expecting end of command\"));");
1812 dump (0, "goto lossage;");
1815 dump (-1, "return 1;");
1817 dump (-1, "lossage:");
1819 dump (0, "free_%s (p);", make_identifier (cmdname));
1820 dump (0, "return 0;");
1826 /* Write out the code to parse aux subcommand SBC. */
1828 dump_aux_subcommand (const subcommand *sbc)
1830 if (sbc->type == SBC_PLAIN )
1834 for (spec = sbc->spec; spec; spec = spec->next)
1837 sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1839 dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1840 dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1845 else if (sbc->type == SBC_STRING)
1847 dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1849 else if (sbc->type == SBC_INT)
1851 dump (0, "msg(MM,\"%s is %%ld\",p->n_%s);", sbc->name,st_lower(sbc->name) );
1853 else if (sbc->type == SBC_CUSTOM)
1855 dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1863 /* Write out auxilliary parser. */
1865 dump_aux_parser (void)
1869 aux_subcommand *asbc;
1871 /* Write out English strings for all the identifiers in the symbol table. */
1877 /* Note the squirmings necessary to make sure that the last string
1878 is not followed by a comma (is it necessary to do that ?? ) */
1879 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1880 if (!sym->unique && !is_keyword (sym->name))
1884 dump (0, "/* Strings for subcommand specifiers. */");
1885 dump (1, "static const char *settings[]=");
1891 buf = xmalloc (1024);
1895 sprintf (buf, "\"%s\",",sym->name);
1899 buf[strlen (buf) - 1] = 0;
1913 dump (0, "static int");
1914 dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1915 make_identifier (cmdname));
1918 dump (1, "for (;;)");
1922 for (sbc = subcommands; sbc; sbc = sbc->next)
1924 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1928 dump_aux_subcommand (sbc);
1934 for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
1936 dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
1939 dump(0,"aux_%s();",make_identifier(asbc->value));
1944 dump (1, "if (!lex_match ('/'))");
1949 dump (1, "if (token != '.')");
1951 dump (0, "lex_error (_(\"expecting end of command\"));");
1952 dump (0, "goto lossage;");
1955 dump (-1, "return 1;");
1957 dump (-1, "lossage:");
1959 dump (0, "free_%s (p);", make_identifier (cmdname));
1960 dump (0, "return 0;");
1961 dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
1962 make_identifier (cmdname), make_identifier (cmdname));
1967 /* Write the output file header. */
1976 curtime = time (NULL);
1977 loctime = localtime (&curtime);
1978 timep = asctime (loctime);
1979 timep[strlen (timep) - 1] = 0;
1980 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1982 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1983 dump (0, " Do not modify!");
1987 dump (0, "#include \"settings.h\"");
1988 dump (0, "#include \"subclist.h\"");
1992 /* Write out commands to free variable state. */
1994 dump_free (int persistent)
2004 for (sbc = subcommands; sbc; sbc = sbc->next)
2006 if (sbc->type == SBC_STRING)
2008 if (sbc->type == SBC_DBL_LIST)
2014 dump (0, "static void");
2015 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
2016 make_identifier (cmdname), used ? "" : " UNUSED");
2022 for (sbc = subcommands; sbc; sbc = sbc->next)
2027 dump (0, "free (p->s_%s);", st_lower (sbc->name));
2030 dump (0, "subc_list_double_destroy(p->dl_%s);", st_lower (sbc->name));
2044 /* Returns the name of a directive found on the current input line, if
2045 any, or a null pointer if none found. */
2047 recognize_directive (void)
2049 static char directive[16];
2053 if (strncmp (sp, "/*", 2))
2055 sp = skip_ws (sp + 2);
2060 ep = strchr (sp, ')');
2066 memcpy (directive, sp, ep - sp);
2067 directive[ep - sp] = '\0';
2071 static void aux_parse (void);
2074 main (int argc, char *argv[])
2078 fail ("Syntax: q2c input.q output.c");
2081 in = fopen (ifn, "r");
2083 fail ("%s: open: %s.", ifn, strerror (errno));
2086 out = fopen (ofn, "w");
2088 fail ("%s: open: %s.", ofn, strerror (errno));
2091 buf = xmalloc (MAX_LINE_LEN);
2092 tokstr = xmalloc (MAX_TOK_LEN);
2098 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2101 const char *directive = recognize_directive ();
2102 if (directive == NULL)
2104 dump (0, "%s", buf);
2108 dump (0, "#line %d \"%s\"", oln - 1, ofn);
2109 if (!strcmp (directive, "specification"))
2111 /* Skip leading slash-star line. */
2117 /* Skip trailing star-slash line. */
2120 else if (!strcmp (directive, "headers"))
2124 dump (0, "#include <stdlib.h>");
2125 dump (0, "#include \"alloc.h\"");
2126 dump (0, "#include \"error.h\"");
2127 dump (0, "#include \"lexer.h\"");
2128 dump (0, "#include \"str.h\"");
2129 dump (0, "#include \"var.h\"");
2133 else if (!strcmp (directive, "declarations"))
2134 dump_declarations ();
2135 else if (!strcmp (directive, "functions"))
2140 else if (!strcmp (directive, "_functions"))
2145 else if (!strcmp (directive, "aux_functions"))
2151 error ("unknown directive `%s'", directive);
2153 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2158 return EXIT_SUCCESS;
2161 /* Parse an entire auxilliary specification. */
2165 aux_subcommand *sbc;
2166 aux_subcommand *prevsbc = 0 ;
2172 sbc = xmalloc(sizeof(aux_subcommand));
2173 sbc->next = prevsbc;
2174 sbc->name = xstrdup (tokstr);
2177 sbc->value = xstrdup (tokstr);
2185 /* Skip trailing star-slash line. */
2187 aux_subcommands = sbc;