1 /* q2c - parser generator for PSPP procedures.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 /* GNU C allows the programmer to declare that certain functions take
30 printf-like arguments, never return, etc. Conditionalize these
31 declarations on whether gcc is in use. */
33 #define ATTRIBUTE(X) __attribute__ (X)
38 /* Marks a function argument as possibly not used. */
39 #define UNUSED ATTRIBUTE ((unused))
41 /* Marks a function that will never return. */
42 #define NO_RETURN ATTRIBUTE ((noreturn))
44 /* Mark a function as taking a printf- or scanf-like format
45 string as its FMT'th argument and that the FIRST'th argument
46 is the first one to be checked against the format string. */
47 #define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (__printf__, FMT, FIRST)))
49 /* Max length of an input line. */
50 #define MAX_LINE_LEN 1024
52 /* Max token length. */
53 #define MAX_TOK_LEN 1024
56 static char *program_name;
58 /* Have the input and output files been opened yet? */
61 /* Input, output files. */
62 static FILE *in, *out;
64 /* Input, output file names. */
65 static char *ifn, *ofn;
67 /* Input, output file line number. */
68 static int ln, oln = 1;
70 /* Input line buffer, current position. */
71 static char *buf, *cp;
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. */
88 static char nullstr[] = "";
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", program_name, 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: ", program_name);
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 *sym);
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 /* DUMP_TOKENS */
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 true; otherwise, returns false. */
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 true; otherwise, returns false. */
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 /* Name of the command; i.e., DESCRIPTIVES. */
563 /* Short prefix for the command; i.e., `dsc_'. */
566 /* List of subcommands. */
567 subcommand *subcommands;
569 /* Default subcommand if any, or NULL. */
574 void parse_subcommands (void);
576 /* Parse an entire specification. */
580 /* Get the command name and prefix. */
581 if (token != T_STRING && token != T_ID)
582 error ("Command name expected.");
583 cmdname = xstrdup (tokstr);
587 prefix = xstrdup (tokstr);
592 /* Read all the subcommands. */
595 parse_subcommands ();
598 /* Parses a single setting into S, given subcommand information SBC
599 and specifier information SPEC. */
601 parse_setting (setting *s, specifier *spec)
605 if (match_token ('*'))
608 error ("Cannot have two settings with omittable keywords.");
613 if (match_token ('!'))
616 error ("Cannot have two default settings.");
622 s->specname = xstrdup (tokstr);
623 s->con = add_symbol (s->specname, 0, 0);
628 /* Parse setting value info if necessary. */
629 if (token != '/' && token != ';' && token != '.' && token != ',')
633 s->valtype = VT_PAREN;
637 s->valtype = VT_PLAIN;
639 s->optvalue = match_token ('*');
643 else if (match_id ("D"))
646 error ("`n' or `d' expected.");
651 s->valname = xstrdup (tokstr);
658 s->restriction = xstrdup (tokstr);
662 s->restriction = NULL;
664 if (s->valtype == VT_PAREN)
669 /* Parse a single specifier into SPEC, given subcommand information
672 parse_specifier (specifier *spec, subcommand *sbc)
677 spec->omit_kw = NULL;
678 spec->varname = NULL;
682 spec->varname = xstrdup (st_lower (tokstr));
686 /* Handle array elements. */
689 spec->index = sbc->narray;
690 if (sbc->type == SBC_ARRAY)
702 if ( sbc->type == SBC_ARRAY && token == T_ID )
704 spec->varname = xstrdup (st_lower (tokstr));
705 spec->index = sbc->narray;
711 /* Parse all the settings. */
713 setting **s = &spec->s;
717 *s = xmalloc (sizeof **s);
718 parse_setting (*s, spec);
719 if (token == ',' || token == ';' || token == '.')
728 /* Parse a list of specifiers for subcommand SBC. */
730 parse_specifiers (subcommand *sbc)
732 specifier **spec = &sbc->spec;
734 if (token == ';' || token == '.')
742 *spec = xmalloc (sizeof **spec);
743 parse_specifier (*spec, sbc);
744 if (token == ';' || token == '.')
747 spec = &(*spec)->next;
749 (*spec)->next = NULL;
752 /* Parse a subcommand into SBC. */
754 parse_subcommand (subcommand *sbc)
756 if (match_token ('*'))
759 error ("Multiple default subcommands.");
763 sbc->arity = ARITY_ONCE_ONLY;
764 if ( match_token('+'))
765 sbc->arity = ARITY_MANY;
766 else if (match_token('^'))
767 sbc->arity = ARITY_ONCE_EXACTLY ;
771 sbc->name = xstrdup (tokstr);
775 sbc->type = SBC_PLAIN;
777 sbc->translatable = 0;
779 if (match_token ('['))
782 sbc->prefix = xstrdup (st_lower (tokstr));
788 sbc->type = SBC_ARRAY;
789 parse_specifiers (sbc);
794 if (match_token ('('))
797 sbc->prefix = xstrdup (st_lower (tokstr));
807 if (match_id ("VAR"))
809 if (match_id ("VARLIST"))
811 if (match_token ('('))
814 sbc->message = xstrdup (tokstr);
819 else sbc->message = NULL;
821 sbc->type = SBC_VARLIST;
823 else if (match_id ("INTEGER"))
825 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
826 if ( token == T_STRING)
828 sbc->restriction = xstrdup (tokstr);
830 if ( match_id("N_") )
836 sbc->translatable = 1;
842 sbc->message = xstrdup (tokstr);
845 sbc->restriction = NULL;
847 else if (match_id ("PINT"))
848 sbc->type = SBC_PINT;
849 else if (match_id ("DOUBLE"))
851 if ( match_id ("LIST") )
852 sbc->type = SBC_DBL_LIST;
856 else if (match_id ("STRING"))
858 sbc->type = SBC_STRING;
859 if (token == T_STRING)
861 sbc->restriction = xstrdup (tokstr);
864 sbc->message = xstrdup (tokstr);
868 sbc->restriction = NULL;
870 else if (match_id ("CUSTOM"))
871 sbc->type = SBC_CUSTOM;
873 parse_specifiers (sbc);
877 /* Parse all the subcommands. */
879 parse_subcommands (void)
881 subcommand **sbc = &subcommands;
885 *sbc = xmalloc (sizeof **sbc);
888 parse_subcommand (*sbc);
900 #define BASE_INDENT 2 /* Starting indent. */
901 #define INC_INDENT 2 /* Indent increment. */
903 /* Increment the indent. */
904 #define indent() indent += INC_INDENT
905 #define outdent() indent -= INC_INDENT
907 /* Size of the indent from the left margin. */
910 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
912 /* Write line FORMAT to the output file, formatted as with printf,
913 indented `indent' characters from the left margin. If INDENTION is
914 greater than 0, indents BASE_INDENT * INDENTION characters after
915 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
916 * INDENTION characters _before_ writing the line. */
918 dump (int indention, const char *format, ...)
924 indent += BASE_INDENT * indention;
927 va_start (args, format);
928 for (i = 0; i < indent; i++)
930 vfprintf (out, format, args);
935 indent += BASE_INDENT * indention;
938 /* Write the structure members for specifier SPEC to the output file.
939 SBC is the including subcommand. */
941 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
944 dump (0, "long %s%s;", sbc->prefix, spec->varname);
949 for (s = spec->s; s; s = s->next)
951 if (s->value != VAL_NONE)
953 const char *typename;
955 assert (s->value == VAL_INT || s->value == VAL_DBL);
956 typename = s->value == VAL_INT ? "long" : "double";
958 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
964 /* Returns true if string T is a PSPP keyword, false otherwise. */
966 is_keyword (const char *t)
968 static const char *kw[] =
970 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
971 "NE", "ALL", "BY", "TO", "WITH", 0,
975 for (cp = kw; *cp; cp++)
976 if (!strcmp (t, *cp))
981 /* Transforms a string NAME into a valid C identifier: makes
982 everything lowercase and maps nonalphabetic characters to
983 underscores. Returns a pointer to a static buffer. */
985 make_identifier (const char *name)
987 char *p = get_buffer ();
990 for (cp = p; *name; name++)
991 if (isalpha ((unsigned char) *name))
992 *cp++ = tolower ((unsigned char) (*name));
1000 /* Writes the struct and enum declarations for the parser. */
1002 dump_declarations (void)
1006 /* Write out enums for all the identifiers in the symbol table. */
1012 /* Note the squirmings necessary to make sure that the last enum
1013 is not followed by a comma, as mandated by ANSI C89. */
1014 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1015 if (!sym->unique && !is_keyword (sym->name))
1019 dump (0, "/* Settings for subcommand specifiers. */");
1026 buf = xmalloc (1024);
1031 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1035 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1040 buf[strlen (buf) - 1] = 0;
1051 /* Write out some type definitions */
1053 dump (0, "#define MAXLISTS 10");
1057 /* For every array subcommand, write out the associated enumerated
1062 for (sbc = subcommands; sbc; sbc = sbc->next)
1063 if (sbc->type == SBC_ARRAY && sbc->narray)
1065 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1073 for (spec = sbc->spec; spec; spec = spec->next)
1074 dump (0, "%s%s%s = %d,",
1075 st_upper (prefix), st_upper (sbc->prefix),
1076 st_upper (spec->varname), spec->index);
1078 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1086 /* Write out structure declaration. */
1090 dump (0, "/* %s structure. */", cmdname);
1091 dump (1, "struct cmd_%s", make_identifier (cmdname));
1093 for (sbc = subcommands; sbc; sbc = sbc->next)
1097 if (sbc != subcommands)
1100 dump (0, "/* %s subcommand. */", sbc->name);
1101 dump (0, "int sbc_%s;", st_lower (sbc->name));
1110 for (spec = sbc->spec; spec; spec = spec->next)
1114 if (sbc->type == SBC_PLAIN)
1115 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1119 dump (0, "int a_%s[%s%scount];",
1120 st_lower (sbc->name),
1122 st_upper (sbc->prefix)
1129 dump_specifier_vars (spec, sbc);
1135 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1136 st_lower (sbc->name));
1137 dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix),
1138 st_lower (sbc->name));
1142 dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix),
1143 st_lower (sbc->name));
1147 dump (0, "char *s_%s;", st_lower (sbc->name));
1152 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1156 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1160 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1161 st_lower(sbc->name));
1165 dump (0, "subc_list_int il_%s[MAXLISTS];",
1166 st_lower(sbc->name));
1179 /* Write out prototypes for custom_*() functions as necessary. */
1184 for (sbc = subcommands; sbc; sbc = sbc->next)
1185 if (sbc->type == SBC_CUSTOM)
1190 dump (0, "/* Prototype for custom subcommands of %s. */",
1193 dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1194 st_lower (prefix), st_lower (sbc->name),
1195 make_identifier (cmdname));
1202 /* Prototypes for parsing and freeing functions. */
1204 dump (0, "/* Command parsing functions. */");
1205 dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1206 make_identifier (cmdname), make_identifier (cmdname));
1207 dump (0, "static void free_%s (struct cmd_%s *);",
1208 make_identifier (cmdname), make_identifier (cmdname));
1213 /* Writes out code to initialize all the variables that need
1214 initialization for particular specifier SPEC inside subcommand SBC. */
1216 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1224 st_upper (prefix), find_symbol (spec->def->con)->name);
1227 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1233 for (s = spec->s; s; s = s->next)
1235 if (s->value != VAL_NONE)
1239 assert (s->value == VAL_INT || s->value == VAL_DBL);
1240 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1242 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1248 /* Write code to initialize all variables. */
1250 dump_vars_init (int persistent)
1252 /* Loop through all the subcommands. */
1256 for (sbc = subcommands; sbc; sbc = sbc->next)
1260 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1271 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1272 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1273 st_lower (sbc->name)
1281 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1282 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1295 for (spec = sbc->spec; spec; spec = spec->next)
1296 if (spec->s == NULL)
1298 if (sbc->type == SBC_PLAIN)
1299 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1302 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1303 st_lower (sbc->name), st_lower (sbc->name));
1308 dump_specifier_init (spec, sbc);
1313 dump (0, "p->%sn_%s = 0;",
1314 st_lower (sbc->prefix), st_lower (sbc->name));
1315 dump (0, "p->%sv_%s = NULL;",
1316 st_lower (sbc->prefix), st_lower (sbc->name));
1320 dump (0, "p->%sv_%s = NULL;",
1321 st_lower (sbc->prefix), st_lower (sbc->name));
1325 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1332 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1333 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1345 /* Return a pointer to a static buffer containing an expression that
1346 will match token T. */
1348 make_match (const char *t)
1358 sprintf (s, "lex_match (lexer, T_%s)", t);
1359 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1360 strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") "
1361 "|| lex_match_id (lexer, \"TRUE\"))");
1362 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1363 strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") "
1364 "|| lex_match_id (lexer, \"FALSE\"))");
1365 else if (isdigit ((unsigned char) t[0]))
1366 sprintf (s, "lex_match_int (lexer, %s)", t);
1368 sprintf (s, "lex_match_id (lexer, \"%s\")", t);
1373 /* Write out the parsing code for specifier SPEC within subcommand
1376 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1380 if (spec->omit_kw && spec->omit_kw->next)
1381 error ("Omittable setting is not last setting in `%s' specifier.",
1383 if (spec->omit_kw && spec->omit_kw->parent->next)
1384 error ("Default specifier is not in last specifier in `%s' "
1385 "subcommand.", sbc->name);
1387 for (s = spec->s; s; s = s->next)
1389 int first = spec == sbc->spec && s == spec->s;
1391 /* Match the setting's keyword. */
1392 if (spec->omit_kw == s)
1399 dump (1, "%s;", make_match (s->specname));
1402 dump (1, "%sif (%s)", first ? "" : "else ",
1403 make_match (s->specname));
1406 /* Handle values. */
1407 if (s->value == VAL_NONE)
1408 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1409 st_upper (prefix), find_symbol (s->con)->name);
1412 if (spec->omit_kw != s)
1417 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1418 st_upper (prefix), find_symbol (s->con)->name);
1420 if ( sbc->type == SBC_ARRAY )
1421 dump (0, "p->a_%s[%s%s%s] = 1;",
1422 st_lower (sbc->name),
1423 st_upper (prefix), st_upper (sbc->prefix),
1424 st_upper (spec->varname));
1428 if (s->valtype == VT_PAREN)
1432 dump (1, "if (lex_match (lexer, '('))");
1437 dump (1, "if (!lex_match (lexer, '('))");
1439 dump (0, "msg (SE, _(\"`(' expected after %s "
1440 "specifier of %s subcommand.\"));",
1441 s->specname, sbc->name);
1442 dump (0, "goto lossage;");
1448 if (s->value == VAL_INT)
1450 dump (1, "if (!lex_is_integer (lexer))");
1452 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1453 "requires an integer argument.\"));",
1454 s->specname, sbc->name);
1455 dump (0, "goto lossage;");
1457 dump (-1, "p->%s%s = lex_integer (lexer);",
1458 sbc->prefix, st_lower (s->valname));
1462 dump (1, "if (!lex_is_number (lexer))");
1464 dump (0, "msg (SE, _(\"Number expected after %s "
1465 "specifier of %s subcommand.\"));",
1466 s->specname, sbc->name);
1467 dump (0, "goto lossage;");
1469 dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
1470 st_lower (s->valname));
1477 str = xmalloc (MAX_TOK_LEN);
1478 str2 = xmalloc (MAX_TOK_LEN);
1479 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1480 sprintf (str, s->restriction, str2, str2, str2, str2,
1481 str2, str2, str2, str2);
1482 dump (1, "if (!(%s))", str);
1488 dump (0, "msg (SE, _(\"Bad argument for %s "
1489 "specifier of %s subcommand.\"));",
1490 s->specname, sbc->name);
1491 dump (0, "goto lossage;");
1496 dump (0, "lex_get (lexer);");
1498 if (s->valtype == VT_PAREN)
1500 dump (1, "if (!lex_match (lexer, ')'))");
1502 dump (0, "msg (SE, _(\"`)' expected after argument for "
1503 "%s specifier of %s.\"));",
1504 s->specname, sbc->name);
1505 dump (0, "goto lossage;");
1515 if (s != spec->omit_kw)
1519 if (s == spec->omit_kw)
1528 /* Write out the code to parse subcommand SBC. */
1530 dump_subcommand (const subcommand *sbc)
1532 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1536 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1542 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1545 dump_specifier_parse (spec, sbc);
1549 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1550 make_match (st_upper (spec->varname)));
1551 if (sbc->type == SBC_PLAIN)
1552 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1555 dump (0, "p->a_%s[%s%s%s] = 1;",
1556 st_lower (sbc->name),
1557 st_upper (prefix), st_upper (sbc->prefix),
1558 st_upper (spec->varname));
1568 /* This code first finds the last specifier in sbc. Then it
1569 finds the last setting within that last specifier. Either
1570 or both might be NULL. */
1583 if (spec && (!spec->s || !spec->omit_kw))
1587 dump (0, "lex_error (lexer, NULL);");
1588 dump (0, "goto lossage;");
1594 dump (0, "lex_match (lexer, ',');");
1598 else if (sbc->type == SBC_VARLIST)
1600 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1602 st_lower (sbc->prefix), st_lower (sbc->name),
1603 st_lower (sbc->prefix), st_lower (sbc->name),
1604 sbc->message ? " |" : "",
1605 sbc->message ? sbc->message : "");
1606 dump (0, "goto lossage;");
1609 else if (sbc->type == SBC_VAR)
1611 dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));",
1612 st_lower (sbc->prefix), st_lower (sbc->name));
1613 dump (1, "if (!p->%sv_%s)",
1614 st_lower (sbc->prefix), st_lower (sbc->name));
1615 dump (0, "goto lossage;");
1618 else if (sbc->type == SBC_STRING)
1620 if (sbc->restriction)
1625 dump (1, "if (!lex_force_string (lexer))");
1626 dump (0, "return false;");
1628 if (sbc->restriction)
1630 dump (0, "x = ds_length (lex_tokstr (lexer));");
1631 dump (1, "if (!(%s))", sbc->restriction);
1633 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1634 sbc->name, sbc->message);
1635 dump (0, "goto lossage;");
1639 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1640 dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));",
1641 st_lower (sbc->name));
1642 dump (0, "lex_get (lexer);");
1643 if (sbc->restriction)
1646 else if (sbc->type == SBC_DBL)
1648 dump (1, "if (!lex_force_num (lexer))");
1649 dump (0, "goto lossage;");
1650 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);",
1651 st_lower (sbc->name), st_lower (sbc->name) );
1652 dump (0, "lex_get(lexer);");
1654 else if (sbc->type == SBC_INT)
1658 dump (1, "if (!lex_force_int (lexer))");
1659 dump (0, "goto lossage;");
1660 dump (-1, "x = lex_integer (lexer);");
1661 dump (0, "lex_get(lexer);");
1662 if (sbc->restriction)
1665 dump (1, "if (!(%s))", sbc->restriction);
1667 sprintf(buf,sbc->message,sbc->name);
1668 if ( sbc->translatable )
1669 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1671 dump (0, "msg (SE, \"%s\");",buf);
1672 dump (0, "goto lossage;");
1675 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1678 else if (sbc->type == SBC_PINT)
1680 dump (0, "lex_match (lexer, '(');");
1681 dump (1, "if (!lex_force_int (lexer))");
1682 dump (0, "goto lossage;");
1683 dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
1684 dump (0, "lex_match (lexer, ')');");
1686 else if (sbc->type == SBC_DBL_LIST)
1688 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1690 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1691 dump (0, "goto lossage;");
1694 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1696 dump (0, "lex_match (lexer, ',');");
1697 dump (0, "if (!lex_force_num (lexer))");
1699 dump (0, "goto lossage;");
1702 dump (0, "subc_list_double_push (&p->dl_%s[p->sbc_%s-1], lex_number (lexer));",
1703 st_lower (sbc->name), st_lower (sbc->name)
1706 dump (0, "lex_get (lexer);");
1710 else if (sbc->type == SBC_CUSTOM)
1712 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1713 st_lower (prefix), st_lower (sbc->name));
1715 dump (1, "case 0:");
1716 dump (0, "goto lossage;");
1717 dump (-1, "case 1:");
1720 dump (-1, "case 2:");
1722 dump (0, "lex_error (lexer, NULL);");
1723 dump (0, "goto lossage;");
1724 dump (-1, "default:");
1726 dump (0, "NOT_REACHED ();");
1732 /* Write out entire parser. */
1734 dump_parser (int persistent)
1740 dump (0, "static int");
1741 dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)",
1742 make_identifier (cmdname),
1743 (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED",
1744 make_identifier (cmdname));
1747 dump_vars_init (persistent);
1749 dump (1, "for (;;)");
1753 if (def && (def->type == SBC_VARLIST))
1755 if (def->type == SBC_VARLIST)
1756 dump (1, "if (lex_token (lexer) == T_ID "
1757 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL "
1758 "&& lex_look_ahead (lexer) != '=')");
1761 dump (0, "if ((lex_token (lexer) == T_ID "
1762 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) "
1763 "&& lex_look_ahead () != '=')");
1764 dump (1, " || token == T_ALL)");
1767 dump (0, "p->sbc_%s++;", st_lower (def->name));
1768 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1770 st_lower (def->prefix), st_lower (def->name),
1771 st_lower (def->prefix), st_lower (def->name));
1772 dump (0, "goto lossage;");
1777 else if (def && def->type == SBC_CUSTOM)
1779 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1780 st_lower (prefix), st_lower (def->name));
1782 dump (1, "case 0:");
1783 dump (0, "goto lossage;");
1784 dump (-1, "case 1:");
1786 dump (0, "p->sbc_%s++;", st_lower (def->name));
1787 dump (0, "continue;");
1788 dump (-1, "case 2:");
1791 dump (-1, "default:");
1793 dump (0, "NOT_REACHED ();");
1801 for (sbc = subcommands; sbc; sbc = sbc->next)
1803 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1807 dump (0, "lex_match (lexer, '=');");
1808 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1809 if (sbc->arity != ARITY_MANY)
1811 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1813 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1815 dump (0, "goto lossage;");
1819 dump_subcommand (sbc);
1826 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1827 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
1830 dump (0, "lex_match (lexer, '=');");
1832 dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
1833 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1835 dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))");
1836 dump(0,"set_cmd_algorithm(ENHANCED);");
1843 dump (1, "if (!lex_match (lexer, '/'))");
1848 dump (1, "if (lex_token (lexer) != '.')");
1850 dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
1851 dump (0, "goto lossage;");
1858 /* Check that mandatory subcommands have been specified */
1861 for (sbc = subcommands; sbc; sbc = sbc->next)
1864 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1866 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1868 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1870 dump (0, "goto lossage;");
1877 dump (-1, "return true;");
1879 dump (-1, "lossage:");
1881 dump (0, "free_%s (p);", make_identifier (cmdname));
1882 dump (0, "return false;");
1888 /* Write the output file header. */
1893 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1895 dump (0, " Generated by q2c from %s.", ifn);
1896 dump (0, " Do not modify!");
1900 /* Write out commands to free variable state. */
1902 dump_free (int persistent)
1912 for (sbc = subcommands; sbc; sbc = sbc->next)
1914 if (sbc->type == SBC_STRING)
1916 if (sbc->type == SBC_DBL_LIST)
1922 dump (0, "static void");
1923 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1924 make_identifier (cmdname), used ? "" : " UNUSED");
1930 for (sbc = subcommands; sbc; sbc = sbc->next)
1935 dump (0, "free (p->v_%s);", st_lower (sbc->name));
1938 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1943 dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
1944 dump (1, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1960 /* Returns the name of a directive found on the current input line, if
1961 any, or a null pointer if none found. */
1963 recognize_directive (void)
1965 static char directive[16];
1969 if (strncmp (sp, "/*", 2))
1971 sp = skip_ws (sp + 2);
1976 ep = strchr (sp, ')');
1982 memcpy (directive, sp, ep - sp);
1983 directive[ep - sp] = '\0';
1988 main (int argc, char *argv[])
1990 program_name = argv[0];
1992 fail ("Syntax: q2c input.q output.c");
1995 in = fopen (ifn, "r");
1997 fail ("%s: open: %s.", ifn, strerror (errno));
2000 out = fopen (ofn, "w");
2002 fail ("%s: open: %s.", ofn, strerror (errno));
2005 buf = xmalloc (MAX_LINE_LEN);
2006 tokstr = xmalloc (MAX_TOK_LEN);
2012 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2015 const char *directive = recognize_directive ();
2016 if (directive == NULL)
2018 dump (0, "%s", buf);
2022 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2023 if (!strcmp (directive, "specification"))
2025 /* Skip leading slash-star line. */
2031 /* Skip trailing star-slash line. */
2034 else if (!strcmp (directive, "headers"))
2038 dump (0, "#include <stdlib.h>");
2039 dump (0, "#include <libpspp/alloc.h>");
2040 dump (0, "#include <libpspp/assertion.h>");
2041 dump (0, "#include <libpspp/message.h>");
2042 dump (0, "#include <language/lexer/lexer.h>");
2043 dump (0, "#include <language/lexer/variable-parser.h>");
2044 dump (0, "#include <data/settings.h>");
2045 dump (0, "#include <libpspp/str.h>");
2046 dump (0, "#include <language/lexer/subcommand-list.h>");
2047 dump (0, "#include <data/variable.h>");
2050 dump (0, "#include \"gettext.h\"");
2051 dump (0, "#define _(msgid) gettext (msgid)");
2054 else if (!strcmp (directive, "declarations"))
2055 dump_declarations ();
2056 else if (!strcmp (directive, "functions"))
2061 else if (!strcmp (directive, "_functions"))
2067 error ("unknown directive `%s'", directive);
2069 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2072 return EXIT_SUCCESS;