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. */
540 ARITY_ONCE_EXACTLY, /* must occur exactly once */
541 ARITY_ONCE_ONLY, /* zero or once */
542 ARITY_MANY /* 0, 1, ... , inf */
545 /* A single subcommand. */
546 typedef struct subcommand subcommand;
549 subcommand *next; /* Next in the chain. */
550 char *name; /* Subcommand name. */
551 subcommand_type type; /* One of SBC_*. */
552 subcommand_arity arity; /* How many times should the subcommand occur*/
553 int narray; /* Index of next array element. */
554 const char *prefix; /* Prefix for variable and constant names. */
555 specifier *spec; /* Array of specifiers. */
557 /* SBC_STRING and SBC_INT only. */
558 char *restriction; /* Expression restricting string length. */
559 char *message; /* Error message. */
560 int translatable; /* Error message is translatable */
563 typedef struct aux_subcommand aux_subcommand;
564 struct aux_subcommand
566 aux_subcommand *next; /* Next in the chain. */
567 char *name; /* Subcommand name. */
568 char *value; /* Subcommand value */
571 static aux_subcommand *aux_subcommands ;
573 /* Name of the command; i.e., DESCRIPTIVES. */
576 /* Short prefix for the command; i.e., `dsc_'. */
579 /* List of subcommands. */
580 subcommand *subcommands;
582 /* Default subcommand if any, or NULL. */
587 void parse_subcommands (void);
589 /* Parse an entire specification. */
593 /* Get the command name and prefix. */
594 if (token != T_STRING && token != T_ID)
595 error ("Command name expected.");
596 cmdname = xstrdup (tokstr);
600 prefix = xstrdup (tokstr);
605 /* Read all the subcommands. */
608 parse_subcommands ();
611 /* Parses a single setting into S, given subcommand information SBC
612 and specifier information SPEC. */
614 parse_setting (setting *s, specifier *spec)
618 if (match_token ('*'))
621 error ("Cannot have two settings with omittable keywords.");
626 if (match_token ('!'))
629 error ("Cannot have two default settings.");
635 s->specname = xstrdup (tokstr);
636 s->con = add_symbol (s->specname, 0, 0);
641 /* Parse setting value info if necessary. */
642 if (token != '/' && token != ';' && token != '.' && token != ',')
646 s->valtype = VT_PAREN;
650 s->valtype = VT_PLAIN;
652 s->optvalue = match_token ('*');
656 else if (match_id ("D"))
659 error ("`n' or `d' expected.");
664 s->valname = xstrdup (tokstr);
671 s->restriction = xstrdup (tokstr);
675 s->restriction = NULL;
677 if (s->valtype == VT_PAREN)
682 /* Parse a single specifier into SPEC, given subcommand information
685 parse_specifier (specifier *spec, subcommand *sbc)
690 spec->omit_kw = NULL;
691 spec->varname = NULL;
695 spec->varname = xstrdup (st_lower (tokstr));
699 /* Handle array elements. */
702 spec->index = sbc->narray;
703 if (sbc->type == SBC_ARRAY)
715 if ( sbc->type == SBC_ARRAY && token == T_ID )
717 spec->varname = xstrdup (st_lower (tokstr));
718 spec->index = sbc->narray;
724 /* Parse all the settings. */
726 setting **s = &spec->s;
730 *s = xmalloc (sizeof (setting));
731 parse_setting (*s, spec);
732 if (token == ',' || token == ';' || token == '.')
741 /* Parse a list of specifiers for subcommand SBC. */
743 parse_specifiers (subcommand *sbc)
745 specifier **spec = &sbc->spec;
747 if (token == ';' || token == '.')
755 *spec = xmalloc (sizeof (specifier));
756 parse_specifier (*spec, sbc);
757 if (token == ';' || token == '.')
760 spec = &(*spec)->next;
762 (*spec)->next = NULL;
765 /* Parse a subcommand into SBC. */
767 parse_subcommand (subcommand *sbc)
769 sbc->arity = ARITY_MANY;
771 if (match_token ('*'))
774 error ("Multiple default subcommands.");
778 if ( match_token('+'))
779 sbc->arity = ARITY_ONCE_ONLY ;
780 else if (match_token('^'))
781 sbc->arity = ARITY_ONCE_EXACTLY ;
785 sbc->name = xstrdup (tokstr);
789 sbc->type = SBC_PLAIN;
791 sbc->translatable = 0;
793 if (match_token ('['))
796 sbc->prefix = xstrdup (st_lower (tokstr));
802 sbc->type = SBC_ARRAY;
803 parse_specifiers (sbc);
808 if (match_token ('('))
811 sbc->prefix = xstrdup (st_lower (tokstr));
821 if (match_id ("VAR"))
823 if (match_id ("VARLIST"))
825 if (match_token ('('))
828 sbc->message = xstrdup (tokstr);
833 else sbc->message = NULL;
835 sbc->type = SBC_VARLIST;
837 else if (match_id ("INTEGER"))
839 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
840 if ( token == T_STRING)
842 sbc->restriction = xstrdup (tokstr);
844 if ( match_id("N_") )
850 sbc->translatable = 1;
856 sbc->message = xstrdup (tokstr);
859 sbc->restriction = NULL;
861 else if (match_id ("PINT"))
862 sbc->type = SBC_PINT;
863 else if (match_id ("DOUBLE"))
865 if ( match_id ("LIST") )
866 sbc->type = SBC_DBL_LIST;
870 else if (match_id ("STRING"))
872 sbc->type = SBC_STRING;
873 if (token == T_STRING)
875 sbc->restriction = xstrdup (tokstr);
878 sbc->message = xstrdup (tokstr);
882 sbc->restriction = NULL;
884 else if (match_id ("CUSTOM"))
885 sbc->type = SBC_CUSTOM;
887 parse_specifiers (sbc);
891 /* Parse all the subcommands. */
893 parse_subcommands (void)
895 subcommand **sbc = &subcommands;
899 *sbc = xmalloc (sizeof (subcommand));
902 parse_subcommand (*sbc);
914 #define BASE_INDENT 2 /* Starting indent. */
915 #define INC_INDENT 2 /* Indent increment. */
917 /* Increment the indent. */
918 #define indent() indent += INC_INDENT
919 #define outdent() indent -= INC_INDENT
921 /* Size of the indent from the left margin. */
924 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
926 /* Write line FORMAT to the output file, formatted as with printf,
927 indented `indent' characters from the left margin. If INDENTION is
928 greater than 0, indents BASE_INDENT * INDENTION characters after
929 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
930 * INDENTION characters _before_ writing the line. */
932 dump (int indention, const char *format, ...)
938 indent += BASE_INDENT * indention;
941 va_start (args, format);
942 for (i = 0; i < indent; i++)
944 vfprintf (out, format, args);
949 indent += BASE_INDENT * indention;
952 /* Write the structure members for specifier SPEC to the output file.
953 SBC is the including subcommand. */
955 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
958 dump (0, "long %s%s;", sbc->prefix, spec->varname);
963 for (s = spec->s; s; s = s->next)
965 if (s->value != VAL_NONE)
967 const char *typename;
969 assert (s->value == VAL_INT || s->value == VAL_DBL);
970 typename = s->value == VAL_INT ? "long" : "double";
972 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
978 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
980 is_keyword (const char *t)
982 static const char *kw[] =
984 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
985 "NE", "ALL", "BY", "TO", "WITH", 0,
989 for (cp = kw; *cp; cp++)
990 if (!strcmp (t, *cp))
995 /* Transforms a string NAME into a valid C identifier: makes
996 everything lowercase and maps nonalphabetic characters to
997 underscores. Returns a pointer to a static buffer. */
999 make_identifier (const char *name)
1001 char *p = get_buffer ();
1004 for (cp = p; *name; name++)
1005 if (isalpha ((unsigned char) *name))
1006 *cp++ = tolower ((unsigned char) (*name));
1014 /* Writes the struct and enum declarations for the parser. */
1016 dump_declarations (void)
1020 /* Write out enums for all the identifiers in the symbol table. */
1026 /* Note the squirmings necessary to make sure that the last enum
1027 is not followed by a comma, as mandated by ANSI C89. */
1028 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1029 if (!sym->unique && !is_keyword (sym->name))
1033 dump (0, "/* Settings for subcommand specifiers. */");
1040 buf = xmalloc (1024);
1045 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1049 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1054 buf[strlen (buf) - 1] = 0;
1065 /* Write out some type definitions */
1067 dump (0, "#define MAXLISTS 10");
1071 /* For every array subcommand, write out the associated enumerated
1076 for (sbc = subcommands; sbc; sbc = sbc->next)
1077 if (sbc->type == SBC_ARRAY && sbc->narray)
1079 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1087 for (spec = sbc->spec; spec; spec = spec->next)
1088 dump (0, "%s%s%s = %d,",
1089 st_upper (prefix), st_upper (sbc->prefix),
1090 st_upper (spec->varname), spec->index);
1092 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1100 /* Write out structure declaration. */
1104 dump (0, "/* %s structure. */", cmdname);
1105 dump (1, "struct cmd_%s", make_identifier (cmdname));
1107 for (sbc = subcommands; sbc; sbc = sbc->next)
1111 if (sbc != subcommands)
1114 dump (0, "/* %s subcommand. */", sbc->name);
1115 dump (0, "int sbc_%s;", st_lower (sbc->name));
1124 for (spec = sbc->spec; spec; spec = spec->next)
1128 if (sbc->type == SBC_PLAIN)
1129 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1133 dump (0, "int a_%s[%s%scount];",
1134 st_lower (sbc->name),
1136 st_upper (sbc->prefix)
1143 dump_specifier_vars (spec, sbc);
1149 dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1150 st_lower (sbc->name));
1151 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1152 st_lower (sbc->name));
1156 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1157 st_lower (sbc->name));
1161 dump (0, "char *s_%s;", st_lower (sbc->name));
1166 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1170 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1174 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1175 st_lower(sbc->name));
1179 dump (0, "subc_list_int il_%s[MAXLISTS];",
1180 st_lower(sbc->name));
1193 /* Write out prototypes for custom_*() functions as necessary. */
1198 for (sbc = subcommands; sbc; sbc = sbc->next)
1199 if (sbc->type == SBC_CUSTOM)
1204 dump (0, "/* Prototype for custom subcommands of %s. */",
1207 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1208 st_lower (prefix), st_lower (sbc->name),
1209 make_identifier (cmdname));
1216 /* Prototypes for parsing and freeing functions. */
1218 dump (0, "/* Command parsing functions. */");
1219 dump (0, "static int parse_%s (struct cmd_%s *);",
1220 make_identifier (cmdname), make_identifier (cmdname));
1221 dump (0, "static void free_%s (struct cmd_%s *);",
1222 make_identifier (cmdname), make_identifier (cmdname));
1227 /* Writes out code to initialize all the variables that need
1228 initialization for particular specifier SPEC inside subcommand SBC. */
1230 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1238 st_upper (prefix), find_symbol (spec->def->con)->name);
1241 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1247 for (s = spec->s; s; s = s->next)
1249 if (s->value != VAL_NONE)
1253 assert (s->value == VAL_INT || s->value == VAL_DBL);
1254 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1256 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1262 /* Write code to initialize all variables. */
1264 dump_vars_init (int persistent)
1266 /* Loop through all the subcommands. */
1270 for (sbc = subcommands; sbc; sbc = sbc->next)
1274 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1285 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1286 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1287 st_lower (sbc->name)
1295 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1296 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1309 for (spec = sbc->spec; spec; spec = spec->next)
1310 if (spec->s == NULL)
1312 if (sbc->type == SBC_PLAIN)
1313 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1316 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1317 st_lower (sbc->name), st_lower (sbc->name));
1322 dump_specifier_init (spec, sbc);
1327 dump (0, "p->%sn_%s = 0;",
1328 st_lower (sbc->prefix), st_lower (sbc->name));
1329 dump (0, "p->%sv_%s = NULL;",
1330 st_lower (sbc->prefix), st_lower (sbc->name));
1334 dump (0, "p->%sv_%s = NULL;",
1335 st_lower (sbc->prefix), st_lower (sbc->name));
1339 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1346 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1347 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1359 /* Return a pointer to a static buffer containing an expression that
1360 will match token T. */
1362 make_match (const char *t)
1372 sprintf (s, "lex_match (T_%s)", t);
1373 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1374 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1375 "|| lex_match_id (\"TRUE\"))");
1376 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1377 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1378 "|| lex_match_id (\"FALSE\"))");
1379 else if (isdigit ((unsigned char) t[0]))
1380 sprintf (s, "lex_match_int (%s)", t);
1382 sprintf (s, "lex_match_id (\"%s\")", t);
1387 /* Write out the parsing code for specifier SPEC within subcommand
1390 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1394 if (spec->omit_kw && spec->omit_kw->next)
1395 error ("Omittable setting is not last setting in `%s' specifier.",
1397 if (spec->omit_kw && spec->omit_kw->parent->next)
1398 error ("Default specifier is not in last specifier in `%s' "
1399 "subcommand.", sbc->name);
1401 for (s = spec->s; s; s = s->next)
1403 int first = spec == sbc->spec && s == spec->s;
1405 /* Match the setting's keyword. */
1406 if (spec->omit_kw == s)
1413 dump (1, "%s;", make_match (s->specname));
1416 dump (1, "%sif (%s)", first ? "" : "else ",
1417 make_match (s->specname));
1420 /* Handle values. */
1421 if (s->value == VAL_NONE)
1422 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1423 st_upper (prefix), find_symbol (s->con)->name);
1426 if (spec->omit_kw != s)
1431 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1432 st_upper (prefix), find_symbol (s->con)->name);
1434 if ( sbc->type == SBC_ARRAY )
1435 dump (0, "p->a_%s[%s%s%s] = 1;",
1436 st_lower (sbc->name),
1437 st_upper (prefix), st_upper (sbc->prefix),
1438 st_upper (spec->varname));
1442 if (s->valtype == VT_PAREN)
1446 dump (1, "if (lex_match ('('))");
1451 dump (1, "if (!lex_match ('('))");
1453 dump (0, "msg (SE, _(\"`(' expected after %s "
1454 "specifier of %s subcommand.\"));",
1455 s->specname, sbc->name);
1456 dump (0, "goto lossage;");
1462 if (s->value == VAL_INT)
1464 dump (1, "if (!lex_is_integer ())");
1466 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1467 "requires an integer argument.\"));",
1468 s->specname, sbc->name);
1469 dump (0, "goto lossage;");
1471 dump (-1, "p->%s%s = lex_integer ();",
1472 sbc->prefix, st_lower (s->valname));
1476 dump (1, "if (!lex_is_number ())");
1478 dump (0, "msg (SE, _(\"Number expected after %s "
1479 "specifier of %s subcommand.\"));",
1480 s->specname, sbc->name);
1481 dump (0, "goto lossage;");
1483 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1484 st_lower (s->valname));
1491 str = xmalloc (MAX_TOK_LEN);
1492 str2 = xmalloc (MAX_TOK_LEN);
1493 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1494 sprintf (str, s->restriction, str2, str2, str2, str2,
1495 str2, str2, str2, str2);
1496 dump (1, "if (!(%s))", str);
1502 dump (0, "msg (SE, _(\"Bad argument for %s "
1503 "specifier of %s subcommand.\"));",
1504 s->specname, sbc->name);
1505 dump (0, "goto lossage;");
1510 dump (0, "lex_get ();");
1512 if (s->valtype == VT_PAREN)
1514 dump (1, "if (!lex_match (')'))");
1516 dump (0, "msg (SE, _(\"`)' expected after argument for "
1517 "%s specifier of %s.\"));",
1518 s->specname, sbc->name);
1519 dump (0, "goto lossage;");
1529 if (s != spec->omit_kw)
1533 if (s == spec->omit_kw)
1542 /* Write out the code to parse subcommand SBC. */
1544 dump_subcommand (const subcommand *sbc)
1546 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1550 dump (1, "while (token != '/' && token != '.')");
1556 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1559 dump_specifier_parse (spec, sbc);
1563 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1564 make_match (st_upper (spec->varname)));
1565 if (sbc->type == SBC_PLAIN)
1566 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1569 dump (0, "p->a_%s[%s%s%s] = 1;",
1570 st_lower (sbc->name),
1571 st_upper (prefix), st_upper (sbc->prefix),
1572 st_upper (spec->varname));
1582 /* This code first finds the last specifier in sbc. Then it
1583 finds the last setting within that last specifier. Either
1584 or both might be NULL. */
1597 if (spec && (!spec->s || !spec->omit_kw))
1601 dump (0, "lex_error (NULL);");
1602 dump (0, "goto lossage;");
1608 dump (0, "lex_match (',');");
1612 else if (sbc->type == SBC_VARLIST)
1614 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1616 st_lower (sbc->prefix), st_lower (sbc->name),
1617 st_lower (sbc->prefix), st_lower (sbc->name),
1618 sbc->message ? " |" : "",
1619 sbc->message ? sbc->message : "");
1620 dump (0, "goto lossage;");
1623 else if (sbc->type == SBC_VAR)
1625 dump (0, "p->%sv_%s = parse_variable ();",
1626 st_lower (sbc->prefix), st_lower (sbc->name));
1627 dump (1, "if (!p->%sv_%s)",
1628 st_lower (sbc->prefix), st_lower (sbc->name));
1629 dump (0, "goto lossage;");
1632 else if (sbc->type == SBC_STRING)
1634 if (sbc->restriction)
1639 dump (1, "if (!lex_force_string ())");
1640 dump (0, "return 0;");
1642 if (sbc->restriction)
1644 dump (0, "x = ds_length (&tokstr);");
1645 dump (1, "if (!(%s))", sbc->restriction);
1647 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1648 sbc->name, sbc->message);
1649 dump (0, "goto lossage;");
1653 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1654 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1655 st_lower (sbc->name));
1656 dump (0, "lex_get ();");
1657 if (sbc->restriction)
1660 else if (sbc->type == SBC_DBL)
1662 dump (1, "if (!lex_force_num ())");
1663 dump (0, "goto lossage;");
1664 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1665 st_lower (sbc->name), st_lower (sbc->name) );
1666 dump (0, "lex_get();");
1668 else if (sbc->type == SBC_INT)
1672 dump (1, "if (!lex_force_int ())");
1673 dump (0, "goto lossage;");
1674 dump (-1, "x = lex_integer ();");
1675 dump (0, "lex_get();");
1676 if (sbc->restriction)
1679 dump (1, "if (!(%s))", sbc->restriction);
1681 sprintf(buf,sbc->message,sbc->name);
1682 if ( sbc->translatable )
1683 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1685 dump (0, "msg (SE, \"%s\");",buf);
1686 dump (0, "goto lossage;");
1689 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1692 else if (sbc->type == SBC_PINT)
1694 dump (0, "lex_match ('(');");
1695 dump (1, "if (!lex_force_int ())");
1696 dump (0, "goto lossage;");
1697 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1698 dump (0, "lex_match (')');");
1700 else if (sbc->type == SBC_DBL_LIST)
1702 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1704 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1705 dump (0, "goto lossage;");
1708 dump (1, "while (token != '/' && token != '.')");
1710 dump (0, "lex_match(',');");
1711 dump (0, "if (!lex_force_num ())");
1713 dump (0, "goto lossage;");
1716 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1717 st_lower (sbc->name),st_lower (sbc->name)
1720 dump (0, "lex_get();");
1724 else if (sbc->type == SBC_CUSTOM)
1726 dump (1, "switch (%scustom_%s (p))",
1727 st_lower (prefix), st_lower (sbc->name));
1729 dump (1, "case 0:");
1730 dump (0, "goto lossage;");
1731 dump (-1, "case 1:");
1734 dump (-1, "case 2:");
1736 dump (0, "lex_error (NULL);");
1737 dump (0, "goto lossage;");
1738 dump (-1, "default:");
1740 dump (0, "assert (0);");
1746 /* Write out entire parser. */
1748 dump_parser (int persistent)
1754 dump (0, "static int");
1755 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1756 make_identifier (cmdname));
1759 dump_vars_init (persistent);
1761 dump (1, "for (;;)");
1765 if (def && (def->type == SBC_VARLIST))
1767 if (def->type == SBC_VARLIST)
1768 dump (1, "if (token == T_ID "
1769 "&& dict_lookup_var (default_dict, tokid) != NULL "
1770 "&& lex_look_ahead () != '=')");
1773 dump (0, "if ((token == T_ID "
1774 "&& dict_lookup_var (default_dict, tokid) "
1775 "&& lex_look_ahead () != '=')");
1776 dump (1, " || token == T_ALL)");
1779 dump (0, "p->sbc_%s++;", st_lower (def->name));
1780 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1782 st_lower (def->prefix), st_lower (def->name),
1783 st_lower (def->prefix), st_lower (def->name));
1784 dump (0, "goto lossage;");
1789 else if (def && def->type == SBC_CUSTOM)
1791 dump (1, "switch (%scustom_%s (p))",
1792 st_lower (prefix), st_lower (def->name));
1794 dump (1, "case 0:");
1795 dump (0, "goto lossage;");
1796 dump (-1, "case 1:");
1798 dump (0, "p->sbc_%s++;", st_lower (def->name));
1799 dump (0, "continue;");
1800 dump (-1, "case 2:");
1803 dump (-1, "default:");
1805 dump (0, "assert (0);");
1813 for (sbc = subcommands; sbc; sbc = sbc->next)
1815 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1819 dump (0, "lex_match ('=');");
1820 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1821 if (sbc->arity != ARITY_MANY)
1823 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1825 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1827 dump (0, "goto lossage;");
1831 dump_subcommand (sbc);
1838 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1839 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1842 dump (0, "lex_match ('=');");
1844 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1845 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1847 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1848 dump(0,"set_cmd_algorithm(ENHANCED);");
1855 dump (1, "if (!lex_match ('/'))");
1860 dump (1, "if (token != '.')");
1862 dump (0, "lex_error (_(\"expecting end of command\"));");
1863 dump (0, "goto lossage;");
1870 /* Check that mandatory subcommands have been specified */
1873 for (sbc = subcommands; sbc; sbc = sbc->next)
1876 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1878 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1880 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1882 dump (0, "goto lossage;");
1889 dump (-1, "return 1;");
1891 dump (-1, "lossage:");
1893 dump (0, "free_%s (p);", make_identifier (cmdname));
1894 dump (0, "return 0;");
1900 /* Write out the code to parse aux subcommand SBC. */
1902 dump_aux_subcommand (const subcommand *sbc)
1904 if (sbc->type == SBC_PLAIN )
1908 for (spec = sbc->spec; spec; spec = spec->next)
1911 sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1913 dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1914 dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1919 else if (sbc->type == SBC_STRING)
1921 dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1923 else if (sbc->type == SBC_INT)
1927 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1928 dump (0, "msg(MM,\"%s is %%ld\",p->n_%s[i]);", sbc->name,st_lower(sbc->name) );
1932 else if (sbc->type == SBC_CUSTOM)
1934 dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1942 /* Write out auxilliary parser. */
1944 dump_aux_parser (void)
1948 aux_subcommand *asbc;
1950 /* Write out English strings for all the identifiers in the symbol table. */
1956 /* Note the squirmings necessary to make sure that the last string
1957 is not followed by a comma (is it necessary to do that ?? ) */
1958 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1959 if (!sym->unique && !is_keyword (sym->name))
1963 dump (0, "/* Strings for subcommand specifiers. */");
1964 dump (1, "static const char *settings[]=");
1970 buf = xmalloc (1024);
1974 sprintf (buf, "\"%s\",",sym->name);
1978 buf[strlen (buf) - 1] = 0;
1992 dump (0, "static int");
1993 dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1994 make_identifier (cmdname));
1997 dump (1, "for (;;)");
2001 for (sbc = subcommands; sbc; sbc = sbc->next)
2003 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
2007 dump_aux_subcommand (sbc);
2013 for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
2015 dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
2018 dump(0,"aux_%s();",make_identifier(asbc->value));
2023 dump (1, "if (!lex_match ('/'))");
2028 dump (1, "if (token != '.')");
2030 dump (0, "lex_error (_(\"expecting end of command\"));");
2031 dump (0, "goto lossage;");
2034 dump (-1, "return 1;");
2036 dump (-1, "lossage:");
2038 dump (0, "free_%s (p);", make_identifier (cmdname));
2039 dump (0, "return 0;");
2040 dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */",
2041 make_identifier (cmdname), make_identifier (cmdname));
2046 /* Write the output file header. */
2055 curtime = time (NULL);
2056 loctime = localtime (&curtime);
2057 timep = asctime (loctime);
2058 timep[strlen (timep) - 1] = 0;
2059 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
2061 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
2062 dump (0, " Do not modify!");
2066 /* Write out commands to free variable state. */
2068 dump_free (int persistent)
2078 for (sbc = subcommands; sbc; sbc = sbc->next)
2080 if (sbc->type == SBC_STRING)
2082 if (sbc->type == SBC_DBL_LIST)
2088 dump (0, "static void");
2089 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
2090 make_identifier (cmdname), used ? "" : " UNUSED");
2096 for (sbc = subcommands; sbc; sbc = sbc->next)
2101 dump (0, "free (p->v_variables);");
2104 dump (0, "free (p->s_%s);", st_lower (sbc->name));
2108 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
2109 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
2124 /* Returns the name of a directive found on the current input line, if
2125 any, or a null pointer if none found. */
2127 recognize_directive (void)
2129 static char directive[16];
2133 if (strncmp (sp, "/*", 2))
2135 sp = skip_ws (sp + 2);
2140 ep = strchr (sp, ')');
2146 memcpy (directive, sp, ep - sp);
2147 directive[ep - sp] = '\0';
2151 static void aux_parse (void);
2154 main (int argc, char *argv[])
2158 fail ("Syntax: q2c input.q output.c");
2161 in = fopen (ifn, "r");
2163 fail ("%s: open: %s.", ifn, strerror (errno));
2166 out = fopen (ofn, "w");
2168 fail ("%s: open: %s.", ofn, strerror (errno));
2171 buf = xmalloc (MAX_LINE_LEN);
2172 tokstr = xmalloc (MAX_TOK_LEN);
2178 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2181 const char *directive = recognize_directive ();
2182 if (directive == NULL)
2184 dump (0, "%s", buf);
2188 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2189 if (!strcmp (directive, "specification"))
2191 /* Skip leading slash-star line. */
2197 /* Skip trailing star-slash line. */
2200 else if (!strcmp (directive, "headers"))
2204 dump (0, "#include <stdlib.h>");
2205 dump (0, "#include \"alloc.h\"");
2206 dump (0, "#include \"error.h\"");
2207 dump (0, "#include \"lexer.h\"");
2208 dump (0, "#include \"settings.h\"");
2209 dump (0, "#include \"str.h\"");
2210 dump (0, "#include \"subclist.h\"");
2211 dump (0, "#include \"var.h\"");
2215 else if (!strcmp (directive, "declarations"))
2216 dump_declarations ();
2217 else if (!strcmp (directive, "functions"))
2222 else if (!strcmp (directive, "_functions"))
2227 else if (!strcmp (directive, "aux_functions"))
2233 error ("unknown directive `%s'", directive);
2235 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2240 return EXIT_SUCCESS;
2243 /* Parse an entire auxilliary specification. */
2247 aux_subcommand *sbc;
2248 aux_subcommand *prevsbc = 0 ;
2254 sbc = xmalloc(sizeof(aux_subcommand));
2255 sbc->next = prevsbc;
2256 sbc->name = xstrdup (tokstr);
2259 sbc->value = xstrdup (tokstr);
2267 /* Skip trailing star-slash line. */
2269 aux_subcommands = sbc;