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
37 #define EXIT_SUCCESS 0
41 #define EXIT_FAILURE 1
46 #include "misc/strerror.c"
50 #include "debug-print.h"
52 /* Max length of an input line. */
53 #define MAX_LINE_LEN 1024
55 /* Max token length. */
56 #define MAX_TOK_LEN 1024
61 /* Have the input and output files been opened yet? */
64 /* Input, output files. */
67 /* Input, output file names. */
70 /* Input, output file line number. */
73 /* Input line buffer, current position. */
79 T_STRING = 256, /* String literal. */
80 T_ID = 257 /* Identifier. */
83 /* Current token: either one of the above, or a single character. */
86 /* Token string value. */
89 /* Utility functions. */
93 /* Close all open files and delete the output file, on failure. */
102 if (remove (ofn) == -1)
103 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
106 void hcf (void) NO_RETURN;
108 /* Terminate unsuccessfully. */
116 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
117 int error (const char *, ...) PRINTF_FORMAT (1, 2);
119 /* Output an error message and terminate unsuccessfully. */
121 fail (const char *format, ...)
125 va_start (args, format);
126 fprintf (stderr, "%s: ", program_name);
127 vfprintf (stderr, format, args);
128 fprintf (stderr, "\n");
134 /* Output a context-dependent error message and terminate
137 error (const char *format,...)
141 va_start (args, format);
142 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
143 vfprintf (stderr, format, args);
144 fprintf (stderr, "\n");
150 #define VME "virtual memory exhausted"
152 /* Allocate a block of SIZE bytes and return a pointer to its
155 xmalloc (size_t size)
164 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
169 /* Make a dynamically allocated copy of string S and return a pointer
170 to the first character. */
172 xstrdup (const char *s)
178 size = strlen (s) + 1;
182 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
188 /* Returns a pointer to one of 8 static buffers. The buffers are used
193 static char b[8][256];
202 /* Copies a string to a static buffer, converting it to lowercase in
203 the process, and returns a pointer to the static buffer. */
205 st_lower (const char *s)
209 p = cp = get_buffer ();
211 *cp++ = tolower ((unsigned char) (*s++));
217 /* Copies a string to a static buffer, converting it to uppercase in
218 the process, and returns a pointer to the static buffer. */
220 st_upper (const char *s)
224 p = cp = get_buffer ();
226 *cp++ = toupper ((unsigned char) (*s++));
232 /* Returns the address of the first non-whitespace character in S, or
233 the address of the null terminator if none. */
235 skip_ws (const char *s)
237 while (isspace ((unsigned char) *s))
242 /* Read one line from the input file into buf. Lines having special
243 formats are handled specially. */
248 if (0 == fgets (buf, MAX_LINE_LEN, in))
251 fail ("%s: fgets: %s", ifn, strerror (errno));
255 cp = strchr (buf, '\n');
263 /* Symbol table manager. */
265 /* Symbol table entry. */
266 typedef struct symbol symbol;
269 symbol *next; /* Next symbol in symbol table. */
270 char *name; /* Symbol name. */
271 int unique; /* 1=Name must be unique in this file. */
272 int ln; /* Line number of definition. */
273 int value; /* Symbol value. */
279 /* Add a symbol to the symbol table having name NAME, uniqueness
280 UNIQUE, and value VALUE. If a symbol having the same name is found
281 in the symbol table, its sequence number is returned and the symbol
282 table is not modified. Otherwise, the symbol is added and the next
283 available sequence number is returned. */
285 add_symbol (const char *name, int unique, int value)
290 sym = xmalloc (sizeof *sym);
291 sym->name = xstrdup (name);
292 sym->unique = unique;
305 if (!strcmp (iter->name, name))
309 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
311 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
328 /* Finds the symbol having given sequence number X within the symbol
329 table, and returns the associated symbol structure. */
336 while (x > 1 && iter)
346 /* Writes a printable representation of the current token to
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 /* Name of the command; i.e., DESCRIPTIVES. */
566 /* Short prefix for the command; i.e., `dsc_'. */
569 /* List of subcommands. */
570 subcommand *subcommands;
572 /* Default subcommand if any, or NULL. */
577 void parse_subcommands (void);
579 /* Parse an entire specification. */
583 /* Get the command name and prefix. */
584 if (token != T_STRING && token != T_ID)
585 error ("Command name expected.");
586 cmdname = xstrdup (tokstr);
590 prefix = xstrdup (tokstr);
595 /* Read all the subcommands. */
598 parse_subcommands ();
601 /* Parses a single setting into S, given subcommand information SBC
602 and specifier information SPEC. */
604 parse_setting (setting *s, specifier *spec)
608 if (match_token ('*'))
611 error ("Cannot have two settings with omittable keywords.");
616 if (match_token ('!'))
619 error ("Cannot have two default settings.");
625 s->specname = xstrdup (tokstr);
626 s->con = add_symbol (s->specname, 0, 0);
631 /* Parse setting value info if necessary. */
632 if (token != '/' && token != ';' && token != '.' && token != ',')
636 s->valtype = VT_PAREN;
640 s->valtype = VT_PLAIN;
642 s->optvalue = match_token ('*');
646 else if (match_id ("D"))
649 error ("`n' or `d' expected.");
654 s->valname = xstrdup (tokstr);
661 s->restriction = xstrdup (tokstr);
665 s->restriction = NULL;
667 if (s->valtype == VT_PAREN)
672 /* Parse a single specifier into SPEC, given subcommand information
675 parse_specifier (specifier *spec, subcommand *sbc)
680 spec->omit_kw = NULL;
681 spec->varname = NULL;
685 spec->varname = xstrdup (st_lower (tokstr));
689 /* Handle array elements. */
692 spec->index = sbc->narray;
693 if (sbc->type == SBC_ARRAY)
705 if ( sbc->type == SBC_ARRAY && token == T_ID )
707 spec->varname = xstrdup (st_lower (tokstr));
708 spec->index = sbc->narray;
714 /* Parse all the settings. */
716 setting **s = &spec->s;
720 *s = xmalloc (sizeof **s);
721 parse_setting (*s, spec);
722 if (token == ',' || token == ';' || token == '.')
731 /* Parse a list of specifiers for subcommand SBC. */
733 parse_specifiers (subcommand *sbc)
735 specifier **spec = &sbc->spec;
737 if (token == ';' || token == '.')
745 *spec = xmalloc (sizeof **spec);
746 parse_specifier (*spec, sbc);
747 if (token == ';' || token == '.')
750 spec = &(*spec)->next;
752 (*spec)->next = NULL;
755 /* Parse a subcommand into SBC. */
757 parse_subcommand (subcommand *sbc)
759 sbc->arity = ARITY_MANY;
761 if (match_token ('*'))
764 error ("Multiple default subcommands.");
768 if ( match_token('+'))
769 sbc->arity = ARITY_ONCE_ONLY ;
770 else if (match_token('^'))
771 sbc->arity = ARITY_ONCE_EXACTLY ;
775 sbc->name = xstrdup (tokstr);
779 sbc->type = SBC_PLAIN;
781 sbc->translatable = 0;
783 if (match_token ('['))
786 sbc->prefix = xstrdup (st_lower (tokstr));
792 sbc->type = SBC_ARRAY;
793 parse_specifiers (sbc);
798 if (match_token ('('))
801 sbc->prefix = xstrdup (st_lower (tokstr));
811 if (match_id ("VAR"))
813 if (match_id ("VARLIST"))
815 if (match_token ('('))
818 sbc->message = xstrdup (tokstr);
823 else sbc->message = NULL;
825 sbc->type = SBC_VARLIST;
827 else if (match_id ("INTEGER"))
829 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
830 if ( token == T_STRING)
832 sbc->restriction = xstrdup (tokstr);
834 if ( match_id("N_") )
840 sbc->translatable = 1;
846 sbc->message = xstrdup (tokstr);
849 sbc->restriction = NULL;
851 else if (match_id ("PINT"))
852 sbc->type = SBC_PINT;
853 else if (match_id ("DOUBLE"))
855 if ( match_id ("LIST") )
856 sbc->type = SBC_DBL_LIST;
860 else if (match_id ("STRING"))
862 sbc->type = SBC_STRING;
863 if (token == T_STRING)
865 sbc->restriction = xstrdup (tokstr);
868 sbc->message = xstrdup (tokstr);
872 sbc->restriction = NULL;
874 else if (match_id ("CUSTOM"))
875 sbc->type = SBC_CUSTOM;
877 parse_specifiers (sbc);
881 /* Parse all the subcommands. */
883 parse_subcommands (void)
885 subcommand **sbc = &subcommands;
889 *sbc = xmalloc (sizeof **sbc);
892 parse_subcommand (*sbc);
904 #define BASE_INDENT 2 /* Starting indent. */
905 #define INC_INDENT 2 /* Indent increment. */
907 /* Increment the indent. */
908 #define indent() indent += INC_INDENT
909 #define outdent() indent -= INC_INDENT
911 /* Size of the indent from the left margin. */
914 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
916 /* Write line FORMAT to the output file, formatted as with printf,
917 indented `indent' characters from the left margin. If INDENTION is
918 greater than 0, indents BASE_INDENT * INDENTION characters after
919 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
920 * INDENTION characters _before_ writing the line. */
922 dump (int indention, const char *format, ...)
928 indent += BASE_INDENT * indention;
931 va_start (args, format);
932 for (i = 0; i < indent; i++)
934 vfprintf (out, format, args);
939 indent += BASE_INDENT * indention;
942 /* Write the structure members for specifier SPEC to the output file.
943 SBC is the including subcommand. */
945 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
948 dump (0, "long %s%s;", sbc->prefix, spec->varname);
953 for (s = spec->s; s; s = s->next)
955 if (s->value != VAL_NONE)
957 const char *typename;
959 assert (s->value == VAL_INT || s->value == VAL_DBL);
960 typename = s->value == VAL_INT ? "long" : "double";
962 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
968 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
970 is_keyword (const char *t)
972 static const char *kw[] =
974 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
975 "NE", "ALL", "BY", "TO", "WITH", 0,
979 for (cp = kw; *cp; cp++)
980 if (!strcmp (t, *cp))
985 /* Transforms a string NAME into a valid C identifier: makes
986 everything lowercase and maps nonalphabetic characters to
987 underscores. Returns a pointer to a static buffer. */
989 make_identifier (const char *name)
991 char *p = get_buffer ();
994 for (cp = p; *name; name++)
995 if (isalpha ((unsigned char) *name))
996 *cp++ = tolower ((unsigned char) (*name));
1004 /* Writes the struct and enum declarations for the parser. */
1006 dump_declarations (void)
1010 /* Write out enums for all the identifiers in the symbol table. */
1016 /* Note the squirmings necessary to make sure that the last enum
1017 is not followed by a comma, as mandated by ANSI C89. */
1018 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1019 if (!sym->unique && !is_keyword (sym->name))
1023 dump (0, "/* Settings for subcommand specifiers. */");
1030 buf = xmalloc (1024);
1035 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1039 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1044 buf[strlen (buf) - 1] = 0;
1055 /* Write out some type definitions */
1057 dump (0, "#define MAXLISTS 10");
1061 /* For every array subcommand, write out the associated enumerated
1066 for (sbc = subcommands; sbc; sbc = sbc->next)
1067 if (sbc->type == SBC_ARRAY && sbc->narray)
1069 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1077 for (spec = sbc->spec; spec; spec = spec->next)
1078 dump (0, "%s%s%s = %d,",
1079 st_upper (prefix), st_upper (sbc->prefix),
1080 st_upper (spec->varname), spec->index);
1082 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1090 /* Write out structure declaration. */
1094 dump (0, "/* %s structure. */", cmdname);
1095 dump (1, "struct cmd_%s", make_identifier (cmdname));
1097 for (sbc = subcommands; sbc; sbc = sbc->next)
1101 if (sbc != subcommands)
1104 dump (0, "/* %s subcommand. */", sbc->name);
1105 dump (0, "int sbc_%s;", st_lower (sbc->name));
1114 for (spec = sbc->spec; spec; spec = spec->next)
1118 if (sbc->type == SBC_PLAIN)
1119 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1123 dump (0, "int a_%s[%s%scount];",
1124 st_lower (sbc->name),
1126 st_upper (sbc->prefix)
1133 dump_specifier_vars (spec, sbc);
1139 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1140 st_lower (sbc->name));
1141 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1142 st_lower (sbc->name));
1146 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1147 st_lower (sbc->name));
1151 dump (0, "char *s_%s;", st_lower (sbc->name));
1156 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1160 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1164 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1165 st_lower(sbc->name));
1169 dump (0, "subc_list_int il_%s[MAXLISTS];",
1170 st_lower(sbc->name));
1183 /* Write out prototypes for custom_*() functions as necessary. */
1188 for (sbc = subcommands; sbc; sbc = sbc->next)
1189 if (sbc->type == SBC_CUSTOM)
1194 dump (0, "/* Prototype for custom subcommands of %s. */",
1197 dump (0, "static int %scustom_%s (struct cmd_%s *);",
1198 st_lower (prefix), st_lower (sbc->name),
1199 make_identifier (cmdname));
1206 /* Prototypes for parsing and freeing functions. */
1208 dump (0, "/* Command parsing functions. */");
1209 dump (0, "static int parse_%s (struct cmd_%s *);",
1210 make_identifier (cmdname), make_identifier (cmdname));
1211 dump (0, "static void free_%s (struct cmd_%s *);",
1212 make_identifier (cmdname), make_identifier (cmdname));
1217 /* Writes out code to initialize all the variables that need
1218 initialization for particular specifier SPEC inside subcommand SBC. */
1220 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1228 st_upper (prefix), find_symbol (spec->def->con)->name);
1231 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1237 for (s = spec->s; s; s = s->next)
1239 if (s->value != VAL_NONE)
1243 assert (s->value == VAL_INT || s->value == VAL_DBL);
1244 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1246 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1252 /* Write code to initialize all variables. */
1254 dump_vars_init (int persistent)
1256 /* Loop through all the subcommands. */
1260 for (sbc = subcommands; sbc; sbc = sbc->next)
1264 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1275 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1276 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1277 st_lower (sbc->name)
1285 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1286 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1299 for (spec = sbc->spec; spec; spec = spec->next)
1300 if (spec->s == NULL)
1302 if (sbc->type == SBC_PLAIN)
1303 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1306 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1307 st_lower (sbc->name), st_lower (sbc->name));
1312 dump_specifier_init (spec, sbc);
1317 dump (0, "p->%sn_%s = 0;",
1318 st_lower (sbc->prefix), st_lower (sbc->name));
1319 dump (0, "p->%sv_%s = NULL;",
1320 st_lower (sbc->prefix), st_lower (sbc->name));
1324 dump (0, "p->%sv_%s = NULL;",
1325 st_lower (sbc->prefix), st_lower (sbc->name));
1329 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1336 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1337 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1349 /* Return a pointer to a static buffer containing an expression that
1350 will match token T. */
1352 make_match (const char *t)
1362 sprintf (s, "lex_match (T_%s)", t);
1363 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1364 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1365 "|| lex_match_id (\"TRUE\"))");
1366 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1367 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1368 "|| lex_match_id (\"FALSE\"))");
1369 else if (isdigit ((unsigned char) t[0]))
1370 sprintf (s, "lex_match_int (%s)", t);
1372 sprintf (s, "lex_match_id (\"%s\")", t);
1377 /* Write out the parsing code for specifier SPEC within subcommand
1380 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1384 if (spec->omit_kw && spec->omit_kw->next)
1385 error ("Omittable setting is not last setting in `%s' specifier.",
1387 if (spec->omit_kw && spec->omit_kw->parent->next)
1388 error ("Default specifier is not in last specifier in `%s' "
1389 "subcommand.", sbc->name);
1391 for (s = spec->s; s; s = s->next)
1393 int first = spec == sbc->spec && s == spec->s;
1395 /* Match the setting's keyword. */
1396 if (spec->omit_kw == s)
1403 dump (1, "%s;", make_match (s->specname));
1406 dump (1, "%sif (%s)", first ? "" : "else ",
1407 make_match (s->specname));
1410 /* Handle values. */
1411 if (s->value == VAL_NONE)
1412 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1413 st_upper (prefix), find_symbol (s->con)->name);
1416 if (spec->omit_kw != s)
1421 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1422 st_upper (prefix), find_symbol (s->con)->name);
1424 if ( sbc->type == SBC_ARRAY )
1425 dump (0, "p->a_%s[%s%s%s] = 1;",
1426 st_lower (sbc->name),
1427 st_upper (prefix), st_upper (sbc->prefix),
1428 st_upper (spec->varname));
1432 if (s->valtype == VT_PAREN)
1436 dump (1, "if (lex_match ('('))");
1441 dump (1, "if (!lex_match ('('))");
1443 dump (0, "msg (SE, _(\"`(' expected after %s "
1444 "specifier of %s subcommand.\"));",
1445 s->specname, sbc->name);
1446 dump (0, "goto lossage;");
1452 if (s->value == VAL_INT)
1454 dump (1, "if (!lex_is_integer ())");
1456 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1457 "requires an integer argument.\"));",
1458 s->specname, sbc->name);
1459 dump (0, "goto lossage;");
1461 dump (-1, "p->%s%s = lex_integer ();",
1462 sbc->prefix, st_lower (s->valname));
1466 dump (1, "if (!lex_is_number ())");
1468 dump (0, "msg (SE, _(\"Number expected after %s "
1469 "specifier of %s subcommand.\"));",
1470 s->specname, sbc->name);
1471 dump (0, "goto lossage;");
1473 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1474 st_lower (s->valname));
1481 str = xmalloc (MAX_TOK_LEN);
1482 str2 = xmalloc (MAX_TOK_LEN);
1483 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1484 sprintf (str, s->restriction, str2, str2, str2, str2,
1485 str2, str2, str2, str2);
1486 dump (1, "if (!(%s))", str);
1492 dump (0, "msg (SE, _(\"Bad argument for %s "
1493 "specifier of %s subcommand.\"));",
1494 s->specname, sbc->name);
1495 dump (0, "goto lossage;");
1500 dump (0, "lex_get ();");
1502 if (s->valtype == VT_PAREN)
1504 dump (1, "if (!lex_match (')'))");
1506 dump (0, "msg (SE, _(\"`)' expected after argument for "
1507 "%s specifier of %s.\"));",
1508 s->specname, sbc->name);
1509 dump (0, "goto lossage;");
1519 if (s != spec->omit_kw)
1523 if (s == spec->omit_kw)
1532 /* Write out the code to parse subcommand SBC. */
1534 dump_subcommand (const subcommand *sbc)
1536 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1540 dump (1, "while (token != '/' && token != '.')");
1546 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1549 dump_specifier_parse (spec, sbc);
1553 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1554 make_match (st_upper (spec->varname)));
1555 if (sbc->type == SBC_PLAIN)
1556 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1559 dump (0, "p->a_%s[%s%s%s] = 1;",
1560 st_lower (sbc->name),
1561 st_upper (prefix), st_upper (sbc->prefix),
1562 st_upper (spec->varname));
1572 /* This code first finds the last specifier in sbc. Then it
1573 finds the last setting within that last specifier. Either
1574 or both might be NULL. */
1587 if (spec && (!spec->s || !spec->omit_kw))
1591 dump (0, "lex_error (NULL);");
1592 dump (0, "goto lossage;");
1598 dump (0, "lex_match (',');");
1602 else if (sbc->type == SBC_VARLIST)
1604 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1606 st_lower (sbc->prefix), st_lower (sbc->name),
1607 st_lower (sbc->prefix), st_lower (sbc->name),
1608 sbc->message ? " |" : "",
1609 sbc->message ? sbc->message : "");
1610 dump (0, "goto lossage;");
1613 else if (sbc->type == SBC_VAR)
1615 dump (0, "p->%sv_%s = parse_variable ();",
1616 st_lower (sbc->prefix), st_lower (sbc->name));
1617 dump (1, "if (!p->%sv_%s)",
1618 st_lower (sbc->prefix), st_lower (sbc->name));
1619 dump (0, "goto lossage;");
1622 else if (sbc->type == SBC_STRING)
1624 if (sbc->restriction)
1629 dump (1, "if (!lex_force_string ())");
1630 dump (0, "return 0;");
1632 if (sbc->restriction)
1634 dump (0, "x = ds_length (&tokstr);");
1635 dump (1, "if (!(%s))", sbc->restriction);
1637 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1638 sbc->name, sbc->message);
1639 dump (0, "goto lossage;");
1643 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1644 dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
1645 st_lower (sbc->name));
1646 dump (0, "lex_get ();");
1647 if (sbc->restriction)
1650 else if (sbc->type == SBC_DBL)
1652 dump (1, "if (!lex_force_num ())");
1653 dump (0, "goto lossage;");
1654 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1655 st_lower (sbc->name), st_lower (sbc->name) );
1656 dump (0, "lex_get();");
1658 else if (sbc->type == SBC_INT)
1662 dump (1, "if (!lex_force_int ())");
1663 dump (0, "goto lossage;");
1664 dump (-1, "x = lex_integer ();");
1665 dump (0, "lex_get();");
1666 if (sbc->restriction)
1669 dump (1, "if (!(%s))", sbc->restriction);
1671 sprintf(buf,sbc->message,sbc->name);
1672 if ( sbc->translatable )
1673 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1675 dump (0, "msg (SE, \"%s\");",buf);
1676 dump (0, "goto lossage;");
1679 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1682 else if (sbc->type == SBC_PINT)
1684 dump (0, "lex_match ('(');");
1685 dump (1, "if (!lex_force_int ())");
1686 dump (0, "goto lossage;");
1687 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1688 dump (0, "lex_match (')');");
1690 else if (sbc->type == SBC_DBL_LIST)
1692 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1694 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1695 dump (0, "goto lossage;");
1698 dump (1, "while (token != '/' && token != '.')");
1700 dump (0, "lex_match(',');");
1701 dump (0, "if (!lex_force_num ())");
1703 dump (0, "goto lossage;");
1706 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1707 st_lower (sbc->name),st_lower (sbc->name)
1710 dump (0, "lex_get();");
1714 else if (sbc->type == SBC_CUSTOM)
1716 dump (1, "switch (%scustom_%s (p))",
1717 st_lower (prefix), st_lower (sbc->name));
1719 dump (1, "case 0:");
1720 dump (0, "goto lossage;");
1721 dump (-1, "case 1:");
1724 dump (-1, "case 2:");
1726 dump (0, "lex_error (NULL);");
1727 dump (0, "goto lossage;");
1728 dump (-1, "default:");
1730 dump (0, "assert (0);");
1736 /* Write out entire parser. */
1738 dump_parser (int persistent)
1744 dump (0, "static int");
1745 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1746 make_identifier (cmdname));
1749 dump_vars_init (persistent);
1751 dump (1, "for (;;)");
1755 if (def && (def->type == SBC_VARLIST))
1757 if (def->type == SBC_VARLIST)
1758 dump (1, "if (token == T_ID "
1759 "&& dict_lookup_var (default_dict, tokid) != NULL "
1760 "&& lex_look_ahead () != '=')");
1763 dump (0, "if ((token == T_ID "
1764 "&& dict_lookup_var (default_dict, tokid) "
1765 "&& lex_look_ahead () != '=')");
1766 dump (1, " || token == T_ALL)");
1769 dump (0, "p->sbc_%s++;", st_lower (def->name));
1770 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1772 st_lower (def->prefix), st_lower (def->name),
1773 st_lower (def->prefix), st_lower (def->name));
1774 dump (0, "goto lossage;");
1779 else if (def && def->type == SBC_CUSTOM)
1781 dump (1, "switch (%scustom_%s (p))",
1782 st_lower (prefix), st_lower (def->name));
1784 dump (1, "case 0:");
1785 dump (0, "goto lossage;");
1786 dump (-1, "case 1:");
1788 dump (0, "p->sbc_%s++;", st_lower (def->name));
1789 dump (0, "continue;");
1790 dump (-1, "case 2:");
1793 dump (-1, "default:");
1795 dump (0, "assert (0);");
1803 for (sbc = subcommands; sbc; sbc = sbc->next)
1805 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1809 dump (0, "lex_match ('=');");
1810 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1811 if (sbc->arity != ARITY_MANY)
1813 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1815 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1817 dump (0, "goto lossage;");
1821 dump_subcommand (sbc);
1828 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1829 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1832 dump (0, "lex_match ('=');");
1834 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1835 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1837 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1838 dump(0,"set_cmd_algorithm(ENHANCED);");
1845 dump (1, "if (!lex_match ('/'))");
1850 dump (1, "if (token != '.')");
1852 dump (0, "lex_error (_(\"expecting end of command\"));");
1853 dump (0, "goto lossage;");
1860 /* Check that mandatory subcommands have been specified */
1863 for (sbc = subcommands; sbc; sbc = sbc->next)
1866 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1868 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1870 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1872 dump (0, "goto lossage;");
1879 dump (-1, "return 1;");
1881 dump (-1, "lossage:");
1883 dump (0, "free_%s (p);", make_identifier (cmdname));
1884 dump (0, "return 0;");
1890 /* Write the output file header. */
1899 curtime = time (NULL);
1900 loctime = localtime (&curtime);
1901 timep = asctime (loctime);
1902 timep[strlen (timep) - 1] = 0;
1903 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1905 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1906 dump (0, " Do not modify!");
1910 /* Write out commands to free variable state. */
1912 dump_free (int persistent)
1922 for (sbc = subcommands; sbc; sbc = sbc->next)
1924 if (sbc->type == SBC_STRING)
1926 if (sbc->type == SBC_DBL_LIST)
1932 dump (0, "static void");
1933 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1934 make_identifier (cmdname), used ? "" : " UNUSED");
1940 for (sbc = subcommands; sbc; sbc = sbc->next)
1945 dump (0, "free (p->v_%s);", st_lower (sbc->name));
1948 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1952 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
1953 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1968 /* Returns the name of a directive found on the current input line, if
1969 any, or a null pointer if none found. */
1971 recognize_directive (void)
1973 static char directive[16];
1977 if (strncmp (sp, "/*", 2))
1979 sp = skip_ws (sp + 2);
1984 ep = strchr (sp, ')');
1990 memcpy (directive, sp, ep - sp);
1991 directive[ep - sp] = '\0';
1996 main (int argc, char *argv[])
1998 program_name = argv[0];
2000 fail ("Syntax: q2c input.q output.c");
2003 in = fopen (ifn, "r");
2005 fail ("%s: open: %s.", ifn, strerror (errno));
2008 out = fopen (ofn, "w");
2010 fail ("%s: open: %s.", ofn, strerror (errno));
2013 buf = xmalloc (MAX_LINE_LEN);
2014 tokstr = xmalloc (MAX_TOK_LEN);
2020 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2023 const char *directive = recognize_directive ();
2024 if (directive == NULL)
2026 dump (0, "%s", buf);
2030 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2031 if (!strcmp (directive, "specification"))
2033 /* Skip leading slash-star line. */
2039 /* Skip trailing star-slash line. */
2042 else if (!strcmp (directive, "headers"))
2046 dump (0, "#include <stdlib.h>");
2047 dump (0, "#include \"alloc.h\"");
2048 dump (0, "#include \"message.h\"");
2049 dump (0, "#include \"lexer.h\"");
2050 dump (0, "#include \"settings.h\"");
2051 dump (0, "#include \"str.h\"");
2052 dump (0, "#include \"subcommand-list.h\"");
2053 dump (0, "#include \"variable.h\"");
2056 dump (0, "#include \"gettext.h\"");
2057 dump (0, "#define _(msgid) gettext (msgid)");
2060 else if (!strcmp (directive, "declarations"))
2061 dump_declarations ();
2062 else if (!strcmp (directive, "functions"))
2067 else if (!strcmp (directive, "_functions"))
2073 error ("unknown directive `%s'", directive);
2075 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2080 return EXIT_SUCCESS;