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
32 #include <libpspp/compiler.h>
33 #include <libpspp/str.h>
38 #define EXIT_SUCCESS 0
42 #define EXIT_FAILURE 1
46 #include <libpspp/debug-print.h>
48 /* Max length of an input line. */
49 #define MAX_LINE_LEN 1024
51 /* Max token length. */
52 #define MAX_TOK_LEN 1024
57 /* Have the input and output files been opened yet? */
60 /* Input, output files. */
63 /* Input, output file names. */
66 /* Input, output file line number. */
69 /* Input line buffer, current position. */
75 T_STRING = 256, /* String literal. */
76 T_ID = 257 /* Identifier. */
79 /* Current token: either one of the above, or a single character. */
82 /* Token string value. */
85 /* Utility functions. */
89 /* Close all open files and delete the output file, on failure. */
98 if (remove (ofn) == -1)
99 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
102 void hcf (void) NO_RETURN;
104 /* Terminate unsuccessfully. */
112 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
113 int error (const char *, ...) PRINTF_FORMAT (1, 2);
115 /* Output an error message and terminate unsuccessfully. */
117 fail (const char *format, ...)
121 va_start (args, format);
122 fprintf (stderr, "%s: ", program_name);
123 vfprintf (stderr, format, args);
124 fprintf (stderr, "\n");
130 /* Output a context-dependent error message and terminate
133 error (const char *format,...)
137 va_start (args, format);
138 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
139 vfprintf (stderr, format, args);
140 fprintf (stderr, "\n");
146 #define VME "virtual memory exhausted"
148 /* Allocate a block of SIZE bytes and return a pointer to its
151 xmalloc (size_t size)
160 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
165 /* Make a dynamically allocated copy of string S and return a pointer
166 to the first character. */
168 xstrdup (const char *s)
174 size = strlen (s) + 1;
178 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
184 /* Returns a pointer to one of 8 static buffers. The buffers are used
189 static char b[8][256];
198 /* Copies a string to a static buffer, converting it to lowercase in
199 the process, and returns a pointer to the static buffer. */
201 st_lower (const char *s)
205 p = cp = get_buffer ();
207 *cp++ = tolower ((unsigned char) (*s++));
213 /* Copies a string to a static buffer, converting it to uppercase in
214 the process, and returns a pointer to the static buffer. */
216 st_upper (const char *s)
220 p = cp = get_buffer ();
222 *cp++ = toupper ((unsigned char) (*s++));
228 /* Returns the address of the first non-whitespace character in S, or
229 the address of the null terminator if none. */
231 skip_ws (const char *s)
233 while (isspace ((unsigned char) *s))
238 /* Read one line from the input file into buf. Lines having special
239 formats are handled specially. */
244 if (0 == fgets (buf, MAX_LINE_LEN, in))
247 fail ("%s: fgets: %s", ifn, strerror (errno));
251 cp = strchr (buf, '\n');
259 /* Symbol table manager. */
261 /* Symbol table entry. */
262 typedef struct symbol symbol;
265 symbol *next; /* Next symbol in symbol table. */
266 char *name; /* Symbol name. */
267 int unique; /* 1=Name must be unique in this file. */
268 int ln; /* Line number of definition. */
269 int value; /* Symbol value. */
275 /* Add a symbol to the symbol table having name NAME, uniqueness
276 UNIQUE, and value VALUE. If a symbol having the same name is found
277 in the symbol table, its sequence number is returned and the symbol
278 table is not modified. Otherwise, the symbol is added and the next
279 available sequence number is returned. */
281 add_symbol (const char *name, int unique, int value)
286 sym = xmalloc (sizeof *sym);
287 sym->name = xstrdup (name);
288 sym->unique = unique;
301 if (!strcmp (iter->name, name))
305 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
307 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
324 /* Finds the symbol having given sequence number X within the symbol
325 table, and returns the associated symbol structure. */
332 while (x > 1 && iter)
342 /* Writes a printable representation of the current token to
350 printf ("STRING\t\"%s\"\n", tokstr);
353 printf ("ID\t%s\n", tokstr);
356 printf ("PUNCT\t%c\n", token);
359 #endif /* DEBUGGING */
361 /* Reads a token from the input file. */
365 /* Skip whitespace and check for end of file. */
373 fail ("%s: Unexpected end of file.", ifn);
381 while (*cp != '"' && *cp)
387 error ("Unterminated string literal.");
395 error ("Unterminated string literal.");
398 else if (*cp == '_' || isalnum ((unsigned char) *cp))
402 while (*cp == '_' || isalnum ((unsigned char) *cp))
403 *dest++ = toupper ((unsigned char) (*cp++));
416 /* Force the current token to be an identifier token. */
421 error ("Identifier expected.");
424 /* Force the current token to be a string token. */
428 if (token != T_STRING)
429 error ("String expected.");
432 /* Checks whether the current token is the identifier S; if so, skips
433 the token and returns 1; otherwise, returns 0. */
435 match_id (const char *s)
437 if (token == T_ID && !strcmp (tokstr, s))
445 /* Checks whether the current token is T. If so, skips the token and
446 returns 1; otherwise, returns 0. */
458 /* Force the current token to be T, and skip it. */
463 error ("`%c' expected.", t);
469 /* Some specifiers have associated values. */
472 VAL_NONE, /* No value. */
473 VAL_INT, /* Integer value. */
474 VAL_DBL /* Floating point value. */
477 /* For those specifiers with values, the syntax of those values. */
480 VT_PLAIN, /* Unadorned value. */
481 VT_PAREN /* Value must be enclosed in parentheses. */
484 /* Forward definition. */
485 typedef struct specifier specifier;
487 /* A single setting. */
488 typedef struct setting setting;
491 specifier *parent; /* Owning specifier. */
492 setting *next; /* Next in the chain. */
493 char *specname; /* Name of the setting. */
494 int con; /* Sequence number. */
497 int valtype; /* One of VT_*. */
498 int value; /* One of VAL_*. */
499 int optvalue; /* 1=value is optional, 0=value is required. */
500 char *valname; /* Variable name for the value. */
501 char *restriction; /* !=NULL: expression specifying valid values. */
504 /* A single specifier. */
507 specifier *next; /* Next in the chain. */
508 char *varname; /* Variable name. */
509 setting *s; /* Associated settings. */
511 setting *def; /* Default setting. */
512 setting *omit_kw; /* Setting for which the keyword can be omitted. */
514 int index; /* Next array index. */
517 /* Subcommand types. */
520 SBC_PLAIN, /* The usual case. */
521 SBC_VARLIST, /* Variable list. */
522 SBC_INT, /* Integer value. */
523 SBC_PINT, /* Integer inside parentheses. */
524 SBC_DBL, /* Floating point value. */
525 SBC_INT_LIST, /* List of integers (?). */
526 SBC_DBL_LIST, /* List of floating points (?). */
527 SBC_CUSTOM, /* Custom. */
528 SBC_ARRAY, /* Array of boolean values. */
529 SBC_STRING, /* String value. */
530 SBC_VAR /* Single variable name. */
536 ARITY_ONCE_EXACTLY, /* must occur exactly once */
537 ARITY_ONCE_ONLY, /* zero or once */
538 ARITY_MANY /* 0, 1, ... , inf */
541 /* A single subcommand. */
542 typedef struct subcommand subcommand;
545 subcommand *next; /* Next in the chain. */
546 char *name; /* Subcommand name. */
547 subcommand_type type; /* One of SBC_*. */
548 subcommand_arity arity; /* How many times should the subcommand occur*/
549 int narray; /* Index of next array element. */
550 const char *prefix; /* Prefix for variable and constant names. */
551 specifier *spec; /* Array of specifiers. */
553 /* SBC_STRING and SBC_INT only. */
554 char *restriction; /* Expression restricting string length. */
555 char *message; /* Error message. */
556 int translatable; /* Error message is translatable */
559 /* Name of the command; i.e., DESCRIPTIVES. */
562 /* Short prefix for the command; i.e., `dsc_'. */
565 /* List of subcommands. */
566 subcommand *subcommands;
568 /* Default subcommand if any, or NULL. */
573 void parse_subcommands (void);
575 /* Parse an entire specification. */
579 /* Get the command name and prefix. */
580 if (token != T_STRING && token != T_ID)
581 error ("Command name expected.");
582 cmdname = xstrdup (tokstr);
586 prefix = xstrdup (tokstr);
591 /* Read all the subcommands. */
594 parse_subcommands ();
597 /* Parses a single setting into S, given subcommand information SBC
598 and specifier information SPEC. */
600 parse_setting (setting *s, specifier *spec)
604 if (match_token ('*'))
607 error ("Cannot have two settings with omittable keywords.");
612 if (match_token ('!'))
615 error ("Cannot have two default settings.");
621 s->specname = xstrdup (tokstr);
622 s->con = add_symbol (s->specname, 0, 0);
627 /* Parse setting value info if necessary. */
628 if (token != '/' && token != ';' && token != '.' && token != ',')
632 s->valtype = VT_PAREN;
636 s->valtype = VT_PLAIN;
638 s->optvalue = match_token ('*');
642 else if (match_id ("D"))
645 error ("`n' or `d' expected.");
650 s->valname = xstrdup (tokstr);
657 s->restriction = xstrdup (tokstr);
661 s->restriction = NULL;
663 if (s->valtype == VT_PAREN)
668 /* Parse a single specifier into SPEC, given subcommand information
671 parse_specifier (specifier *spec, subcommand *sbc)
676 spec->omit_kw = NULL;
677 spec->varname = NULL;
681 spec->varname = xstrdup (st_lower (tokstr));
685 /* Handle array elements. */
688 spec->index = sbc->narray;
689 if (sbc->type == SBC_ARRAY)
701 if ( sbc->type == SBC_ARRAY && token == T_ID )
703 spec->varname = xstrdup (st_lower (tokstr));
704 spec->index = sbc->narray;
710 /* Parse all the settings. */
712 setting **s = &spec->s;
716 *s = xmalloc (sizeof **s);
717 parse_setting (*s, spec);
718 if (token == ',' || token == ';' || token == '.')
727 /* Parse a list of specifiers for subcommand SBC. */
729 parse_specifiers (subcommand *sbc)
731 specifier **spec = &sbc->spec;
733 if (token == ';' || token == '.')
741 *spec = xmalloc (sizeof **spec);
742 parse_specifier (*spec, sbc);
743 if (token == ';' || token == '.')
746 spec = &(*spec)->next;
748 (*spec)->next = NULL;
751 /* Parse a subcommand into SBC. */
753 parse_subcommand (subcommand *sbc)
755 sbc->arity = ARITY_MANY;
757 if (match_token ('*'))
760 error ("Multiple default subcommands.");
764 if ( match_token('+'))
765 sbc->arity = ARITY_ONCE_ONLY ;
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 1 if string T is a PSPP keyword, 0 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, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1138 st_lower (sbc->name));
1142 dump (0, "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 cmd_%s *);",
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 cmd_%s *);",
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 (T_%s)", t);
1359 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1360 strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1361 "|| lex_match_id (\"TRUE\"))");
1362 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1363 strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1364 "|| lex_match_id (\"FALSE\"))");
1365 else if (isdigit ((unsigned char) t[0]))
1366 sprintf (s, "lex_match_int (%s)", t);
1368 sprintf (s, "lex_match_id (\"%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 ('('))");
1437 dump (1, "if (!lex_match ('('))");
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 ())");
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 ();",
1458 sbc->prefix, st_lower (s->valname));
1462 dump (1, "if (!lex_is_number ())");
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 = tokval;", 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 ();");
1498 if (s->valtype == VT_PAREN)
1500 dump (1, "if (!lex_match (')'))");
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 (token != '/' && token != '.')");
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 (NULL);");
1588 dump (0, "goto lossage;");
1594 dump (0, "lex_match (',');");
1598 else if (sbc->type == SBC_VARLIST)
1600 dump (1, "if (!parse_variables (default_dict, &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 ();",
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 ())");
1626 dump (0, "return 0;");
1628 if (sbc->restriction)
1630 dump (0, "x = ds_length (&tokstr);");
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 = xstrdup (ds_c_str (&tokstr));",
1641 st_lower (sbc->name));
1642 dump (0, "lex_get ();");
1643 if (sbc->restriction)
1646 else if (sbc->type == SBC_DBL)
1648 dump (1, "if (!lex_force_num ())");
1649 dump (0, "goto lossage;");
1650 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();",
1651 st_lower (sbc->name), st_lower (sbc->name) );
1652 dump (0, "lex_get();");
1654 else if (sbc->type == SBC_INT)
1658 dump (1, "if (!lex_force_int ())");
1659 dump (0, "goto lossage;");
1660 dump (-1, "x = lex_integer ();");
1661 dump (0, "lex_get();");
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 ('(');");
1681 dump (1, "if (!lex_force_int ())");
1682 dump (0, "goto lossage;");
1683 dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1684 dump (0, "lex_match (')');");
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 (token != '/' && token != '.')");
1696 dump (0, "lex_match(',');");
1697 dump (0, "if (!lex_force_num ())");
1699 dump (0, "goto lossage;");
1702 dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());",
1703 st_lower (sbc->name),st_lower (sbc->name)
1706 dump (0, "lex_get();");
1710 else if (sbc->type == SBC_CUSTOM)
1712 dump (1, "switch (%scustom_%s (p))",
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 (NULL);");
1723 dump (0, "goto lossage;");
1724 dump (-1, "default:");
1726 dump (0, "assert (0);");
1732 /* Write out entire parser. */
1734 dump_parser (int persistent)
1740 dump (0, "static int");
1741 dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1742 make_identifier (cmdname));
1745 dump_vars_init (persistent);
1747 dump (1, "for (;;)");
1751 if (def && (def->type == SBC_VARLIST))
1753 if (def->type == SBC_VARLIST)
1754 dump (1, "if (token == T_ID "
1755 "&& dict_lookup_var (default_dict, tokid) != NULL "
1756 "&& lex_look_ahead () != '=')");
1759 dump (0, "if ((token == T_ID "
1760 "&& dict_lookup_var (default_dict, tokid) "
1761 "&& lex_look_ahead () != '=')");
1762 dump (1, " || token == T_ALL)");
1765 dump (0, "p->sbc_%s++;", st_lower (def->name));
1766 dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1768 st_lower (def->prefix), st_lower (def->name),
1769 st_lower (def->prefix), st_lower (def->name));
1770 dump (0, "goto lossage;");
1775 else if (def && def->type == SBC_CUSTOM)
1777 dump (1, "switch (%scustom_%s (p))",
1778 st_lower (prefix), st_lower (def->name));
1780 dump (1, "case 0:");
1781 dump (0, "goto lossage;");
1782 dump (-1, "case 1:");
1784 dump (0, "p->sbc_%s++;", st_lower (def->name));
1785 dump (0, "continue;");
1786 dump (-1, "case 2:");
1789 dump (-1, "default:");
1791 dump (0, "assert (0);");
1799 for (sbc = subcommands; sbc; sbc = sbc->next)
1801 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1805 dump (0, "lex_match ('=');");
1806 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1807 if (sbc->arity != ARITY_MANY)
1809 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1811 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1813 dump (0, "goto lossage;");
1817 dump_subcommand (sbc);
1824 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1825 dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
1828 dump (0, "lex_match ('=');");
1830 dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
1831 dump(0,"set_cmd_algorithm(COMPATIBLE);");
1833 dump(1,"else if (lex_match_id(\"ENHANCED\"))");
1834 dump(0,"set_cmd_algorithm(ENHANCED);");
1841 dump (1, "if (!lex_match ('/'))");
1846 dump (1, "if (token != '.')");
1848 dump (0, "lex_error (_(\"expecting end of command\"));");
1849 dump (0, "goto lossage;");
1856 /* Check that mandatory subcommands have been specified */
1859 for (sbc = subcommands; sbc; sbc = sbc->next)
1862 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1864 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1866 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1868 dump (0, "goto lossage;");
1875 dump (-1, "return 1;");
1877 dump (-1, "lossage:");
1879 dump (0, "free_%s (p);", make_identifier (cmdname));
1880 dump (0, "return 0;");
1886 /* Write the output file header. */
1895 curtime = time (NULL);
1896 loctime = localtime (&curtime);
1897 timep = asctime (loctime);
1898 timep[strlen (timep) - 1] = 0;
1899 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1901 dump (0, " Generated by q2c from %s on %s.", ifn, timep);
1902 dump (0, " Do not modify!");
1906 /* Write out commands to free variable state. */
1908 dump_free (int persistent)
1918 for (sbc = subcommands; sbc; sbc = sbc->next)
1920 if (sbc->type == SBC_STRING)
1922 if (sbc->type == SBC_DBL_LIST)
1928 dump (0, "static void");
1929 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1930 make_identifier (cmdname), used ? "" : " UNUSED");
1936 for (sbc = subcommands; sbc; sbc = sbc->next)
1941 dump (0, "free (p->v_%s);", st_lower (sbc->name));
1944 dump (0, "free (p->s_%s);", st_lower (sbc->name));
1948 dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
1949 dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
1964 /* Returns the name of a directive found on the current input line, if
1965 any, or a null pointer if none found. */
1967 recognize_directive (void)
1969 static char directive[16];
1973 if (strncmp (sp, "/*", 2))
1975 sp = skip_ws (sp + 2);
1980 ep = strchr (sp, ')');
1986 memcpy (directive, sp, ep - sp);
1987 directive[ep - sp] = '\0';
1992 main (int argc, char *argv[])
1994 program_name = argv[0];
1996 fail ("Syntax: q2c input.q output.c");
1999 in = fopen (ifn, "r");
2001 fail ("%s: open: %s.", ifn, strerror (errno));
2004 out = fopen (ofn, "w");
2006 fail ("%s: open: %s.", ofn, strerror (errno));
2009 buf = xmalloc (MAX_LINE_LEN);
2010 tokstr = xmalloc (MAX_TOK_LEN);
2016 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2019 const char *directive = recognize_directive ();
2020 if (directive == NULL)
2022 dump (0, "%s", buf);
2026 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2027 if (!strcmp (directive, "specification"))
2029 /* Skip leading slash-star line. */
2035 /* Skip trailing star-slash line. */
2038 else if (!strcmp (directive, "headers"))
2042 dump (0, "#include <stdlib.h>");
2043 dump (0, "#include <libpspp/alloc.h>");
2044 dump (0, "#include <libpspp/message.h>");
2045 dump (0, "#include <language/lexer/lexer.h>");
2046 dump (0, "#include <data/settings.h>");
2047 dump (0, "#include <libpspp/str.h>");
2048 dump (0, "#include <language/lexer/subcommand-list.h>");
2049 dump (0, "#include <data/variable.h>");
2052 dump (0, "#include \"gettext.h\"");
2053 dump (0, "#define _(msgid) gettext (msgid)");
2056 else if (!strcmp (directive, "declarations"))
2057 dump_declarations ();
2058 else if (!strcmp (directive, "functions"))
2063 else if (!strcmp (directive, "_functions"))
2069 error ("unknown directive `%s'", directive);
2071 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2076 return EXIT_SUCCESS;