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
30 #include <libpspp/assertion.h>
31 #include <libpspp/compiler.h>
32 #include <libpspp/str.h>
36 /* Max length of an input line. */
37 #define MAX_LINE_LEN 1024
39 /* Max token length. */
40 #define MAX_TOK_LEN 1024
45 /* Have the input and output files been opened yet? */
48 /* Input, output files. */
51 /* Input, output file names. */
54 /* Input, output file line number. */
57 /* Input line buffer, current position. */
63 T_STRING = 256, /* String literal. */
64 T_ID = 257 /* Identifier. */
67 /* Current token: either one of the above, or a single character. */
70 /* Token string value. */
73 /* Utility functions. */
77 /* Close all open files and delete the output file, on failure. */
86 if (remove (ofn) == -1)
87 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
90 void hcf (void) NO_RETURN;
92 /* Terminate unsuccessfully. */
100 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
101 int error (const char *, ...) PRINTF_FORMAT (1, 2);
103 /* Output an error message and terminate unsuccessfully. */
105 fail (const char *format, ...)
109 va_start (args, format);
110 fprintf (stderr, "%s: ", program_name);
111 vfprintf (stderr, format, args);
112 fprintf (stderr, "\n");
118 /* Output a context-dependent error message and terminate
121 error (const char *format,...)
125 va_start (args, format);
126 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
127 vfprintf (stderr, format, args);
128 fprintf (stderr, "\n");
134 #define VME "virtual memory exhausted"
136 /* Allocate a block of SIZE bytes and return a pointer to its
139 xmalloc (size_t size)
148 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
153 /* Make a dynamically allocated copy of string S and return a pointer
154 to the first character. */
156 xstrdup (const char *s)
162 size = strlen (s) + 1;
166 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
172 /* Returns a pointer to one of 8 static buffers. The buffers are used
177 static char b[8][256];
186 /* Copies a string to a static buffer, converting it to lowercase in
187 the process, and returns a pointer to the static buffer. */
189 st_lower (const char *s)
193 p = cp = get_buffer ();
195 *cp++ = tolower ((unsigned char) (*s++));
201 /* Copies a string to a static buffer, converting it to uppercase in
202 the process, and returns a pointer to the static buffer. */
204 st_upper (const char *s)
208 p = cp = get_buffer ();
210 *cp++ = toupper ((unsigned char) (*s++));
216 /* Returns the address of the first non-whitespace character in S, or
217 the address of the null terminator if none. */
219 skip_ws (const char *s)
221 while (isspace ((unsigned char) *s))
226 /* Read one line from the input file into buf. Lines having special
227 formats are handled specially. */
232 if (0 == fgets (buf, MAX_LINE_LEN, in))
235 fail ("%s: fgets: %s", ifn, strerror (errno));
239 cp = strchr (buf, '\n');
247 /* Symbol table manager. */
249 /* Symbol table entry. */
250 typedef struct symbol symbol;
253 symbol *next; /* Next symbol in symbol table. */
254 char *name; /* Symbol name. */
255 int unique; /* 1=Name must be unique in this file. */
256 int ln; /* Line number of definition. */
257 int value; /* Symbol value. */
263 /* Add a symbol to the symbol table having name NAME, uniqueness
264 UNIQUE, and value VALUE. If a symbol having the same name is found
265 in the symbol table, its sequence number is returned and the symbol
266 table is not modified. Otherwise, the symbol is added and the next
267 available sequence number is returned. */
269 add_symbol (const char *name, int unique, int value)
274 sym = xmalloc (sizeof *sym);
275 sym->name = xstrdup (name);
276 sym->unique = unique;
289 if (!strcmp (iter->name, name))
293 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
295 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
312 /* Finds the symbol having given sequence number X within the symbol
313 table, and returns the associated symbol structure. */
320 while (x > 1 && iter)
330 /* Writes a printable representation of the current token to
338 printf ("STRING\t\"%s\"\n", tokstr);
341 printf ("ID\t%s\n", tokstr);
344 printf ("PUNCT\t%c\n", token);
347 #endif /* DUMP_TOKENS */
349 /* Reads a token from the input file. */
353 /* Skip whitespace and check for end of file. */
361 fail ("%s: Unexpected end of file.", ifn);
369 while (*cp != '"' && *cp)
375 error ("Unterminated string literal.");
383 error ("Unterminated string literal.");
386 else if (*cp == '_' || isalnum ((unsigned char) *cp))
390 while (*cp == '_' || isalnum ((unsigned char) *cp))
391 *dest++ = toupper ((unsigned char) (*cp++));
404 /* Force the current token to be an identifier token. */
409 error ("Identifier expected.");
412 /* Force the current token to be a string token. */
416 if (token != T_STRING)
417 error ("String expected.");
420 /* Checks whether the current token is the identifier S; if so, skips
421 the token and returns true; otherwise, returns false. */
423 match_id (const char *s)
425 if (token == T_ID && !strcmp (tokstr, s))
433 /* Checks whether the current token is T. If so, skips the token and
434 returns true; otherwise, returns false. */
446 /* Force the current token to be T, and skip it. */
451 error ("`%c' expected.", t);
457 /* Some specifiers have associated values. */
460 VAL_NONE, /* No value. */
461 VAL_INT, /* Integer value. */
462 VAL_DBL /* Floating point value. */
465 /* For those specifiers with values, the syntax of those values. */
468 VT_PLAIN, /* Unadorned value. */
469 VT_PAREN /* Value must be enclosed in parentheses. */
472 /* Forward definition. */
473 typedef struct specifier specifier;
475 /* A single setting. */
476 typedef struct setting setting;
479 specifier *parent; /* Owning specifier. */
480 setting *next; /* Next in the chain. */
481 char *specname; /* Name of the setting. */
482 int con; /* Sequence number. */
485 int valtype; /* One of VT_*. */
486 int value; /* One of VAL_*. */
487 int optvalue; /* 1=value is optional, 0=value is required. */
488 char *valname; /* Variable name for the value. */
489 char *restriction; /* !=NULL: expression specifying valid values. */
492 /* A single specifier. */
495 specifier *next; /* Next in the chain. */
496 char *varname; /* Variable name. */
497 setting *s; /* Associated settings. */
499 setting *def; /* Default setting. */
500 setting *omit_kw; /* Setting for which the keyword can be omitted. */
502 int index; /* Next array index. */
505 /* Subcommand types. */
508 SBC_PLAIN, /* The usual case. */
509 SBC_VARLIST, /* Variable list. */
510 SBC_INT, /* Integer value. */
511 SBC_PINT, /* Integer inside parentheses. */
512 SBC_DBL, /* Floating point value. */
513 SBC_INT_LIST, /* List of integers (?). */
514 SBC_DBL_LIST, /* List of floating points (?). */
515 SBC_CUSTOM, /* Custom. */
516 SBC_ARRAY, /* Array of boolean values. */
517 SBC_STRING, /* String value. */
518 SBC_VAR /* Single variable name. */
524 ARITY_ONCE_EXACTLY, /* must occur exactly once */
525 ARITY_ONCE_ONLY, /* zero or once */
526 ARITY_MANY /* 0, 1, ... , inf */
529 /* A single subcommand. */
530 typedef struct subcommand subcommand;
533 subcommand *next; /* Next in the chain. */
534 char *name; /* Subcommand name. */
535 subcommand_type type; /* One of SBC_*. */
536 subcommand_arity arity; /* How many times should the subcommand occur*/
537 int narray; /* Index of next array element. */
538 const char *prefix; /* Prefix for variable and constant names. */
539 specifier *spec; /* Array of specifiers. */
541 /* SBC_STRING and SBC_INT only. */
542 char *restriction; /* Expression restricting string length. */
543 char *message; /* Error message. */
544 int translatable; /* Error message is translatable */
547 /* Name of the command; i.e., DESCRIPTIVES. */
550 /* Short prefix for the command; i.e., `dsc_'. */
553 /* List of subcommands. */
554 subcommand *subcommands;
556 /* Default subcommand if any, or NULL. */
561 void parse_subcommands (void);
563 /* Parse an entire specification. */
567 /* Get the command name and prefix. */
568 if (token != T_STRING && token != T_ID)
569 error ("Command name expected.");
570 cmdname = xstrdup (tokstr);
574 prefix = xstrdup (tokstr);
579 /* Read all the subcommands. */
582 parse_subcommands ();
585 /* Parses a single setting into S, given subcommand information SBC
586 and specifier information SPEC. */
588 parse_setting (setting *s, specifier *spec)
592 if (match_token ('*'))
595 error ("Cannot have two settings with omittable keywords.");
600 if (match_token ('!'))
603 error ("Cannot have two default settings.");
609 s->specname = xstrdup (tokstr);
610 s->con = add_symbol (s->specname, 0, 0);
615 /* Parse setting value info if necessary. */
616 if (token != '/' && token != ';' && token != '.' && token != ',')
620 s->valtype = VT_PAREN;
624 s->valtype = VT_PLAIN;
626 s->optvalue = match_token ('*');
630 else if (match_id ("D"))
633 error ("`n' or `d' expected.");
638 s->valname = xstrdup (tokstr);
645 s->restriction = xstrdup (tokstr);
649 s->restriction = NULL;
651 if (s->valtype == VT_PAREN)
656 /* Parse a single specifier into SPEC, given subcommand information
659 parse_specifier (specifier *spec, subcommand *sbc)
664 spec->omit_kw = NULL;
665 spec->varname = NULL;
669 spec->varname = xstrdup (st_lower (tokstr));
673 /* Handle array elements. */
676 spec->index = sbc->narray;
677 if (sbc->type == SBC_ARRAY)
689 if ( sbc->type == SBC_ARRAY && token == T_ID )
691 spec->varname = xstrdup (st_lower (tokstr));
692 spec->index = sbc->narray;
698 /* Parse all the settings. */
700 setting **s = &spec->s;
704 *s = xmalloc (sizeof **s);
705 parse_setting (*s, spec);
706 if (token == ',' || token == ';' || token == '.')
715 /* Parse a list of specifiers for subcommand SBC. */
717 parse_specifiers (subcommand *sbc)
719 specifier **spec = &sbc->spec;
721 if (token == ';' || token == '.')
729 *spec = xmalloc (sizeof **spec);
730 parse_specifier (*spec, sbc);
731 if (token == ';' || token == '.')
734 spec = &(*spec)->next;
736 (*spec)->next = NULL;
739 /* Parse a subcommand into SBC. */
741 parse_subcommand (subcommand *sbc)
743 if (match_token ('*'))
746 error ("Multiple default subcommands.");
750 sbc->arity = ARITY_ONCE_ONLY;
751 if ( match_token('+'))
752 sbc->arity = ARITY_MANY;
753 else if (match_token('^'))
754 sbc->arity = ARITY_ONCE_EXACTLY ;
758 sbc->name = xstrdup (tokstr);
762 sbc->type = SBC_PLAIN;
764 sbc->translatable = 0;
766 if (match_token ('['))
769 sbc->prefix = xstrdup (st_lower (tokstr));
775 sbc->type = SBC_ARRAY;
776 parse_specifiers (sbc);
781 if (match_token ('('))
784 sbc->prefix = xstrdup (st_lower (tokstr));
794 if (match_id ("VAR"))
796 if (match_id ("VARLIST"))
798 if (match_token ('('))
801 sbc->message = xstrdup (tokstr);
806 else sbc->message = NULL;
808 sbc->type = SBC_VARLIST;
810 else if (match_id ("INTEGER"))
812 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
813 if ( token == T_STRING)
815 sbc->restriction = xstrdup (tokstr);
817 if ( match_id("N_") )
823 sbc->translatable = 1;
829 sbc->message = xstrdup (tokstr);
832 sbc->restriction = NULL;
834 else if (match_id ("PINT"))
835 sbc->type = SBC_PINT;
836 else if (match_id ("DOUBLE"))
838 if ( match_id ("LIST") )
839 sbc->type = SBC_DBL_LIST;
843 else if (match_id ("STRING"))
845 sbc->type = SBC_STRING;
846 if (token == T_STRING)
848 sbc->restriction = xstrdup (tokstr);
851 sbc->message = xstrdup (tokstr);
855 sbc->restriction = NULL;
857 else if (match_id ("CUSTOM"))
858 sbc->type = SBC_CUSTOM;
860 parse_specifiers (sbc);
864 /* Parse all the subcommands. */
866 parse_subcommands (void)
868 subcommand **sbc = &subcommands;
872 *sbc = xmalloc (sizeof **sbc);
875 parse_subcommand (*sbc);
887 #define BASE_INDENT 2 /* Starting indent. */
888 #define INC_INDENT 2 /* Indent increment. */
890 /* Increment the indent. */
891 #define indent() indent += INC_INDENT
892 #define outdent() indent -= INC_INDENT
894 /* Size of the indent from the left margin. */
897 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
899 /* Write line FORMAT to the output file, formatted as with printf,
900 indented `indent' characters from the left margin. If INDENTION is
901 greater than 0, indents BASE_INDENT * INDENTION characters after
902 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
903 * INDENTION characters _before_ writing the line. */
905 dump (int indention, const char *format, ...)
911 indent += BASE_INDENT * indention;
914 va_start (args, format);
915 for (i = 0; i < indent; i++)
917 vfprintf (out, format, args);
922 indent += BASE_INDENT * indention;
925 /* Write the structure members for specifier SPEC to the output file.
926 SBC is the including subcommand. */
928 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
931 dump (0, "long %s%s;", sbc->prefix, spec->varname);
936 for (s = spec->s; s; s = s->next)
938 if (s->value != VAL_NONE)
940 const char *typename;
942 assert (s->value == VAL_INT || s->value == VAL_DBL);
943 typename = s->value == VAL_INT ? "long" : "double";
945 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
951 /* Returns true if string T is a PSPP keyword, false otherwise. */
953 is_keyword (const char *t)
955 static const char *kw[] =
957 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
958 "NE", "ALL", "BY", "TO", "WITH", 0,
962 for (cp = kw; *cp; cp++)
963 if (!strcmp (t, *cp))
968 /* Transforms a string NAME into a valid C identifier: makes
969 everything lowercase and maps nonalphabetic characters to
970 underscores. Returns a pointer to a static buffer. */
972 make_identifier (const char *name)
974 char *p = get_buffer ();
977 for (cp = p; *name; name++)
978 if (isalpha ((unsigned char) *name))
979 *cp++ = tolower ((unsigned char) (*name));
987 /* Writes the struct and enum declarations for the parser. */
989 dump_declarations (void)
993 /* Write out enums for all the identifiers in the symbol table. */
999 /* Note the squirmings necessary to make sure that the last enum
1000 is not followed by a comma, as mandated by ANSI C89. */
1001 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1002 if (!sym->unique && !is_keyword (sym->name))
1006 dump (0, "/* Settings for subcommand specifiers. */");
1013 buf = xmalloc (1024);
1018 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1022 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1027 buf[strlen (buf) - 1] = 0;
1038 /* Write out some type definitions */
1040 dump (0, "#define MAXLISTS 10");
1044 /* For every array subcommand, write out the associated enumerated
1049 for (sbc = subcommands; sbc; sbc = sbc->next)
1050 if (sbc->type == SBC_ARRAY && sbc->narray)
1052 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1060 for (spec = sbc->spec; spec; spec = spec->next)
1061 dump (0, "%s%s%s = %d,",
1062 st_upper (prefix), st_upper (sbc->prefix),
1063 st_upper (spec->varname), spec->index);
1065 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1073 /* Write out structure declaration. */
1077 dump (0, "/* %s structure. */", cmdname);
1078 dump (1, "struct cmd_%s", make_identifier (cmdname));
1080 for (sbc = subcommands; sbc; sbc = sbc->next)
1084 if (sbc != subcommands)
1087 dump (0, "/* %s subcommand. */", sbc->name);
1088 dump (0, "int sbc_%s;", st_lower (sbc->name));
1097 for (spec = sbc->spec; spec; spec = spec->next)
1101 if (sbc->type == SBC_PLAIN)
1102 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1106 dump (0, "int a_%s[%s%scount];",
1107 st_lower (sbc->name),
1109 st_upper (sbc->prefix)
1116 dump_specifier_vars (spec, sbc);
1122 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1123 st_lower (sbc->name));
1124 dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1125 st_lower (sbc->name));
1129 dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1130 st_lower (sbc->name));
1134 dump (0, "char *s_%s;", st_lower (sbc->name));
1139 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1143 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1147 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1148 st_lower(sbc->name));
1152 dump (0, "subc_list_int il_%s[MAXLISTS];",
1153 st_lower(sbc->name));
1166 /* Write out prototypes for custom_*() functions as necessary. */
1171 for (sbc = subcommands; sbc; sbc = sbc->next)
1172 if (sbc->type == SBC_CUSTOM)
1177 dump (0, "/* Prototype for custom subcommands of %s. */",
1180 dump (0, "static int %scustom_%s (struct dataset *, struct cmd_%s *, void *);",
1181 st_lower (prefix), st_lower (sbc->name),
1182 make_identifier (cmdname));
1189 /* Prototypes for parsing and freeing functions. */
1191 dump (0, "/* Command parsing functions. */");
1192 dump (0, "static int parse_%s (struct dataset *, struct cmd_%s *, void *);",
1193 make_identifier (cmdname), make_identifier (cmdname));
1194 dump (0, "static void free_%s (struct cmd_%s *);",
1195 make_identifier (cmdname), make_identifier (cmdname));
1200 /* Writes out code to initialize all the variables that need
1201 initialization for particular specifier SPEC inside subcommand SBC. */
1203 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1211 st_upper (prefix), find_symbol (spec->def->con)->name);
1214 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1220 for (s = spec->s; s; s = s->next)
1222 if (s->value != VAL_NONE)
1226 assert (s->value == VAL_INT || s->value == VAL_DBL);
1227 init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1229 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1235 /* Write code to initialize all variables. */
1237 dump_vars_init (int persistent)
1239 /* Loop through all the subcommands. */
1243 for (sbc = subcommands; sbc; sbc = sbc->next)
1247 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1258 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1259 dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
1260 st_lower (sbc->name)
1268 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1269 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1282 for (spec = sbc->spec; spec; spec = spec->next)
1283 if (spec->s == NULL)
1285 if (sbc->type == SBC_PLAIN)
1286 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1289 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1290 st_lower (sbc->name), st_lower (sbc->name));
1295 dump_specifier_init (spec, sbc);
1300 dump (0, "p->%sn_%s = 0;",
1301 st_lower (sbc->prefix), st_lower (sbc->name));
1302 dump (0, "p->%sv_%s = NULL;",
1303 st_lower (sbc->prefix), st_lower (sbc->name));
1307 dump (0, "p->%sv_%s = NULL;",
1308 st_lower (sbc->prefix), st_lower (sbc->name));
1312 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1319 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1320 dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
1332 /* Return a pointer to a static buffer containing an expression that
1333 will match token T. */
1335 make_match (const char *t)
1345 sprintf (s, "lex_match (T_%s)", t);
1346 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1347 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1348 "|| lex_match_id (\"TRUE\"))");
1349 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1350 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1351 "|| lex_match_id (\"FALSE\"))");
1352 else if (isdigit ((unsigned char) t[0]))
1353 sprintf (s, "lex_match_int (%s)", t);
1355 sprintf (s, "lex_match_id (\"%s\")", t);
1360 /* Write out the parsing code for specifier SPEC within subcommand
1363 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1367 if (spec->omit_kw && spec->omit_kw->next)
1368 error ("Omittable setting is not last setting in `%s' specifier.",
1370 if (spec->omit_kw && spec->omit_kw->parent->next)
1371 error ("Default specifier is not in last specifier in `%s' "
1372 "subcommand.", sbc->name);
1374 for (s = spec->s; s; s = s->next)
1376 int first = spec == sbc->spec && s == spec->s;
1378 /* Match the setting's keyword. */
1379 if (spec->omit_kw == s)
1386 dump (1, "%s;", make_match (s->specname));
1389 dump (1, "%sif (%s)", first ? "" : "else ",
1390 make_match (s->specname));
1393 /* Handle values. */
1394 if (s->value == VAL_NONE)
1395 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1396 st_upper (prefix), find_symbol (s->con)->name);
1399 if (spec->omit_kw != s)
1404 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1405 st_upper (prefix), find_symbol (s->con)->name);
1407 if ( sbc->type == SBC_ARRAY )
1408 dump (0, "p->a_%s[%s%s%s] = 1;",
1409 st_lower (sbc->name),
1410 st_upper (prefix), st_upper (sbc->prefix),
1411 st_upper (spec->varname));
1415 if (s->valtype == VT_PAREN)
1419 dump (1, "if (lex_match ('('))");
1424 dump (1, "if (!lex_match ('('))");
1426 dump (0, "msg (SE, _(\"`(' expected after %s "
1427 "specifier of %s subcommand.\"));",
1428 s->specname, sbc->name);
1429 dump (0, "goto lossage;");
1435 if (s->value == VAL_INT)
1437 dump (1, "if (!lex_is_integer ())");
1439 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1440 "requires an integer argument.\"));",
1441 s->specname, sbc->name);
1442 dump (0, "goto lossage;");
1444 dump (-1, "p->%s%s = lex_integer ();",
1445 sbc->prefix, st_lower (s->valname));
1449 dump (1, "if (!lex_is_number ())");
1451 dump (0, "msg (SE, _(\"Number expected after %s "
1452 "specifier of %s subcommand.\"));",
1453 s->specname, sbc->name);
1454 dump (0, "goto lossage;");
1456 dump (-1, "p->%s%s = tokval;", sbc->prefix,
1457 st_lower (s->valname));
1464 str = xmalloc (MAX_TOK_LEN);
1465 str2 = xmalloc (MAX_TOK_LEN);
1466 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1467 sprintf (str, s->restriction, str2, str2, str2, str2,
1468 str2, str2, str2, str2);
1469 dump (1, "if (!(%s))", str);
1475 dump (0, "msg (SE, _(\"Bad argument for %s "
1476 "specifier of %s subcommand.\"));",
1477 s->specname, sbc->name);
1478 dump (0, "goto lossage;");
1483 dump (0, "lex_get ();");
1485 if (s->valtype == VT_PAREN)
1487 dump (1, "if (!lex_match (')'))");
1489 dump (0, "msg (SE, _(\"`)' expected after argument for "
1490 "%s specifier of %s.\"));",
1491 s->specname, sbc->name);
1492 dump (0, "goto lossage;");
1502 if (s != spec->omit_kw)
1506 if (s == spec->omit_kw)
1515 /* Write out the code to parse subcommand SBC. */
1517 dump_subcommand (const subcommand *sbc)
1519 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1523 dump (1, "while (token != '/' && token != '.')");
1529 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1532 dump_specifier_parse (spec, sbc);
1536 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1537 make_match (st_upper (spec->varname)));
1538 if (sbc->type == SBC_PLAIN)
1539 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1542 dump (0, "p->a_%s[%s%s%s] = 1;",
1543 st_lower (sbc->name),
1544 st_upper (prefix), st_upper (sbc->prefix),
1545 st_upper (spec->varname));
1555 /* This code first finds the last specifier in sbc. Then it
1556 finds the last setting within that last specifier. Either
1557 or both might be NULL. */
1570 if (spec && (!spec->s || !spec->omit_kw))
1574 dump (0, "lex_error (NULL);");
1575 dump (0, "goto lossage;");
1581 dump (0, "lex_match (',');");
1585 else if (sbc->type == SBC_VARLIST)
1587 dump (1, "if (!parse_variables (dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1589 st_lower (sbc->prefix), st_lower (sbc->name),
1590 st_lower (sbc->prefix), st_lower (sbc->name),
1591 sbc->message ? " |" : "",
1592 sbc->message ? sbc->message : "");
1593 dump (0, "goto lossage;");
1596 else if (sbc->type == SBC_VAR)
1598 dump (0, "p->%sv_%s = parse_variable (dataset_dict (ds));",
1599 st_lower (sbc->prefix), st_lower (sbc->name));
1600 dump (1, "if (!p->%sv_%s)",
1601 st_lower (sbc->prefix), st_lower (sbc->name));
1602 dump (0, "goto lossage;");
1605 else if (sbc->type == SBC_STRING)
1607 if (sbc->restriction)
1612 dump (1, "if (!lex_force_string ())");
1613 dump (0, "return false;");
1615 if (sbc->restriction)
1617 dump (0, "x = ds_length (&tokstr);");
1618 dump (1, "if (!(%s))", sbc->restriction);
1620 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1621 sbc->name, sbc->message);
1622 dump (0, "goto lossage;");
1626 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1627 dump (0, "p->s_%s = ds_xstrdup (&tokstr);",
1628 st_lower (sbc->name));
1629 dump (0, "lex_get ();");
1630 if (sbc->restriction)
1633 else if (sbc->type == SBC_DBL)
1635 dump (1, "if (!lex_force_num ())");
1636 dump (0, "goto lossage;");
1637 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1638 st_lower (sbc->name), st_lower (sbc->name) );
1639 dump (0, "lex_get();");
1641 else if (sbc->type == SBC_INT)
1645 dump (1, "if (!lex_force_int ())");
1646 dump (0, "goto lossage;");
1647 dump (-1, "x = lex_integer ();");
1648 dump (0, "lex_get();");
1649 if (sbc->restriction)
1652 dump (1, "if (!(%s))", sbc->restriction);
1654 sprintf(buf,sbc->message,sbc->name);
1655 if ( sbc->translatable )
1656 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1658 dump (0, "msg (SE, \"%s\");",buf);
1659 dump (0, "goto lossage;");
1662 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1665 else if (sbc->type == SBC_PINT)
1667 dump (0, "lex_match ('(');");
1668 dump (1, "if (!lex_force_int ())");
1669 dump (0, "goto lossage;");
1670 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1671 dump (0, "lex_match (')');");
1673 else if (sbc->type == SBC_DBL_LIST)
1675 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1677 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1678 dump (0, "goto lossage;");
1681 dump (1, "while (token != '/' && token != '.')");
1683 dump (0, "lex_match(',');");
1684 dump (0, "if (!lex_force_num ())");
1686 dump (0, "goto lossage;");
1689 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1690 st_lower (sbc->name),st_lower (sbc->name)
1693 dump (0, "lex_get();");
1697 else if (sbc->type == SBC_CUSTOM)
1699 dump (1, "switch (%scustom_%s (ds, p, aux))",
1700 st_lower (prefix), st_lower (sbc->name));
1702 dump (1, "case 0:");
1703 dump (0, "goto lossage;");
1704 dump (-1, "case 1:");
1707 dump (-1, "case 2:");
1709 dump (0, "lex_error (NULL);");
1710 dump (0, "goto lossage;");
1711 dump (-1, "default:");
1713 dump (0, "NOT_REACHED ();");
1719 /* Write out entire parser. */
1721 dump_parser (int persistent)
1727 dump (0, "static int");
1728 dump (0, "parse_%s (struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)",
1729 make_identifier (cmdname),
1730 (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED",
1731 make_identifier (cmdname));
1734 dump_vars_init (persistent);
1736 dump (1, "for (;;)");
1740 if (def && (def->type == SBC_VARLIST))
1742 if (def->type == SBC_VARLIST)
1743 dump (1, "if (token == T_ID "
1744 "&& dict_lookup_var (dataset_dict (ds), tokid) != NULL "
1745 "&& lex_look_ahead () != '=')");
1748 dump (0, "if ((token == T_ID "
1749 "&& dict_lookup_var (dataset_dict (ds), tokid) "
1750 "&& lex_look_ahead () != '=')");
1751 dump (1, " || token == T_ALL)");
1754 dump (0, "p->sbc_%s++;", st_lower (def->name));
1755 dump (1, "if (!parse_variables (dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1757 st_lower (def->prefix), st_lower (def->name),
1758 st_lower (def->prefix), st_lower (def->name));
1759 dump (0, "goto lossage;");
1764 else if (def && def->type == SBC_CUSTOM)
1766 dump (1, "switch (%scustom_%s (ds, p, aux))",
1767 st_lower (prefix), st_lower (def->name));
1769 dump (1, "case 0:");
1770 dump (0, "goto lossage;");
1771 dump (-1, "case 1:");
1773 dump (0, "p->sbc_%s++;", st_lower (def->name));
1774 dump (0, "continue;");
1775 dump (-1, "case 2:");
1778 dump (-1, "default:");
1780 dump (0, "NOT_REACHED ();");
1788 for (sbc = subcommands; sbc; sbc = sbc->next)
1790 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1794 dump (0, "lex_match ('=');");
1795 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1796 if (sbc->arity != ARITY_MANY)
1798 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1800 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1802 dump (0, "goto lossage;");
1806 dump_subcommand (sbc);
1813 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1814 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1817 dump (0, "lex_match ('=');");
1819 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1820 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1822 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1823 dump(0,"set_cmd_algorithm(ENHANCED);");
1830 dump (1, "if (!lex_match ('/'))");
1835 dump (1, "if (token != '.')");
1837 dump (0, "lex_error (_(\"expecting end of command\"));");
1838 dump (0, "goto lossage;");
1845 /* Check that mandatory subcommands have been specified */
1848 for (sbc = subcommands; sbc; sbc = sbc->next)
1851 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1853 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1855 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1857 dump (0, "goto lossage;");
1864 dump (-1, "return true;");
1866 dump (-1, "lossage:");
1868 dump (0, "free_%s (p);", make_identifier (cmdname));
1869 dump (0, "return false;");
1875 /* Write the output file header. */
1884 curtime = time (NULL);
1885 loctime = localtime (&curtime);
1886 timep = asctime (loctime);
1887 timep[strlen (timep) - 1] = 0;
1888 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1890 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1891 dump (0, " Do not modify!");
1895 /* Write out commands to free variable state. */
1897 dump_free (int persistent)
1907 for (sbc = subcommands; sbc; sbc = sbc->next)
1909 if (sbc->type == SBC_STRING)
1911 if (sbc->type == SBC_DBL_LIST)
1917 dump (0, "static void");
1918 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1919 make_identifier (cmdname), used ? "" : " UNUSED");
1925 for (sbc = subcommands; sbc; sbc = sbc->next)
1930 dump (0, "free (p->v_%s);", st_lower (sbc->name));
1933 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1938 dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
1939 dump (1, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1955 /* Returns the name of a directive found on the current input line, if
1956 any, or a null pointer if none found. */
1958 recognize_directive (void)
1960 static char directive[16];
1964 if (strncmp (sp, "/*", 2))
1966 sp = skip_ws (sp + 2);
1971 ep = strchr (sp, ')');
1977 memcpy (directive, sp, ep - sp);
1978 directive[ep - sp] = '\0';
1983 main (int argc, char *argv[])
1985 program_name = argv[0];
1987 fail ("Syntax: q2c input.q output.c");
1990 in = fopen (ifn, "r");
1992 fail ("%s: open: %s.", ifn, strerror (errno));
1995 out = fopen (ofn, "w");
1997 fail ("%s: open: %s.", ofn, strerror (errno));
2000 buf = xmalloc (MAX_LINE_LEN);
2001 tokstr = xmalloc (MAX_TOK_LEN);
2007 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2010 const char *directive = recognize_directive ();
2011 if (directive == NULL)
2013 dump (0, "%s", buf);
2017 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2018 if (!strcmp (directive, "specification"))
2020 /* Skip leading slash-star line. */
2026 /* Skip trailing star-slash line. */
2029 else if (!strcmp (directive, "headers"))
2033 dump (0, "#include <stdlib.h>");
2034 dump (0, "#include <libpspp/alloc.h>");
2035 dump (0, "#include <libpspp/assertion.h>");
2036 dump (0, "#include <libpspp/message.h>");
2037 dump (0, "#include <language/lexer/lexer.h>");
2038 dump (0, "#include <language/lexer/variable-parser.h>");
2039 dump (0, "#include <data/settings.h>");
2040 dump (0, "#include <libpspp/str.h>");
2041 dump (0, "#include <language/lexer/subcommand-list.h>");
2042 dump (0, "#include <data/variable.h>");
2045 dump (0, "#include \"gettext.h\"");
2046 dump (0, "#define _(msgid) gettext (msgid)");
2049 else if (!strcmp (directive, "declarations"))
2050 dump_declarations ();
2051 else if (!strcmp (directive, "functions"))
2056 else if (!strcmp (directive, "_functions"))
2062 error ("unknown directive `%s'", directive);
2064 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2067 return EXIT_SUCCESS;