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. */
476 VAL_STRING /* String value. */
479 /* For those specifiers with values, the syntax of those values. */
482 VT_PLAIN, /* Unadorned value. */
483 VT_PAREN /* Value must be enclosed in parentheses. */
486 /* Forward definition. */
487 typedef struct specifier specifier;
489 /* A single setting. */
490 typedef struct setting setting;
493 specifier *parent; /* Owning specifier. */
494 setting *next; /* Next in the chain. */
495 char *specname; /* Name of the setting. */
496 int con; /* Sequence number. */
499 int valtype; /* One of VT_*. */
500 int value; /* One of VAL_*. */
501 int optvalue; /* 1=value is optional, 0=value is required. */
502 char *valname; /* Variable name for the value. */
503 char *restriction; /* !=NULL: expression specifying valid values. */
506 /* A single specifier. */
509 specifier *next; /* Next in the chain. */
510 char *varname; /* Variable name. */
511 setting *s; /* Associated settings. */
513 setting *def; /* Default setting. */
514 setting *omit_kw; /* Setting for which the keyword can be omitted. */
516 int index; /* Next array index. */
519 /* Subcommand types. */
522 SBC_PLAIN, /* The usual case. */
523 SBC_VARLIST, /* Variable list. */
524 SBC_INT, /* Integer value. */
525 SBC_PINT, /* Integer inside parentheses. */
526 SBC_DBL, /* Floating point value. */
527 SBC_INT_LIST, /* List of integers (?). */
528 SBC_DBL_LIST, /* List of floating points (?). */
529 SBC_CUSTOM, /* Custom. */
530 SBC_ARRAY, /* Array of boolean values. */
531 SBC_STRING, /* String value. */
532 SBC_VAR /* Single variable name. */
538 ARITY_ONCE_EXACTLY, /* must occur exactly once */
539 ARITY_ONCE_ONLY, /* zero or once */
540 ARITY_MANY /* 0, 1, ... , inf */
543 /* A single subcommand. */
544 typedef struct subcommand subcommand;
547 subcommand *next; /* Next in the chain. */
548 char *name; /* Subcommand name. */
549 subcommand_type type; /* One of SBC_*. */
550 subcommand_arity arity; /* How many times should the subcommand occur*/
551 int narray; /* Index of next array element. */
552 const char *prefix; /* Prefix for variable and constant names. */
553 specifier *spec; /* Array of specifiers. */
555 /* SBC_STRING and SBC_INT only. */
556 char *restriction; /* Expression restricting string length. */
557 char *message; /* Error message. */
558 int translatable; /* Error message is translatable */
561 /* Name of the command; i.e., DESCRIPTIVES. */
564 /* Short prefix for the command; i.e., `dsc_'. */
567 /* List of subcommands. */
568 subcommand *subcommands;
570 /* Default subcommand if any, or NULL. */
575 void parse_subcommands (void);
577 /* Parse an entire specification. */
581 /* Get the command name and prefix. */
582 if (token != T_STRING && token != T_ID)
583 error ("Command name expected.");
584 cmdname = xstrdup (tokstr);
588 prefix = xstrdup (tokstr);
593 /* Read all the subcommands. */
596 parse_subcommands ();
599 /* Parses a single setting into S, given subcommand information SBC
600 and specifier information SPEC. */
602 parse_setting (setting *s, specifier *spec)
606 if (match_token ('*'))
609 error ("Cannot have two settings with omittable keywords.");
614 if (match_token ('!'))
617 error ("Cannot have two default settings.");
623 s->specname = xstrdup (tokstr);
624 s->con = add_symbol (s->specname, 0, 0);
629 /* Parse setting value info if necessary. */
630 if (token != '/' && token != ';' && token != '.' && token != ',')
634 s->valtype = VT_PAREN;
638 s->valtype = VT_PLAIN;
640 s->optvalue = match_token ('*');
644 else if (match_id ("D"))
646 else if (match_id ("S"))
647 s->value = VAL_STRING;
649 error ("`n', `d', or `s' 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 if (match_token ('*'))
762 error ("Multiple default subcommands.");
766 sbc->arity = ARITY_ONCE_ONLY;
767 if ( match_token('+'))
768 sbc->arity = ARITY_MANY;
769 else if (match_token('^'))
770 sbc->arity = ARITY_ONCE_EXACTLY ;
774 sbc->name = xstrdup (tokstr);
778 sbc->type = SBC_PLAIN;
780 sbc->translatable = 0;
782 if (match_token ('['))
785 sbc->prefix = xstrdup (st_lower (tokstr));
791 sbc->type = SBC_ARRAY;
792 parse_specifiers (sbc);
797 if (match_token ('('))
800 sbc->prefix = xstrdup (st_lower (tokstr));
810 if (match_id ("VAR"))
812 if (match_id ("VARLIST"))
814 if (match_token ('('))
817 sbc->message = xstrdup (tokstr);
822 else sbc->message = NULL;
824 sbc->type = SBC_VARLIST;
826 else if (match_id ("INTEGER"))
828 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
829 if ( token == T_STRING)
831 sbc->restriction = xstrdup (tokstr);
833 if ( match_id("N_") )
839 sbc->translatable = 1;
845 sbc->message = xstrdup (tokstr);
848 sbc->restriction = NULL;
850 else if (match_id ("PINT"))
851 sbc->type = SBC_PINT;
852 else if (match_id ("DOUBLE"))
854 if ( match_id ("LIST") )
855 sbc->type = SBC_DBL_LIST;
859 else if (match_id ("STRING"))
861 sbc->type = SBC_STRING;
862 if (token == T_STRING)
864 sbc->restriction = xstrdup (tokstr);
867 sbc->message = xstrdup (tokstr);
871 sbc->restriction = NULL;
873 else if (match_id ("CUSTOM"))
874 sbc->type = SBC_CUSTOM;
876 parse_specifiers (sbc);
880 /* Parse all the subcommands. */
882 parse_subcommands (void)
884 subcommand **sbc = &subcommands;
888 *sbc = xmalloc (sizeof **sbc);
891 parse_subcommand (*sbc);
903 #define BASE_INDENT 2 /* Starting indent. */
904 #define INC_INDENT 2 /* Indent increment. */
906 /* Increment the indent. */
907 #define indent() indent += INC_INDENT
908 #define outdent() indent -= INC_INDENT
910 /* Size of the indent from the left margin. */
913 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
915 /* Write line FORMAT to the output file, formatted as with printf,
916 indented `indent' characters from the left margin. If INDENTION is
917 greater than 0, indents BASE_INDENT * INDENTION characters after
918 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
919 * INDENTION characters _before_ writing the line. */
921 dump (int indention, const char *format, ...)
927 indent += BASE_INDENT * indention;
930 va_start (args, format);
931 for (i = 0; i < indent; i++)
933 vfprintf (out, format, args);
938 indent += BASE_INDENT * indention;
941 /* Write the structure members for specifier SPEC to the output file.
942 SBC is the including subcommand. */
944 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
947 dump (0, "long %s%s;", sbc->prefix, spec->varname);
952 for (s = spec->s; s; s = s->next)
954 if (s->value != VAL_NONE)
956 const char *typename;
958 assert (s->value == VAL_INT || s->value == VAL_DBL
959 || s->value == VAL_STRING);
960 typename = (s->value == VAL_INT ? "long"
961 : s->value == VAL_DBL ? "double"
964 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
970 /* Returns true if string T is a PSPP keyword, false otherwise. */
972 is_keyword (const char *t)
974 static const char *kw[] =
976 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
977 "NE", "ALL", "BY", "TO", "WITH", 0,
981 for (cp = kw; *cp; cp++)
982 if (!strcmp (t, *cp))
987 /* Transforms a string NAME into a valid C identifier: makes
988 everything lowercase and maps nonalphabetic characters to
989 underscores. Returns a pointer to a static buffer. */
991 make_identifier (const char *name)
993 char *p = get_buffer ();
996 for (cp = p; *name; name++)
997 if (isalpha ((unsigned char) *name))
998 *cp++ = tolower ((unsigned char) (*name));
1006 /* Writes the struct and enum declarations for the parser. */
1008 dump_declarations (void)
1012 dump (0, "struct dataset;");
1014 /* Write out enums for all the identifiers in the symbol table. */
1020 /* Note the squirmings necessary to make sure that the last enum
1021 is not followed by a comma, as mandated by ANSI C89. */
1022 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1023 if (!sym->unique && !is_keyword (sym->name))
1027 dump (0, "/* Settings for subcommand specifiers. */");
1034 buf = xmalloc (1024);
1039 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1043 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1048 buf[strlen (buf) - 1] = 0;
1059 /* Write out some type definitions */
1061 dump (0, "#define MAXLISTS 10");
1065 /* For every array subcommand, write out the associated enumerated
1070 for (sbc = subcommands; sbc; sbc = sbc->next)
1071 if (sbc->type == SBC_ARRAY && sbc->narray)
1073 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1081 for (spec = sbc->spec; spec; spec = spec->next)
1082 dump (0, "%s%s%s = %d,",
1083 st_upper (prefix), st_upper (sbc->prefix),
1084 st_upper (spec->varname), spec->index);
1086 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1094 /* Write out structure declaration. */
1098 dump (0, "/* %s structure. */", cmdname);
1099 dump (1, "struct cmd_%s", make_identifier (cmdname));
1101 for (sbc = subcommands; sbc; sbc = sbc->next)
1105 if (sbc != subcommands)
1108 dump (0, "/* %s subcommand. */", sbc->name);
1109 dump (0, "int sbc_%s;", st_lower (sbc->name));
1118 for (spec = sbc->spec; spec; spec = spec->next)
1122 if (sbc->type == SBC_PLAIN)
1123 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1127 dump (0, "int a_%s[%s%scount];",
1128 st_lower (sbc->name),
1130 st_upper (sbc->prefix)
1137 dump_specifier_vars (spec, sbc);
1143 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1144 st_lower (sbc->name));
1145 dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix),
1146 st_lower (sbc->name));
1150 dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix),
1151 st_lower (sbc->name));
1155 dump (0, "char *s_%s;", st_lower (sbc->name));
1160 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1164 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1168 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1169 st_lower(sbc->name));
1173 dump (0, "subc_list_int il_%s[MAXLISTS];",
1174 st_lower(sbc->name));
1187 /* Write out prototypes for custom_*() functions as necessary. */
1192 for (sbc = subcommands; sbc; sbc = sbc->next)
1193 if (sbc->type == SBC_CUSTOM)
1198 dump (0, "/* Prototype for custom subcommands of %s. */",
1201 dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1202 st_lower (prefix), st_lower (sbc->name),
1203 make_identifier (cmdname));
1210 /* Prototypes for parsing and freeing functions. */
1212 dump (0, "/* Command parsing functions. */");
1213 dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1214 make_identifier (cmdname), make_identifier (cmdname));
1215 dump (0, "static void free_%s (struct cmd_%s *);",
1216 make_identifier (cmdname), make_identifier (cmdname));
1221 /* Writes out code to initialize all the variables that need
1222 initialization for particular specifier SPEC inside subcommand SBC. */
1224 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1232 st_upper (prefix), find_symbol (spec->def->con)->name);
1235 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1241 for (s = spec->s; s; s = s->next)
1243 if (s->value != VAL_NONE)
1247 assert (s->value == VAL_INT || s->value == VAL_DBL
1248 || s->value == VAL_STRING);
1249 init = (s->value == VAL_INT ? "NOT_LONG"
1250 : s->value == VAL_DBL ? "SYSMIS"
1253 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1259 /* Write code to initialize all variables. */
1261 dump_vars_init (int persistent)
1263 /* Loop through all the subcommands. */
1267 for (sbc = subcommands; sbc; sbc = sbc->next)
1271 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1280 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1281 dump (0, "subc_list_%s_create(&p->%cl_%s[i]) ;",
1282 sbc->type == SBC_INT_LIST ? "int" : "double",
1283 sbc->type == SBC_INT_LIST ? 'i' : 'd',
1284 st_lower (sbc->name)
1292 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1293 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1306 for (spec = sbc->spec; spec; spec = spec->next)
1307 if (spec->s == NULL)
1309 if (sbc->type == SBC_PLAIN)
1310 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1313 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1314 st_lower (sbc->name), st_lower (sbc->name));
1319 dump_specifier_init (spec, sbc);
1324 dump (0, "p->%sn_%s = 0;",
1325 st_lower (sbc->prefix), st_lower (sbc->name));
1326 dump (0, "p->%sv_%s = NULL;",
1327 st_lower (sbc->prefix), st_lower (sbc->name));
1331 dump (0, "p->%sv_%s = NULL;",
1332 st_lower (sbc->prefix), st_lower (sbc->name));
1336 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1343 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1344 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1356 /* Return a pointer to a static buffer containing an expression that
1357 will match token T. */
1359 make_match (const char *t)
1369 sprintf (s, "lex_match (lexer, T_%s)", t);
1370 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1371 strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") "
1372 "|| lex_match_id (lexer, \"TRUE\"))");
1373 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1374 strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") "
1375 "|| lex_match_id (lexer, \"FALSE\"))");
1376 else if (isdigit ((unsigned char) t[0]))
1377 sprintf (s, "lex_match_int (lexer, %s)", t);
1379 sprintf (s, "lex_match_id (lexer, \"%s\")", t);
1384 /* Write out the parsing code for specifier SPEC within subcommand
1387 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1391 if (spec->omit_kw && spec->omit_kw->next)
1392 error ("Omittable setting is not last setting in `%s' specifier.",
1394 if (spec->omit_kw && spec->omit_kw->parent->next)
1395 error ("Default specifier is not in last specifier in `%s' "
1396 "subcommand.", sbc->name);
1398 for (s = spec->s; s; s = s->next)
1400 int first = spec == sbc->spec && s == spec->s;
1402 /* Match the setting's keyword. */
1403 if (spec->omit_kw == s)
1410 dump (1, "%s;", make_match (s->specname));
1413 dump (1, "%sif (%s)", first ? "" : "else ",
1414 make_match (s->specname));
1417 /* Handle values. */
1418 if (s->value == VAL_NONE)
1419 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1420 st_upper (prefix), find_symbol (s->con)->name);
1423 if (spec->omit_kw != s)
1428 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1429 st_upper (prefix), find_symbol (s->con)->name);
1431 if ( sbc->type == SBC_ARRAY )
1432 dump (0, "p->a_%s[%s%s%s] = 1;",
1433 st_lower (sbc->name),
1434 st_upper (prefix), st_upper (sbc->prefix),
1435 st_upper (spec->varname));
1439 if (s->valtype == VT_PAREN)
1443 dump (1, "if (lex_match (lexer, '('))");
1448 dump (1, "if (!lex_match (lexer, '('))");
1450 dump (0, "msg (SE, _(\"`(' expected after %s "
1451 "specifier of %s subcommand.\"));",
1452 s->specname, sbc->name);
1453 dump (0, "goto lossage;");
1459 if (s->value == VAL_INT)
1461 dump (1, "if (!lex_is_integer (lexer))");
1463 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1464 "requires an integer argument.\"));",
1465 s->specname, sbc->name);
1466 dump (0, "goto lossage;");
1468 dump (-1, "p->%s%s = lex_integer (lexer);",
1469 sbc->prefix, st_lower (s->valname));
1471 else if (s->value == VAL_DBL)
1473 dump (1, "if (!lex_is_number (lexer))");
1475 dump (0, "msg (SE, _(\"Number expected after %s "
1476 "specifier of %s subcommand.\"));",
1477 s->specname, sbc->name);
1478 dump (0, "goto lossage;");
1480 dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
1481 st_lower (s->valname));
1483 else if (s->value == VAL_STRING)
1485 dump (1, "if (lex_token (lexer) != T_ID "
1486 "&& lex_token (lexer) != T_STRING)");
1488 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1489 "requires a string argument.\"));",
1490 s->specname, sbc->name);
1491 dump (0, "goto lossage;");
1493 dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
1494 dump (0, "p->%s%s = xstrdup (ds_cstr (lex_tokstr (lexer)));",
1495 sbc->prefix, st_lower (s->valname));
1504 str = xmalloc (MAX_TOK_LEN);
1505 str2 = xmalloc (MAX_TOK_LEN);
1506 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1507 sprintf (str, s->restriction, str2, str2, str2, str2,
1508 str2, str2, str2, str2);
1509 dump (1, "if (!(%s))", str);
1515 dump (0, "msg (SE, _(\"Bad argument for %s "
1516 "specifier of %s subcommand.\"));",
1517 s->specname, sbc->name);
1518 dump (0, "goto lossage;");
1523 dump (0, "lex_get (lexer);");
1525 if (s->valtype == VT_PAREN)
1527 dump (1, "if (!lex_match (lexer, ')'))");
1529 dump (0, "msg (SE, _(\"`)' expected after argument for "
1530 "%s specifier of %s.\"));",
1531 s->specname, sbc->name);
1532 dump (0, "goto lossage;");
1542 if (s != spec->omit_kw)
1546 if (s == spec->omit_kw)
1555 /* Write out the code to parse subcommand SBC. */
1557 dump_subcommand (const subcommand *sbc)
1559 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1563 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1569 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1572 dump_specifier_parse (spec, sbc);
1576 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1577 make_match (st_upper (spec->varname)));
1578 if (sbc->type == SBC_PLAIN)
1579 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1582 dump (0, "p->a_%s[%s%s%s] = 1;",
1583 st_lower (sbc->name),
1584 st_upper (prefix), st_upper (sbc->prefix),
1585 st_upper (spec->varname));
1595 /* This code first finds the last specifier in sbc. Then it
1596 finds the last setting within that last specifier. Either
1597 or both might be NULL. */
1610 if (spec && (!spec->s || !spec->omit_kw))
1614 dump (0, "lex_error (lexer, NULL);");
1615 dump (0, "goto lossage;");
1621 dump (0, "lex_match (lexer, ',');");
1625 else if (sbc->type == SBC_VARLIST)
1627 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1629 st_lower (sbc->prefix), st_lower (sbc->name),
1630 st_lower (sbc->prefix), st_lower (sbc->name),
1631 sbc->message ? " |" : "",
1632 sbc->message ? sbc->message : "");
1633 dump (0, "goto lossage;");
1636 else if (sbc->type == SBC_VAR)
1638 dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));",
1639 st_lower (sbc->prefix), st_lower (sbc->name));
1640 dump (1, "if (!p->%sv_%s)",
1641 st_lower (sbc->prefix), st_lower (sbc->name));
1642 dump (0, "goto lossage;");
1645 else if (sbc->type == SBC_STRING)
1647 if (sbc->restriction)
1652 dump (1, "if (!lex_force_string (lexer))");
1653 dump (0, "return false;");
1655 if (sbc->restriction)
1657 dump (0, "x = ds_length (lex_tokstr (lexer));");
1658 dump (1, "if (!(%s))", sbc->restriction);
1660 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1661 sbc->name, sbc->message);
1662 dump (0, "goto lossage;");
1666 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1667 dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));",
1668 st_lower (sbc->name));
1669 dump (0, "lex_get (lexer);");
1670 if (sbc->restriction)
1673 else if (sbc->type == SBC_DBL)
1675 dump (1, "if (!lex_force_num (lexer))");
1676 dump (0, "goto lossage;");
1677 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);",
1678 st_lower (sbc->name), st_lower (sbc->name) );
1679 dump (0, "lex_get(lexer);");
1681 else if (sbc->type == SBC_INT)
1685 dump (1, "if (!lex_force_int (lexer))");
1686 dump (0, "goto lossage;");
1687 dump (-1, "x = lex_integer (lexer);");
1688 dump (0, "lex_get(lexer);");
1689 if (sbc->restriction)
1692 dump (1, "if (!(%s))", sbc->restriction);
1694 sprintf(buf,sbc->message,sbc->name);
1695 if ( sbc->translatable )
1696 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1698 dump (0, "msg (SE, \"%s\");",buf);
1699 dump (0, "goto lossage;");
1702 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1705 else if (sbc->type == SBC_PINT)
1707 dump (0, "lex_match (lexer, '(');");
1708 dump (1, "if (!lex_force_int (lexer))");
1709 dump (0, "goto lossage;");
1710 dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
1711 dump (0, "lex_match (lexer, ')');");
1713 else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST)
1715 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1717 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1718 dump (0, "goto lossage;");
1721 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1723 dump (0, "lex_match (lexer, ',');");
1724 dump (0, "if (!lex_force_num (lexer))");
1726 dump (0, "goto lossage;");
1729 dump (0, "subc_list_%s_push (&p->%cl_%s[p->sbc_%s-1], lex_number (lexer));",
1730 sbc->type == SBC_INT_LIST ? "int" : "double",
1731 sbc->type == SBC_INT_LIST ? 'i' : 'd',
1732 st_lower (sbc->name), st_lower (sbc->name));
1734 dump (0, "lex_get (lexer);");
1738 else if (sbc->type == SBC_CUSTOM)
1740 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1741 st_lower (prefix), st_lower (sbc->name));
1743 dump (1, "case 0:");
1744 dump (0, "goto lossage;");
1745 dump (-1, "case 1:");
1748 dump (-1, "case 2:");
1750 dump (0, "lex_error (lexer, NULL);");
1751 dump (0, "goto lossage;");
1752 dump (-1, "default:");
1754 dump (0, "NOT_REACHED ();");
1760 /* Write out entire parser. */
1762 dump_parser (int persistent)
1768 dump (0, "static int");
1769 dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)",
1770 make_identifier (cmdname),
1771 (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED",
1772 make_identifier (cmdname));
1775 dump_vars_init (persistent);
1777 dump (1, "for (;;)");
1781 if (def && (def->type == SBC_VARLIST))
1783 if (def->type == SBC_VARLIST)
1784 dump (1, "if (lex_token (lexer) == T_ID "
1785 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL "
1786 "&& lex_look_ahead (lexer) != '=')");
1789 dump (0, "if ((lex_token (lexer) == T_ID "
1790 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) "
1791 "&& lex_look_ahead () != '=')");
1792 dump (1, " || token == T_ALL)");
1795 dump (0, "p->sbc_%s++;", st_lower (def->name));
1796 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1798 st_lower (def->prefix), st_lower (def->name),
1799 st_lower (def->prefix), st_lower (def->name));
1800 dump (0, "goto lossage;");
1805 else if (def && def->type == SBC_CUSTOM)
1807 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1808 st_lower (prefix), st_lower (def->name));
1810 dump (1, "case 0:");
1811 dump (0, "goto lossage;");
1812 dump (-1, "case 1:");
1814 dump (0, "p->sbc_%s++;", st_lower (def->name));
1815 dump (0, "continue;");
1816 dump (-1, "case 2:");
1819 dump (-1, "default:");
1821 dump (0, "NOT_REACHED ();");
1829 for (sbc = subcommands; sbc; sbc = sbc->next)
1831 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1835 dump (0, "lex_match (lexer, '=');");
1836 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1837 if (sbc->arity != ARITY_MANY)
1839 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1841 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1843 dump (0, "goto lossage;");
1847 dump_subcommand (sbc);
1854 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1855 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
1858 dump (0, "lex_match (lexer, '=');");
1860 dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
1861 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1863 dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))");
1864 dump(0,"set_cmd_algorithm(ENHANCED);");
1871 dump (1, "if (!lex_match (lexer, '/'))");
1876 dump (1, "if (lex_token (lexer) != '.')");
1878 dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
1879 dump (0, "goto lossage;");
1886 /* Check that mandatory subcommands have been specified */
1889 for (sbc = subcommands; sbc; sbc = sbc->next)
1892 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1894 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1896 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1898 dump (0, "goto lossage;");
1905 dump (-1, "return true;");
1907 dump (-1, "lossage:");
1909 dump (0, "free_%s (p);", make_identifier (cmdname));
1910 dump (0, "return false;");
1916 /* Write the output file header. */
1921 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1923 dump (0, " Generated by q2c from %s.", ifn);
1924 dump (0, " Do not modify!");
1928 /* Write out commands to free variable state. */
1930 dump_free (int persistent)
1940 for (sbc = subcommands; sbc; sbc = sbc->next)
1941 used = (sbc->type == SBC_STRING
1942 || sbc->type == SBC_DBL_LIST
1943 || sbc->type == SBC_INT_LIST);
1946 dump (0, "static void");
1947 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1948 make_identifier (cmdname), used ? "" : " UNUSED");
1954 for (sbc = subcommands; sbc; sbc = sbc->next)
1959 dump (0, "free (p->v_%s);", st_lower (sbc->name));
1962 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1968 dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
1969 dump (1, "subc_list_%s_destroy(&p->%cl_%s[i]);",
1970 sbc->type == SBC_INT_LIST ? "int" : "double",
1971 sbc->type == SBC_INT_LIST ? 'i' : 'd',
1972 st_lower (sbc->name));
1981 for (spec = sbc->spec; spec; spec = spec->next)
1982 for (s = spec->s; s; s = s->next)
1983 if (s->value == VAL_STRING)
1984 dump (0, "free (p->%s%s);",
1985 sbc->prefix, st_lower (s->valname));
1999 /* Returns the name of a directive found on the current input line, if
2000 any, or a null pointer if none found. */
2002 recognize_directive (void)
2004 static char directive[16];
2008 if (strncmp (sp, "/*", 2))
2010 sp = skip_ws (sp + 2);
2015 ep = strchr (sp, ')');
2021 memcpy (directive, sp, ep - sp);
2022 directive[ep - sp] = '\0';
2027 main (int argc, char *argv[])
2029 program_name = argv[0];
2031 fail ("Syntax: q2c input.q output.c");
2034 in = fopen (ifn, "r");
2036 fail ("%s: open: %s.", ifn, strerror (errno));
2039 out = fopen (ofn, "w");
2041 fail ("%s: open: %s.", ofn, strerror (errno));
2044 buf = xmalloc (MAX_LINE_LEN);
2045 tokstr = xmalloc (MAX_TOK_LEN);
2051 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2054 const char *directive = recognize_directive ();
2055 if (directive == NULL)
2057 dump (0, "%s", buf);
2061 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2062 if (!strcmp (directive, "specification"))
2064 /* Skip leading slash-star line. */
2070 /* Skip trailing star-slash line. */
2073 else if (!strcmp (directive, "headers"))
2077 dump (0, "#include <stdlib.h>");
2078 dump (0, "#include <libpspp/alloc.h>");
2079 dump (0, "#include <libpspp/assertion.h>");
2080 dump (0, "#include <libpspp/message.h>");
2081 dump (0, "#include <language/lexer/lexer.h>");
2082 dump (0, "#include <language/lexer/variable-parser.h>");
2083 dump (0, "#include <data/settings.h>");
2084 dump (0, "#include <libpspp/magic.h>");
2085 dump (0, "#include <libpspp/str.h>");
2086 dump (0, "#include <language/lexer/subcommand-list.h>");
2087 dump (0, "#include <data/variable.h>");
2090 dump (0, "#include \"gettext.h\"");
2091 dump (0, "#define _(msgid) gettext (msgid)");
2094 else if (!strcmp (directive, "declarations"))
2095 dump_declarations ();
2096 else if (!strcmp (directive, "functions"))
2101 else if (!strcmp (directive, "_functions"))
2107 error ("unknown directive `%s'", directive);
2109 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2112 return EXIT_SUCCESS;