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", 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 ("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 typedef struct aux_subcommand aux_subcommand;
561 struct aux_subcommand
563 aux_subcommand *next; /* Next in the chain. */
564 char *name; /* Subcommand name. */
565 char *value; /* Subcommand value */
568 static aux_subcommand *aux_subcommands ;
570 /* Name of the command; i.e., DESCRIPTIVES. */
573 /* Short prefix for the command; i.e., `dsc_'. */
576 /* List of subcommands. */
577 subcommand *subcommands;
579 /* Default subcommand if any, or NULL. */
584 void parse_subcommands (void);
586 /* Parse an entire specification. */
590 /* Get the command name and prefix. */
591 if (token != T_STRING && token != T_ID)
592 error ("Command name expected.");
593 cmdname = xstrdup (tokstr);
597 prefix = xstrdup (tokstr);
602 /* Read all the subcommands. */
605 parse_subcommands ();
608 /* Parses a single setting into S, given subcommand information SBC
609 and specifier information SPEC. */
611 parse_setting (setting *s, specifier *spec)
615 if (match_token ('*'))
618 error ("Cannot have two settings with omittable keywords.");
623 if (match_token ('!'))
626 error ("Cannot have two default settings.");
632 s->specname = xstrdup (tokstr);
633 s->con = add_symbol (s->specname, 0, 0);
638 /* Parse setting value info if necessary. */
639 if (token != '/' && token != ';' && token != '.' && token != ',')
643 s->valtype = VT_PAREN;
647 s->valtype = VT_PLAIN;
649 s->optvalue = match_token ('*');
653 else if (match_id ("D"))
656 error ("`n' or `d' expected.");
661 s->valname = xstrdup (tokstr);
668 s->restriction = xstrdup (tokstr);
672 s->restriction = NULL;
674 if (s->valtype == VT_PAREN)
679 /* Parse a single specifier into SPEC, given subcommand information
682 parse_specifier (specifier *spec, subcommand *sbc)
687 spec->omit_kw = NULL;
688 spec->varname = NULL;
692 spec->varname = xstrdup (st_lower (tokstr));
696 /* Handle array elements. */
699 spec->index = sbc->narray;
700 if (sbc->type == SBC_ARRAY)
712 if ( sbc->type == SBC_ARRAY && token == T_ID )
714 spec->varname = xstrdup (st_lower (tokstr));
715 spec->index = sbc->narray;
721 /* Parse all the settings. */
723 setting **s = &spec->s;
727 *s = xmalloc (sizeof (setting));
728 parse_setting (*s, spec);
729 if (token == ',' || token == ';' || token == '.')
738 /* Parse a list of specifiers for subcommand SBC. */
740 parse_specifiers (subcommand *sbc)
742 specifier **spec = &sbc->spec;
744 if (token == ';' || token == '.')
752 *spec = xmalloc (sizeof (specifier));
753 parse_specifier (*spec, sbc);
754 if (token == ';' || token == '.')
757 spec = &(*spec)->next;
759 (*spec)->next = NULL;
762 /* Parse a subcommand into SBC. */
764 parse_subcommand (subcommand *sbc)
766 sbc->arity = ARITY_MANY;
768 if (match_token ('*'))
771 error ("Multiple default subcommands.");
775 if ( match_token('+'))
776 sbc->arity = ARITY_ONCE_ONLY ;
777 else if (match_token('^'))
778 sbc->arity = ARITY_ONCE_EXACTLY ;
782 sbc->name = xstrdup (tokstr);
786 sbc->type = SBC_PLAIN;
788 sbc->translatable = 0;
790 if (match_token ('['))
793 sbc->prefix = xstrdup (st_lower (tokstr));
799 sbc->type = SBC_ARRAY;
800 parse_specifiers (sbc);
805 if (match_token ('('))
808 sbc->prefix = xstrdup (st_lower (tokstr));
818 if (match_id ("VAR"))
820 if (match_id ("VARLIST"))
822 if (match_token ('('))
825 sbc->message = xstrdup (tokstr);
830 else sbc->message = NULL;
832 sbc->type = SBC_VARLIST;
834 else if (match_id ("INTEGER"))
836 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
837 if ( token == T_STRING)
839 sbc->restriction = xstrdup (tokstr);
841 if ( match_id("N_") )
847 sbc->translatable = 1;
853 sbc->message = xstrdup (tokstr);
856 sbc->restriction = NULL;
858 else if (match_id ("PINT"))
859 sbc->type = SBC_PINT;
860 else if (match_id ("DOUBLE"))
862 if ( match_id ("LIST") )
863 sbc->type = SBC_DBL_LIST;
867 else if (match_id ("STRING"))
869 sbc->type = SBC_STRING;
870 if (token == T_STRING)
872 sbc->restriction = xstrdup (tokstr);
875 sbc->message = xstrdup (tokstr);
879 sbc->restriction = NULL;
881 else if (match_id ("CUSTOM"))
882 sbc->type = SBC_CUSTOM;
884 parse_specifiers (sbc);
888 /* Parse all the subcommands. */
890 parse_subcommands (void)
892 subcommand **sbc = &subcommands;
896 *sbc = xmalloc (sizeof (subcommand));
899 parse_subcommand (*sbc);
911 #define BASE_INDENT 2 /* Starting indent. */
912 #define INC_INDENT 2 /* Indent increment. */
914 /* Increment the indent. */
915 #define indent() indent += INC_INDENT
916 #define outdent() indent -= INC_INDENT
918 /* Size of the indent from the left margin. */
921 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
923 /* Write line FORMAT to the output file, formatted as with printf,
924 indented `indent' characters from the left margin. If INDENTION is
925 greater than 0, indents BASE_INDENT * INDENTION characters after
926 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
927 * INDENTION characters _before_ writing the line. */
929 dump (int indention, const char *format, ...)
935 indent += BASE_INDENT * indention;
938 va_start (args, format);
939 for (i = 0; i < indent; i++)
941 vfprintf (out, format, args);
946 indent += BASE_INDENT * indention;
949 /* Write the structure members for specifier SPEC to the output file.
950 SBC is the including subcommand. */
952 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
955 dump (0, "long %s%s;", sbc->prefix, spec->varname);
960 for (s = spec->s; s; s = s->next)
962 if (s->value != VAL_NONE)
964 const char *typename;
966 assert (s->value == VAL_INT || s->value == VAL_DBL);
967 typename = s->value == VAL_INT ? "long" : "double";
969 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
975 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
977 is_keyword (const char *t)
979 static const char *kw[] =
981 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
982 "NE", "ALL", "BY", "TO", "WITH", 0,
986 for (cp = kw; *cp; cp++)
987 if (!strcmp (t, *cp))
992 /* Transforms a string NAME into a valid C identifier: makes
993 everything lowercase and maps nonalphabetic characters to
994 underscores. Returns a pointer to a static buffer. */
996 make_identifier (const char *name)
998 char *p = get_buffer ();
1001 for (cp = p; *name; name++)
1002 if (isalpha ((unsigned char) *name))
1003 *cp++ = tolower ((unsigned char) (*name));
1011 /* Writes the struct and enum declarations for the parser. */
1013 dump_declarations (void)
1017 /* Write out enums for all the identifiers in the symbol table. */
1023 /* Note the squirmings necessary to make sure that the last enum
1024 is not followed by a comma, as mandated by ANSI C89. */
1025 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1026 if (!sym->unique && !is_keyword (sym->name))
1030 dump (0, "/* Settings for subcommand specifiers. */");
1037 buf = xmalloc (1024);
1042 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1046 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1051 buf[strlen (buf) - 1] = 0;
1062 /* Write out some type definitions */
1064 dump (0, "#define MAXLISTS 10");
1068 /* For every array subcommand, write out the associated enumerated
1073 for (sbc = subcommands; sbc; sbc = sbc->next)
1074 if (sbc->type == SBC_ARRAY && sbc->narray)
1076 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1084 for (spec = sbc->spec; spec; spec = spec->next)
1085 dump (0, "%s%s%s = %d,",
1086 st_upper (prefix), st_upper (sbc->prefix),
1087 st_upper (spec->varname), spec->index);
1089 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1097 /* Write out structure declaration. */
1101 dump (0, "/* %s structure. */", cmdname);
1102 dump (1, "struct cmd_%s", make_identifier (cmdname));
1104 for (sbc = subcommands; sbc; sbc = sbc->next)
1108 if (sbc != subcommands)
1111 dump (0, "/* %s subcommand. */", sbc->name);
1112 dump (0, "int sbc_%s;", st_lower (sbc->name));
1121 for (spec = sbc->spec; spec; spec = spec->next)
1125 if (sbc->type == SBC_PLAIN)
1126 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1130 dump (0, "int a_%s[%s%scount];",
1131 st_lower (sbc->name),
1133 st_upper (sbc->prefix)
1140 dump_specifier_vars (spec, sbc);
1146 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1147 st_lower (sbc->name));
1148 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1149 st_lower (sbc->name));
1153 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1154 st_lower (sbc->name));
1158 dump (0, "char *s_%s;", st_lower (sbc->name));
1163 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1167 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1171 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1172 st_lower(sbc->name));
1176 dump (0, "subc_list_int il_%s[MAXLISTS];",
1177 st_lower(sbc->name));
1190 /* Write out prototypes for custom_*() functions as necessary. */
1195 for (sbc = subcommands; sbc; sbc = sbc->next)
1196 if (sbc->type == SBC_CUSTOM)
1201 dump (0, "/* Prototype for custom subcommands of %s. */",
1204 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1205 st_lower (prefix), st_lower (sbc->name),
1206 make_identifier (cmdname));
1213 /* Prototypes for parsing and freeing functions. */
1215 dump (0, "/* Command parsing functions. */");
1216 dump (0, "static int parse_%s (struct cmd_%s *);",
1217 make_identifier (cmdname), make_identifier (cmdname));
1218 dump (0, "static void free_%s (struct cmd_%s *);",
1219 make_identifier (cmdname), make_identifier (cmdname));
1224 /* Writes out code to initialize all the variables that need
1225 initialization for particular specifier SPEC inside subcommand SBC. */
1227 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1235 st_upper (prefix), find_symbol (spec->def->con)->name);
1238 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1244 for (s = spec->s; s; s = s->next)
1246 if (s->value != VAL_NONE)
1250 assert (s->value == VAL_INT || s->value == VAL_DBL);
1251 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1253 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1259 /* Write code to initialize all variables. */
1261 dump_vars_init (int persistent)
1263 /* Loop through all the subcommands. */
1267 for (sbc = subcommands; sbc; sbc = sbc->next)
1271 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1282 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1283 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1284 st_lower (sbc->name)
1292 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1293 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1306 for (spec = sbc->spec; spec; spec = spec->next)
1307 if (spec->s == NULL)
1309 if (sbc->type == SBC_PLAIN)
1310 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1313 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1314 st_lower (sbc->name), st_lower (sbc->name));
1319 dump_specifier_init (spec, sbc);
1324 dump (0, "p->%sn_%s = 0;",
1325 st_lower (sbc->prefix), st_lower (sbc->name));
1326 dump (0, "p->%sv_%s = NULL;",
1327 st_lower (sbc->prefix), st_lower (sbc->name));
1331 dump (0, "p->%sv_%s = NULL;",
1332 st_lower (sbc->prefix), st_lower (sbc->name));
1336 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1343 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1344 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1356 /* Return a pointer to a static buffer containing an expression that
1357 will match token T. */
1359 make_match (const char *t)
1369 sprintf (s, "lex_match (T_%s)", t);
1370 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1371 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1372 "|| lex_match_id (\"TRUE\"))");
1373 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1374 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1375 "|| lex_match_id (\"FALSE\"))");
1376 else if (isdigit ((unsigned char) t[0]))
1377 sprintf (s, "lex_match_int (%s)", t);
1379 sprintf (s, "lex_match_id (\"%s\")", t);
1384 /* Write out the parsing code for specifier SPEC within subcommand
1387 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1391 if (spec->omit_kw && spec->omit_kw->next)
1392 error ("Omittable setting is not last setting in `%s' specifier.",
1394 if (spec->omit_kw && spec->omit_kw->parent->next)
1395 error ("Default specifier is not in last specifier in `%s' "
1396 "subcommand.", sbc->name);
1398 for (s = spec->s; s; s = s->next)
1400 int first = spec == sbc->spec && s == spec->s;
1402 /* Match the setting's keyword. */
1403 if (spec->omit_kw == s)
1410 dump (1, "%s;", make_match (s->specname));
1413 dump (1, "%sif (%s)", first ? "" : "else ",
1414 make_match (s->specname));
1417 /* Handle values. */
1418 if (s->value == VAL_NONE)
1419 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1420 st_upper (prefix), find_symbol (s->con)->name);
1423 if (spec->omit_kw != s)
1428 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1429 st_upper (prefix), find_symbol (s->con)->name);
1431 if ( sbc->type == SBC_ARRAY )
1432 dump (0, "p->a_%s[%s%s%s] = 1;",
1433 st_lower (sbc->name),
1434 st_upper (prefix), st_upper (sbc->prefix),
1435 st_upper (spec->varname));
1439 if (s->valtype == VT_PAREN)
1443 dump (1, "if (lex_match ('('))");
1448 dump (1, "if (!lex_match ('('))");
1450 dump (0, "msg (SE, _(\"`(' expected after %s "
1451 "specifier of %s subcommand.\"));",
1452 s->specname, sbc->name);
1453 dump (0, "goto lossage;");
1459 if (s->value == VAL_INT)
1461 dump (1, "if (!lex_is_integer ())");
1463 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1464 "requires an integer argument.\"));",
1465 s->specname, sbc->name);
1466 dump (0, "goto lossage;");
1468 dump (-1, "p->%s%s = lex_integer ();",
1469 sbc->prefix, st_lower (s->valname));
1473 dump (1, "if (!lex_is_number ())");
1475 dump (0, "msg (SE, _(\"Number expected after %s "
1476 "specifier of %s subcommand.\"));",
1477 s->specname, sbc->name);
1478 dump (0, "goto lossage;");
1480 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1481 st_lower (s->valname));
1488 str = xmalloc (MAX_TOK_LEN);
1489 str2 = xmalloc (MAX_TOK_LEN);
1490 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1491 sprintf (str, s->restriction, str2, str2, str2, str2,
1492 str2, str2, str2, str2);
1493 dump (1, "if (!(%s))", str);
1499 dump (0, "msg (SE, _(\"Bad argument for %s "
1500 "specifier of %s subcommand.\"));",
1501 s->specname, sbc->name);
1502 dump (0, "goto lossage;");
1507 dump (0, "lex_get ();");
1509 if (s->valtype == VT_PAREN)
1511 dump (1, "if (!lex_match (')'))");
1513 dump (0, "msg (SE, _(\"`)' expected after argument for "
1514 "%s specifier of %s.\"));",
1515 s->specname, sbc->name);
1516 dump (0, "goto lossage;");
1526 if (s != spec->omit_kw)
1530 if (s == spec->omit_kw)
1539 /* Write out the code to parse subcommand SBC. */
1541 dump_subcommand (const subcommand *sbc)
1543 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1547 dump (1, "while (token != '/' && token != '.')");
1553 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1556 dump_specifier_parse (spec, sbc);
1560 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1561 make_match (st_upper (spec->varname)));
1562 if (sbc->type == SBC_PLAIN)
1563 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1566 dump (0, "p->a_%s[%s%s%s] = 1;",
1567 st_lower (sbc->name),
1568 st_upper (prefix), st_upper (sbc->prefix),
1569 st_upper (spec->varname));
1579 /* This code first finds the last specifier in sbc. Then it
1580 finds the last setting within that last specifier. Either
1581 or both might be NULL. */
1594 if (spec && (!spec->s || !spec->omit_kw))
1598 dump (0, "lex_error (NULL);");
1599 dump (0, "goto lossage;");
1605 dump (0, "lex_match (',');");
1609 else if (sbc->type == SBC_VARLIST)
1611 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1613 st_lower (sbc->prefix), st_lower (sbc->name),
1614 st_lower (sbc->prefix), st_lower (sbc->name),
1615 sbc->message ? " |" : "",
1616 sbc->message ? sbc->message : "");
1617 dump (0, "goto lossage;");
1620 else if (sbc->type == SBC_VAR)
1622 dump (0, "p->%sv_%s = parse_variable ();",
1623 st_lower (sbc->prefix), st_lower (sbc->name));
1624 dump (1, "if (!p->%sv_%s)",
1625 st_lower (sbc->prefix), st_lower (sbc->name));
1626 dump (0, "goto lossage;");
1629 else if (sbc->type == SBC_STRING)
1631 if (sbc->restriction)
1636 dump (1, "if (!lex_force_string ())");
1637 dump (0, "return 0;");
1639 if (sbc->restriction)
1641 dump (0, "x = ds_length (&tokstr);");
1642 dump (1, "if (!(%s))", sbc->restriction);
1644 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1645 sbc->name, sbc->message);
1646 dump (0, "goto lossage;");
1650 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1651 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1652 st_lower (sbc->name));
1653 dump (0, "lex_get ();");
1654 if (sbc->restriction)
1657 else if (sbc->type == SBC_DBL)
1659 dump (1, "if (!lex_force_num ())");
1660 dump (0, "goto lossage;");
1661 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1662 st_lower (sbc->name), st_lower (sbc->name) );
1663 dump (0, "lex_get();");
1665 else if (sbc->type == SBC_INT)
1669 dump (1, "if (!lex_force_int ())");
1670 dump (0, "goto lossage;");
1671 dump (-1, "x = lex_integer ();");
1672 dump (0, "lex_get();");
1673 if (sbc->restriction)
1676 dump (1, "if (!(%s))", sbc->restriction);
1678 sprintf(buf,sbc->message,sbc->name);
1679 if ( sbc->translatable )
1680 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1682 dump (0, "msg (SE, \"%s\");",buf);
1683 dump (0, "goto lossage;");
1686 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1689 else if (sbc->type == SBC_PINT)
1691 dump (0, "lex_match ('(');");
1692 dump (1, "if (!lex_force_int ())");
1693 dump (0, "goto lossage;");
1694 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1695 dump (0, "lex_match (')');");
1697 else if (sbc->type == SBC_DBL_LIST)
1699 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1701 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1702 dump (0, "goto lossage;");
1705 dump (1, "while (token != '/' && token != '.')");
1707 dump (0, "lex_match(',');");
1708 dump (0, "if (!lex_force_num ())");
1710 dump (0, "goto lossage;");
1713 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1714 st_lower (sbc->name),st_lower (sbc->name)
1717 dump (0, "lex_get();");
1721 else if (sbc->type == SBC_CUSTOM)
1723 dump (1, "switch (%scustom_%s (p))",
1724 st_lower (prefix), st_lower (sbc->name));
1726 dump (1, "case 0:");
1727 dump (0, "goto lossage;");
1728 dump (-1, "case 1:");
1731 dump (-1, "case 2:");
1733 dump (0, "lex_error (NULL);");
1734 dump (0, "goto lossage;");
1735 dump (-1, "default:");
1737 dump (0, "assert (0);");
1743 /* Write out entire parser. */
1745 dump_parser (int persistent)
1751 dump (0, "static int");
1752 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1753 make_identifier (cmdname));
1756 dump_vars_init (persistent);
1758 dump (1, "for (;;)");
1762 if (def && (def->type == SBC_VARLIST))
1764 if (def->type == SBC_VARLIST)
1765 dump (1, "if (token == T_ID "
1766 "&& dict_lookup_var (default_dict, tokid) != NULL "
1767 "&& lex_look_ahead () != '=')");
1770 dump (0, "if ((token == T_ID "
1771 "&& dict_lookup_var (default_dict, tokid) "
1772 "&& lex_look_ahead () != '=')");
1773 dump (1, " || token == T_ALL)");
1776 dump (0, "p->sbc_%s++;", st_lower (def->name));
1777 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1779 st_lower (def->prefix), st_lower (def->name),
1780 st_lower (def->prefix), st_lower (def->name));
1781 dump (0, "goto lossage;");
1786 else if (def && def->type == SBC_CUSTOM)
1788 dump (1, "switch (%scustom_%s (p))",
1789 st_lower (prefix), st_lower (def->name));
1791 dump (1, "case 0:");
1792 dump (0, "goto lossage;");
1793 dump (-1, "case 1:");
1795 dump (0, "p->sbc_%s++;", st_lower (def->name));
1796 dump (0, "continue;");
1797 dump (-1, "case 2:");
1800 dump (-1, "default:");
1802 dump (0, "assert (0);");
1810 for (sbc = subcommands; sbc; sbc = sbc->next)
1812 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1816 dump (0, "lex_match ('=');");
1817 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1818 if (sbc->arity != ARITY_MANY)
1820 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1822 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1824 dump (0, "goto lossage;");
1828 dump_subcommand (sbc);
1835 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1836 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1839 dump (0, "lex_match ('=');");
1841 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1842 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1844 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1845 dump(0,"set_cmd_algorithm(ENHANCED);");
1852 dump (1, "if (!lex_match ('/'))");
1857 dump (1, "if (token != '.')");
1859 dump (0, "lex_error (_(\"expecting end of command\"));");
1860 dump (0, "goto lossage;");
1867 /* Check that mandatory subcommands have been specified */
1870 for (sbc = subcommands; sbc; sbc = sbc->next)
1873 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1875 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1877 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1879 dump (0, "goto lossage;");
1886 dump (-1, "return 1;");
1888 dump (-1, "lossage:");
1890 dump (0, "free_%s (p);", make_identifier (cmdname));
1891 dump (0, "return 0;");
1897 /* Write out the code to parse aux subcommand SBC. */
1899 dump_aux_subcommand (const subcommand *sbc)
1901 if (sbc->type == SBC_PLAIN )
1905 for (spec = sbc->spec; spec; spec = spec->next)
1908 sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1910 dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1911 dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1916 else if (sbc->type == SBC_STRING)
1918 dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1920 else if (sbc->type == SBC_INT)
1924 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1925 dump (0, "msg(MM,\"%s is %%ld\",p->n_%s[i]);", sbc->name,st_lower(sbc->name) );
1929 else if (sbc->type == SBC_CUSTOM)
1931 dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1939 /* Write out auxilliary parser. */
1941 dump_aux_parser (void)
1945 aux_subcommand *asbc;
1947 /* Write out English strings for all the identifiers in the symbol table. */
1953 /* Note the squirmings necessary to make sure that the last string
1954 is not followed by a comma (is it necessary to do that ?? ) */
1955 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1956 if (!sym->unique && !is_keyword (sym->name))
1960 dump (0, "/* Strings for subcommand specifiers. */");
1961 dump (1, "static const char *settings[]=");
1967 buf = xmalloc (1024);
1971 sprintf (buf, "\"%s\",",sym->name);
1975 buf[strlen (buf) - 1] = 0;
1989 dump (0, "static int");
1990 dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1991 make_identifier (cmdname));
1994 dump (1, "for (;;)");
1998 for (sbc = subcommands; sbc; sbc = sbc->next)
2000 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
2004 dump_aux_subcommand (sbc);
2010 for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
2012 dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
2015 dump(0,"aux_%s();",make_identifier(asbc->value));
2020 dump (1, "if (!lex_match ('/'))");
2025 dump (1, "if (token != '.')");
2027 dump (0, "lex_error (_(\"expecting end of command\"));");
2028 dump (0, "goto lossage;");
2031 dump (-1, "return 1;");
2033 dump (-1, "lossage:");
2035 dump (0, "free_%s (p);", make_identifier (cmdname));
2036 dump (0, "return 0;");
2037 dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
2038 make_identifier (cmdname), make_identifier (cmdname));
2043 /* Write the output file header. */
2052 curtime = time (NULL);
2053 loctime = localtime (&curtime);
2054 timep = asctime (loctime);
2055 timep[strlen (timep) - 1] = 0;
2056 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
2058 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
2059 dump (0, " Do not modify!");
2063 /* Write out commands to free variable state. */
2065 dump_free (int persistent)
2075 for (sbc = subcommands; sbc; sbc = sbc->next)
2077 if (sbc->type == SBC_STRING)
2079 if (sbc->type == SBC_DBL_LIST)
2085 dump (0, "static void");
2086 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
2087 make_identifier (cmdname), used ? "" : " UNUSED");
2093 for (sbc = subcommands; sbc; sbc = sbc->next)
2098 dump (0, "free (p->v_variables);");
2101 dump (0, "free (p->s_%s);", st_lower (sbc->name));
2105 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
2106 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
2121 /* Returns the name of a directive found on the current input line, if
2122 any, or a null pointer if none found. */
2124 recognize_directive (void)
2126 static char directive[16];
2130 if (strncmp (sp, "/*", 2))
2132 sp = skip_ws (sp + 2);
2137 ep = strchr (sp, ')');
2143 memcpy (directive, sp, ep - sp);
2144 directive[ep - sp] = '\0';
2148 static void aux_parse (void);
2151 main (int argc, char *argv[])
2155 fail ("Syntax: q2c input.q output.c");
2158 in = fopen (ifn, "r");
2160 fail ("%s: open: %s.", ifn, strerror (errno));
2163 out = fopen (ofn, "w");
2165 fail ("%s: open: %s.", ofn, strerror (errno));
2168 buf = xmalloc (MAX_LINE_LEN);
2169 tokstr = xmalloc (MAX_TOK_LEN);
2175 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2178 const char *directive = recognize_directive ();
2179 if (directive == NULL)
2181 dump (0, "%s", buf);
2185 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2186 if (!strcmp (directive, "specification"))
2188 /* Skip leading slash-star line. */
2194 /* Skip trailing star-slash line. */
2197 else if (!strcmp (directive, "headers"))
2201 dump (0, "#include <stdlib.h>");
2202 dump (0, "#include \"alloc.h\"");
2203 dump (0, "#include \"error.h\"");
2204 dump (0, "#include \"lexer.h\"");
2205 dump (0, "#include \"settings.h\"");
2206 dump (0, "#include \"str.h\"");
2207 dump (0, "#include \"subclist.h\"");
2208 dump (0, "#include \"var.h\"");
2212 else if (!strcmp (directive, "declarations"))
2213 dump_declarations ();
2214 else if (!strcmp (directive, "functions"))
2219 else if (!strcmp (directive, "_functions"))
2224 else if (!strcmp (directive, "aux_functions"))
2230 error ("unknown directive `%s'", directive);
2232 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2237 return EXIT_SUCCESS;
2240 /* Parse an entire auxilliary specification. */
2244 aux_subcommand *sbc;
2245 aux_subcommand *prevsbc = 0 ;
2251 sbc = xmalloc(sizeof(aux_subcommand));
2252 sbc->next = prevsbc;
2253 sbc->name = xstrdup (tokstr);
2256 sbc->value = xstrdup (tokstr);
2264 /* Skip trailing star-slash line. */
2266 aux_subcommands = sbc;