1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2008 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, see <http://www.gnu.org/licenses/>. */
27 /* GNU C allows the programmer to declare that certain functions take
28 printf-like arguments, never return, etc. Conditionalize these
29 declarations on whether gcc is in use. */
31 #define ATTRIBUTE(X) __attribute__ (X)
36 /* Marks a function argument as possibly not used. */
37 #define UNUSED ATTRIBUTE ((unused))
39 /* Marks a function that will never return. */
40 #define NO_RETURN ATTRIBUTE ((noreturn))
42 /* Mark a function as taking a printf- or scanf-like format
43 string as its FMT'th argument and that the FIRST'th argument
44 is the first one to be checked against the format string. */
45 #define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (__printf__, FMT, FIRST)))
47 /* Max length of an input line. */
48 #define MAX_LINE_LEN 1024
50 /* Max token length. */
51 #define MAX_TOK_LEN 1024
54 static char *program_name;
56 /* Have the input and output files been opened yet? */
59 /* Input, output files. */
60 static FILE *in, *out;
62 /* Input, output file names. */
63 static char *ifn, *ofn;
65 /* Input, output file line number. */
66 static int ln, oln = 1;
68 /* Input line buffer, current position. */
69 static char *buf, *cp;
74 T_STRING = 256, /* String literal. */
75 T_ID = 257 /* Identifier. */
78 /* Current token: either one of the above, or a single character. */
81 /* Token string value. */
84 /* Utility functions. */
86 static char nullstr[] = "";
88 /* Close all open files and delete the output file, on failure. */
97 if (remove (ofn) == -1)
98 fprintf (stderr, "%s: %s: remove: %s\n", program_name, ofn, strerror (errno));
101 void hcf (void) NO_RETURN;
103 /* Terminate unsuccessfully. */
111 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
112 int error (const char *, ...) PRINTF_FORMAT (1, 2);
114 /* Output an error message and terminate unsuccessfully. */
116 fail (const char *format, ...)
120 va_start (args, format);
121 fprintf (stderr, "%s: ", program_name);
122 vfprintf (stderr, format, args);
123 fprintf (stderr, "\n");
129 /* Output a context-dependent error message and terminate
132 error (const char *format,...)
136 va_start (args, format);
137 fprintf (stderr, "%s:%d: (column %d) ", ifn, ln, (int) (cp - buf));
138 vfprintf (stderr, format, args);
139 fprintf (stderr, "\n");
145 #define VME "virtual memory exhausted"
147 /* Allocate a block of SIZE bytes and return a pointer to its
150 xmalloc (size_t size)
159 fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
164 /* Make a dynamically allocated copy of string S and return a pointer
165 to the first character. */
167 xstrdup (const char *s)
173 size = strlen (s) + 1;
177 fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
183 /* Returns a pointer to one of 8 static buffers. The buffers are used
188 static char b[8][256];
197 /* Copies a string to a static buffer, converting it to lowercase in
198 the process, and returns a pointer to the static buffer. */
200 st_lower (const char *s)
204 p = cp = get_buffer ();
206 *cp++ = tolower ((unsigned char) (*s++));
212 /* Copies a string to a static buffer, converting it to uppercase in
213 the process, and returns a pointer to the static buffer. */
215 st_upper (const char *s)
219 p = cp = get_buffer ();
221 *cp++ = toupper ((unsigned char) (*s++));
227 /* Returns the address of the first non-whitespace character in S, or
228 the address of the null terminator if none. */
230 skip_ws (const char *s)
232 while (isspace ((unsigned char) *s))
237 /* Read one line from the input file into buf. Lines having special
238 formats are handled specially. */
243 if (0 == fgets (buf, MAX_LINE_LEN, in))
246 fail ("%s: fgets: %s", ifn, strerror (errno));
250 cp = strchr (buf, '\n');
258 /* Symbol table manager. */
260 /* Symbol table entry. */
261 typedef struct symbol symbol;
264 symbol *next; /* Next symbol in symbol table. */
265 char *name; /* Symbol name. */
266 int unique; /* 1=Name must be unique in this file. */
267 int ln; /* Line number of definition. */
268 int value; /* Symbol value. */
274 /* Add a symbol to the symbol table having name NAME, uniqueness
275 UNIQUE, and value VALUE. If a symbol having the same name is found
276 in the symbol table, its sequence number is returned and the symbol
277 table is not modified. Otherwise, the symbol is added and the next
278 available sequence number is returned. */
280 add_symbol (const char *name, int unique, int value)
285 sym = xmalloc (sizeof *sym);
286 sym->name = xstrdup (name);
287 sym->unique = unique;
300 if (!strcmp (iter->name, name))
304 fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
306 fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
323 /* Finds the symbol having given sequence number X within the symbol
324 table, and returns the associated symbol structure. */
331 while (x > 1 && iter)
341 /* Writes a printable representation of the current token to
349 printf ("STRING\t\"%s\"\n", tokstr);
352 printf ("ID\t%s\n", tokstr);
355 printf ("PUNCT\t%c\n", token);
358 #endif /* DUMP_TOKENS */
361 const char hyphen_proxy = '_';
369 while (*src == '_' || *src == '-' || isalnum ((unsigned char) *src))
371 *dest++ = *src == '-' ? hyphen_proxy :toupper ((unsigned char) (*src));
380 unmunge (const char *s)
382 char *dest = xmalloc (strlen (s) + 1);
387 if (*s == hyphen_proxy)
399 /* Reads a token from the input file. */
403 /* Skip whitespace and check for end of file. */
411 fail ("%s: Unexpected end of file.", ifn);
419 while (*cp != '"' && *cp)
425 error ("Unterminated string literal.");
433 error ("Unterminated string literal.");
436 else if (*cp == '_' || isalnum ((unsigned char) *cp))
453 /* Force the current token to be an identifier token. */
458 error ("Identifier expected.");
461 /* Force the current token to be a string token. */
465 if (token != T_STRING)
466 error ("String expected.");
469 /* Checks whether the current token is the identifier S; if so, skips
470 the token and returns true; otherwise, returns false. */
472 match_id (const char *s)
474 if (token == T_ID && !strcmp (tokstr, s))
482 /* Checks whether the current token is T. If so, skips the token and
483 returns true; otherwise, returns false. */
495 /* Force the current token to be T, and skip it. */
500 error ("`%c' expected.", t);
506 /* Some specifiers have associated values. */
509 VAL_NONE, /* No value. */
510 VAL_INT, /* Integer value. */
511 VAL_DBL, /* Floating point value. */
512 VAL_STRING /* String value. */
515 /* For those specifiers with values, the syntax of those values. */
518 VT_PLAIN, /* Unadorned value. */
519 VT_PAREN /* Value must be enclosed in parentheses. */
522 /* Forward definition. */
523 typedef struct specifier specifier;
525 /* A single setting. */
526 typedef struct setting setting;
529 specifier *parent; /* Owning specifier. */
530 setting *next; /* Next in the chain. */
531 char *specname; /* Name of the setting. */
532 int con; /* Sequence number. */
535 int valtype; /* One of VT_*. */
536 int value; /* One of VAL_*. */
537 int optvalue; /* 1=value is optional, 0=value is required. */
538 char *valname; /* Variable name for the value. */
539 char *restriction; /* !=NULL: expression specifying valid values. */
542 /* A single specifier. */
545 specifier *next; /* Next in the chain. */
546 char *varname; /* Variable name. */
547 setting *s; /* Associated settings. */
549 setting *def; /* Default setting. */
550 setting *omit_kw; /* Setting for which the keyword can be omitted. */
552 int index; /* Next array index. */
555 /* Subcommand types. */
558 SBC_PLAIN, /* The usual case. */
559 SBC_VARLIST, /* Variable list. */
560 SBC_INT, /* Integer value. */
561 SBC_PINT, /* Integer inside parentheses. */
562 SBC_DBL, /* Floating point value. */
563 SBC_INT_LIST, /* List of integers (?). */
564 SBC_DBL_LIST, /* List of floating points (?). */
565 SBC_CUSTOM, /* Custom. */
566 SBC_ARRAY, /* Array of boolean values. */
567 SBC_STRING, /* String value. */
568 SBC_VAR /* Single variable name. */
574 ARITY_ONCE_EXACTLY, /* must occur exactly once */
575 ARITY_ONCE_ONLY, /* zero or once */
576 ARITY_MANY /* 0, 1, ... , inf */
579 /* A single subcommand. */
580 typedef struct subcommand subcommand;
583 subcommand *next; /* Next in the chain. */
584 char *name; /* Subcommand name. */
585 subcommand_type type; /* One of SBC_*. */
586 subcommand_arity arity; /* How many times should the subcommand occur*/
587 int narray; /* Index of next array element. */
588 const char *prefix; /* Prefix for variable and constant names. */
589 specifier *spec; /* Array of specifiers. */
591 /* SBC_STRING and SBC_INT only. */
592 char *restriction; /* Expression restricting string length. */
593 char *message; /* Error message. */
594 int translatable; /* Error message is translatable */
597 /* Name of the command; i.e., DESCRIPTIVES. */
600 /* Short prefix for the command; i.e., `dsc_'. */
603 /* List of subcommands. */
604 subcommand *subcommands;
606 /* Default subcommand if any, or NULL. */
611 void parse_subcommands (void);
613 /* Parse an entire specification. */
617 /* Get the command name and prefix. */
618 if (token != T_STRING && token != T_ID)
619 error ("Command name expected.");
620 cmdname = xstrdup (tokstr);
624 prefix = xstrdup (tokstr);
629 /* Read all the subcommands. */
632 parse_subcommands ();
635 /* Parses a single setting into S, given subcommand information SBC
636 and specifier information SPEC. */
638 parse_setting (setting *s, specifier *spec)
642 if (match_token ('*'))
645 error ("Cannot have two settings with omittable keywords.");
650 if (match_token ('!'))
653 error ("Cannot have two default settings.");
659 s->specname = xstrdup (tokstr);
660 s->con = add_symbol (s->specname, 0, 0);
665 /* Parse setting value info if necessary. */
666 if (token != '/' && token != ';' && token != '.' && token != ',')
670 s->valtype = VT_PAREN;
674 s->valtype = VT_PLAIN;
676 s->optvalue = match_token ('*');
680 else if (match_id ("D"))
682 else if (match_id ("S"))
683 s->value = VAL_STRING;
685 error ("`n', `d', or `s' expected.");
690 s->valname = xstrdup (tokstr);
697 s->restriction = xstrdup (tokstr);
701 s->restriction = NULL;
703 if (s->valtype == VT_PAREN)
708 /* Parse a single specifier into SPEC, given subcommand information
711 parse_specifier (specifier *spec, subcommand *sbc)
716 spec->omit_kw = NULL;
717 spec->varname = NULL;
721 spec->varname = xstrdup (st_lower (tokstr));
725 /* Handle array elements. */
728 spec->index = sbc->narray;
729 if (sbc->type == SBC_ARRAY)
741 if ( sbc->type == SBC_ARRAY && token == T_ID )
743 spec->varname = xstrdup (st_lower (tokstr));
744 spec->index = sbc->narray;
750 /* Parse all the settings. */
752 setting **s = &spec->s;
756 *s = xmalloc (sizeof **s);
757 parse_setting (*s, spec);
758 if (token == ',' || token == ';' || token == '.')
767 /* Parse a list of specifiers for subcommand SBC. */
769 parse_specifiers (subcommand *sbc)
771 specifier **spec = &sbc->spec;
773 if (token == ';' || token == '.')
781 *spec = xmalloc (sizeof **spec);
782 parse_specifier (*spec, sbc);
783 if (token == ';' || token == '.')
786 spec = &(*spec)->next;
788 (*spec)->next = NULL;
791 /* Parse a subcommand into SBC. */
793 parse_subcommand (subcommand *sbc)
795 if (match_token ('*'))
798 error ("Multiple default subcommands.");
802 sbc->arity = ARITY_ONCE_ONLY;
803 if ( match_token('+'))
804 sbc->arity = ARITY_MANY;
805 else if (match_token('^'))
806 sbc->arity = ARITY_ONCE_EXACTLY ;
810 sbc->name = xstrdup (tokstr);
814 sbc->type = SBC_PLAIN;
816 sbc->translatable = 0;
818 if (match_token ('['))
821 sbc->prefix = xstrdup (st_lower (tokstr));
827 sbc->type = SBC_ARRAY;
828 parse_specifiers (sbc);
833 if (match_token ('('))
836 sbc->prefix = xstrdup (st_lower (tokstr));
846 if (match_id ("VAR"))
848 if (match_id ("VARLIST"))
850 if (match_token ('('))
853 sbc->message = xstrdup (tokstr);
858 else sbc->message = NULL;
860 sbc->type = SBC_VARLIST;
862 else if (match_id ("INTEGER"))
864 sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
865 if ( token == T_STRING)
867 sbc->restriction = xstrdup (tokstr);
869 if ( match_id("N_") )
875 sbc->translatable = 1;
881 sbc->message = xstrdup (tokstr);
884 sbc->restriction = NULL;
886 else if (match_id ("PINT"))
887 sbc->type = SBC_PINT;
888 else if (match_id ("DOUBLE"))
890 if ( match_id ("LIST") )
891 sbc->type = SBC_DBL_LIST;
895 else if (match_id ("STRING"))
897 sbc->type = SBC_STRING;
898 if (token == T_STRING)
900 sbc->restriction = xstrdup (tokstr);
903 sbc->message = xstrdup (tokstr);
907 sbc->restriction = NULL;
909 else if (match_id ("CUSTOM"))
910 sbc->type = SBC_CUSTOM;
912 parse_specifiers (sbc);
916 /* Parse all the subcommands. */
918 parse_subcommands (void)
920 subcommand **sbc = &subcommands;
924 *sbc = xmalloc (sizeof **sbc);
927 parse_subcommand (*sbc);
939 #define BASE_INDENT 2 /* Starting indent. */
940 #define INC_INDENT 2 /* Indent increment. */
942 /* Increment the indent. */
943 #define indent() indent += INC_INDENT
944 #define outdent() indent -= INC_INDENT
946 /* Size of the indent from the left margin. */
949 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
951 /* Write line FORMAT to the output file, formatted as with printf,
952 indented `indent' characters from the left margin. If INDENTION is
953 greater than 0, indents BASE_INDENT * INDENTION characters after
954 writing the line; if INDENTION is less than 0, dedents BASE_INDENT
955 * INDENTION characters _before_ writing the line. */
957 dump (int indention, const char *format, ...)
963 indent += BASE_INDENT * indention;
966 va_start (args, format);
967 for (i = 0; i < indent; i++)
969 vfprintf (out, format, args);
974 indent += BASE_INDENT * indention;
977 /* Write the structure members for specifier SPEC to the output file.
978 SBC is the including subcommand. */
980 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
983 dump (0, "long %s%s;", sbc->prefix, spec->varname);
988 for (s = spec->s; s; s = s->next)
990 if (s->value != VAL_NONE)
992 const char *typename;
994 assert (s->value == VAL_INT || s->value == VAL_DBL
995 || s->value == VAL_STRING);
996 typename = (s->value == VAL_INT ? "long"
997 : s->value == VAL_DBL ? "double"
1000 dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
1006 /* Returns true if string T is a PSPP keyword, false otherwise. */
1008 is_keyword (const char *t)
1010 static const char *kw[] =
1012 "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
1013 "NE", "ALL", "BY", "TO", "WITH", 0,
1017 for (cp = kw; *cp; cp++)
1018 if (!strcmp (t, *cp))
1023 /* Transforms a string NAME into a valid C identifier: makes
1024 everything lowercase and maps nonalphabetic characters to
1025 underscores. Returns a pointer to a static buffer. */
1027 make_identifier (const char *name)
1029 char *p = get_buffer ();
1032 for (cp = p; *name; name++)
1033 if (isalpha ((unsigned char) *name))
1034 *cp++ = tolower ((unsigned char) (*name));
1042 /* Writes the struct and enum declarations for the parser. */
1044 dump_declarations (void)
1048 dump (0, "struct dataset;");
1050 /* Write out enums for all the identifiers in the symbol table. */
1056 /* Note the squirmings necessary to make sure that the last enum
1057 is not followed by a comma, as mandated by ANSI C89. */
1058 for (sym = symtab, f = k = 0; sym; sym = sym->next)
1059 if (!sym->unique && !is_keyword (sym->name))
1063 dump (0, "/* Settings for subcommand specifiers. */");
1070 buf = xmalloc (1024);
1075 sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1079 sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1084 buf[strlen (buf) - 1] = 0;
1095 /* Write out some type definitions */
1097 dump (0, "#define MAXLISTS 10");
1101 /* For every array subcommand, write out the associated enumerated
1106 for (sbc = subcommands; sbc; sbc = sbc->next)
1107 if (sbc->type == SBC_ARRAY && sbc->narray)
1109 dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1117 for (spec = sbc->spec; spec; spec = spec->next)
1118 dump (0, "%s%s%s = %d,",
1119 st_upper (prefix), st_upper (sbc->prefix),
1120 st_upper (spec->varname), spec->index);
1122 dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1130 /* Write out structure declaration. */
1134 dump (0, "/* %s structure. */", cmdname);
1135 dump (1, "struct cmd_%s", make_identifier (cmdname));
1137 for (sbc = subcommands; sbc; sbc = sbc->next)
1141 if (sbc != subcommands)
1144 dump (0, "/* %s subcommand. */", sbc->name);
1145 dump (0, "int sbc_%s;", st_lower (sbc->name));
1154 for (spec = sbc->spec; spec; spec = spec->next)
1158 if (sbc->type == SBC_PLAIN)
1159 dump (0, "long int %s%s;", st_lower (sbc->prefix),
1163 dump (0, "int a_%s[%s%scount];",
1164 st_lower (sbc->name),
1166 st_upper (sbc->prefix)
1173 dump_specifier_vars (spec, sbc);
1179 dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
1180 st_lower (sbc->name));
1181 dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix),
1182 st_lower (sbc->name));
1186 dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix),
1187 st_lower (sbc->name));
1191 dump (0, "char *s_%s;", st_lower (sbc->name));
1196 dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
1200 dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
1204 dump (0, "subc_list_double dl_%s[MAXLISTS];",
1205 st_lower(sbc->name));
1209 dump (0, "subc_list_int il_%s[MAXLISTS];",
1210 st_lower(sbc->name));
1223 /* Write out prototypes for custom_*() functions as necessary. */
1228 for (sbc = subcommands; sbc; sbc = sbc->next)
1229 if (sbc->type == SBC_CUSTOM)
1234 dump (0, "/* Prototype for custom subcommands of %s. */",
1237 dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1238 st_lower (prefix), st_lower (sbc->name),
1239 make_identifier (cmdname));
1246 /* Prototypes for parsing and freeing functions. */
1248 dump (0, "/* Command parsing functions. */");
1249 dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
1250 make_identifier (cmdname), make_identifier (cmdname));
1251 dump (0, "static void free_%s (struct cmd_%s *);",
1252 make_identifier (cmdname), make_identifier (cmdname));
1257 /* Writes out code to initialize all the variables that need
1258 initialization for particular specifier SPEC inside subcommand SBC. */
1260 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1268 st_upper (prefix), find_symbol (spec->def->con)->name);
1271 dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1277 for (s = spec->s; s; s = s->next)
1279 if (s->value != VAL_NONE)
1283 assert (s->value == VAL_INT || s->value == VAL_DBL
1284 || s->value == VAL_STRING);
1285 init = (s->value == VAL_INT ? "LONG_MIN"
1286 : s->value == VAL_DBL ? "SYSMIS"
1289 dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1295 /* Write code to initialize all variables. */
1297 dump_vars_init (int persistent)
1299 /* Loop through all the subcommands. */
1303 for (sbc = subcommands; sbc; sbc = sbc->next)
1307 dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1316 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1317 dump (0, "subc_list_%s_create(&p->%cl_%s[i]) ;",
1318 sbc->type == SBC_INT_LIST ? "int" : "double",
1319 sbc->type == SBC_INT_LIST ? 'i' : 'd',
1320 st_lower (sbc->name)
1328 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1329 dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
1342 for (spec = sbc->spec; spec; spec = spec->next)
1343 if (spec->s == NULL)
1345 if (sbc->type == SBC_PLAIN)
1346 dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1349 dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1350 st_lower (sbc->name), st_lower (sbc->name));
1355 dump_specifier_init (spec, sbc);
1360 dump (0, "p->%sn_%s = 0;",
1361 st_lower (sbc->prefix), st_lower (sbc->name));
1362 dump (0, "p->%sv_%s = NULL;",
1363 st_lower (sbc->prefix), st_lower (sbc->name));
1367 dump (0, "p->%sv_%s = NULL;",
1368 st_lower (sbc->prefix), st_lower (sbc->name));
1372 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1379 dump (1, "for (i = 0; i < MAXLISTS; ++i)");
1380 dump (0, "p->n_%s[i] = LONG_MIN;", st_lower (sbc->name));
1392 /* Return a pointer to a static buffer containing an expression that
1393 will match token T. */
1395 make_match (const char *t)
1405 sprintf (s, "lex_match (lexer, T_%s)", t);
1406 else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1407 strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") "
1408 "|| lex_match_id (lexer, \"TRUE\"))");
1409 else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1410 strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") "
1411 "|| lex_match_id (lexer, \"FALSE\"))");
1412 else if (isdigit ((unsigned char) t[0]))
1413 sprintf (s, "lex_match_int (lexer, %s)", t);
1416 char *c = unmunge (t);
1417 sprintf (s, "lex_match_hyphenated_word (lexer, \"%s\")", c);
1424 /* Write out the parsing code for specifier SPEC within subcommand
1427 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1431 if (spec->omit_kw && spec->omit_kw->next)
1432 error ("Omittable setting is not last setting in `%s' specifier.",
1434 if (spec->omit_kw && spec->omit_kw->parent->next)
1435 error ("Default specifier is not in last specifier in `%s' "
1436 "subcommand.", sbc->name);
1438 for (s = spec->s; s; s = s->next)
1440 int first = spec == sbc->spec && s == spec->s;
1442 /* Match the setting's keyword. */
1443 if (spec->omit_kw == s)
1450 dump (1, "%s;", make_match (s->specname));
1453 dump (1, "%sif (%s)", first ? "" : "else ",
1454 make_match (s->specname));
1457 /* Handle values. */
1458 if (s->value == VAL_NONE)
1459 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1460 st_upper (prefix), find_symbol (s->con)->name);
1463 if (spec->omit_kw != s)
1468 dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1469 st_upper (prefix), find_symbol (s->con)->name);
1471 if ( sbc->type == SBC_ARRAY )
1472 dump (0, "p->a_%s[%s%s%s] = 1;",
1473 st_lower (sbc->name),
1474 st_upper (prefix), st_upper (sbc->prefix),
1475 st_upper (spec->varname));
1479 if (s->valtype == VT_PAREN)
1483 dump (1, "if (lex_match (lexer, '('))");
1488 dump (1, "if (!lex_match (lexer, '('))");
1490 dump (0, "msg (SE, _(\"`(' expected after %s "
1491 "specifier of %s subcommand.\"));",
1492 s->specname, sbc->name);
1493 dump (0, "goto lossage;");
1499 if (s->value == VAL_INT)
1501 dump (1, "if (!lex_is_integer (lexer))");
1503 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1504 "requires an integer argument.\"));",
1505 s->specname, sbc->name);
1506 dump (0, "goto lossage;");
1508 dump (-1, "p->%s%s = lex_integer (lexer);",
1509 sbc->prefix, st_lower (s->valname));
1511 else if (s->value == VAL_DBL)
1513 dump (1, "if (!lex_is_number (lexer))");
1515 dump (0, "msg (SE, _(\"Number expected after %s "
1516 "specifier of %s subcommand.\"));",
1517 s->specname, sbc->name);
1518 dump (0, "goto lossage;");
1520 dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
1521 st_lower (s->valname));
1523 else if (s->value == VAL_STRING)
1525 dump (1, "if (lex_token (lexer) != T_ID "
1526 "&& lex_token (lexer) != T_STRING)");
1528 dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1529 "requires a string argument.\"));",
1530 s->specname, sbc->name);
1531 dump (0, "goto lossage;");
1533 dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
1534 dump (0, "p->%s%s = xstrdup (ds_cstr (lex_tokstr (lexer)));",
1535 sbc->prefix, st_lower (s->valname));
1544 str = xmalloc (MAX_TOK_LEN);
1545 str2 = xmalloc (MAX_TOK_LEN);
1546 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1547 sprintf (str, s->restriction, str2, str2, str2, str2,
1548 str2, str2, str2, str2);
1549 dump (1, "if (!(%s))", str);
1555 dump (0, "msg (SE, _(\"Bad argument for %s "
1556 "specifier of %s subcommand.\"));",
1557 s->specname, sbc->name);
1558 dump (0, "goto lossage;");
1563 dump (0, "lex_get (lexer);");
1565 if (s->valtype == VT_PAREN)
1567 dump (1, "if (!lex_match (lexer, ')'))");
1569 dump (0, "msg (SE, _(\"`)' expected after argument for "
1570 "%s specifier of %s.\"));",
1571 s->specname, sbc->name);
1572 dump (0, "goto lossage;");
1582 if (s != spec->omit_kw)
1586 if (s == spec->omit_kw)
1595 /* Write out the code to parse subcommand SBC. */
1597 dump_subcommand (const subcommand *sbc)
1599 if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1603 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1609 for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1612 dump_specifier_parse (spec, sbc);
1616 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1617 make_match (st_upper (spec->varname)));
1618 if (sbc->type == SBC_PLAIN)
1619 dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1622 dump (0, "p->a_%s[%s%s%s] = 1;",
1623 st_lower (sbc->name),
1624 st_upper (prefix), st_upper (sbc->prefix),
1625 st_upper (spec->varname));
1635 /* This code first finds the last specifier in sbc. Then it
1636 finds the last setting within that last specifier. Either
1637 or both might be NULL. */
1650 if (spec && (!spec->s || !spec->omit_kw))
1654 dump (0, "lex_error (lexer, NULL);");
1655 dump (0, "goto lossage;");
1661 dump (0, "lex_match (lexer, ',');");
1665 else if (sbc->type == SBC_VARLIST)
1667 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1669 st_lower (sbc->prefix), st_lower (sbc->name),
1670 st_lower (sbc->prefix), st_lower (sbc->name),
1671 sbc->message ? " |" : "",
1672 sbc->message ? sbc->message : "");
1673 dump (0, "goto lossage;");
1676 else if (sbc->type == SBC_VAR)
1678 dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));",
1679 st_lower (sbc->prefix), st_lower (sbc->name));
1680 dump (1, "if (!p->%sv_%s)",
1681 st_lower (sbc->prefix), st_lower (sbc->name));
1682 dump (0, "goto lossage;");
1685 else if (sbc->type == SBC_STRING)
1687 if (sbc->restriction)
1692 dump (1, "if (!lex_force_string (lexer))");
1693 dump (0, "return false;");
1695 if (sbc->restriction)
1697 dump (0, "x = ds_length (lex_tokstr (lexer));");
1698 dump (1, "if (!(%s))", sbc->restriction);
1700 dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1701 sbc->name, sbc->message);
1702 dump (0, "goto lossage;");
1706 dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1707 dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));",
1708 st_lower (sbc->name));
1709 dump (0, "lex_get (lexer);");
1710 if (sbc->restriction)
1713 else if (sbc->type == SBC_DBL)
1715 dump (1, "if (!lex_force_num (lexer))");
1716 dump (0, "goto lossage;");
1717 dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);",
1718 st_lower (sbc->name), st_lower (sbc->name) );
1719 dump (0, "lex_get(lexer);");
1721 else if (sbc->type == SBC_INT)
1725 dump (1, "if (!lex_force_int (lexer))");
1726 dump (0, "goto lossage;");
1727 dump (-1, "x = lex_integer (lexer);");
1728 dump (0, "lex_get(lexer);");
1729 if (sbc->restriction)
1732 dump (1, "if (!(%s))", sbc->restriction);
1734 sprintf(buf,sbc->message,sbc->name);
1735 if ( sbc->translatable )
1736 dump (0, "msg (SE, gettext(\"%s\"));",buf);
1738 dump (0, "msg (SE, \"%s\");",buf);
1739 dump (0, "goto lossage;");
1742 dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
1745 else if (sbc->type == SBC_PINT)
1747 dump (0, "lex_match (lexer, '(');");
1748 dump (1, "if (!lex_force_int (lexer))");
1749 dump (0, "goto lossage;");
1750 dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
1751 dump (0, "lex_match (lexer, ')');");
1753 else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST)
1755 dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
1757 dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
1758 dump (0, "goto lossage;");
1761 dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
1763 dump (0, "lex_match (lexer, ',');");
1764 dump (0, "if (!lex_force_num (lexer))");
1766 dump (0, "goto lossage;");
1769 dump (0, "subc_list_%s_push (&p->%cl_%s[p->sbc_%s-1], lex_number (lexer));",
1770 sbc->type == SBC_INT_LIST ? "int" : "double",
1771 sbc->type == SBC_INT_LIST ? 'i' : 'd',
1772 st_lower (sbc->name), st_lower (sbc->name));
1774 dump (0, "lex_get (lexer);");
1778 else if (sbc->type == SBC_CUSTOM)
1780 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1781 st_lower (prefix), st_lower (sbc->name));
1783 dump (1, "case 0:");
1784 dump (0, "goto lossage;");
1785 dump (-1, "case 1:");
1788 dump (-1, "case 2:");
1790 dump (0, "lex_error (lexer, NULL);");
1791 dump (0, "goto lossage;");
1792 dump (-1, "default:");
1794 dump (0, "NOT_REACHED ();");
1800 /* Write out entire parser. */
1802 dump_parser (int persistent)
1808 dump (0, "static int");
1809 dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)",
1810 make_identifier (cmdname),
1811 (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED",
1812 make_identifier (cmdname));
1815 dump_vars_init (persistent);
1817 dump (1, "for (;;)");
1821 if (def && (def->type == SBC_VARLIST))
1823 if (def->type == SBC_VARLIST)
1824 dump (1, "if (lex_token (lexer) == T_ID "
1825 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL "
1826 "&& lex_look_ahead (lexer) != '=')");
1829 dump (0, "if ((lex_token (lexer) == T_ID "
1830 "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) "
1831 "&& lex_look_ahead () != '=')");
1832 dump (1, " || token == T_ALL)");
1835 dump (0, "p->sbc_%s++;", st_lower (def->name));
1836 dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
1838 st_lower (def->prefix), st_lower (def->name),
1839 st_lower (def->prefix), st_lower (def->name));
1840 dump (0, "goto lossage;");
1845 else if (def && def->type == SBC_CUSTOM)
1847 dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
1848 st_lower (prefix), st_lower (def->name));
1850 dump (1, "case 0:");
1851 dump (0, "goto lossage;");
1852 dump (-1, "case 1:");
1854 dump (0, "p->sbc_%s++;", st_lower (def->name));
1855 dump (0, "continue;");
1856 dump (-1, "case 2:");
1859 dump (-1, "default:");
1861 dump (0, "NOT_REACHED ();");
1869 for (sbc = subcommands; sbc; sbc = sbc->next)
1871 dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1875 dump (0, "lex_match (lexer, '=');");
1876 dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1877 if (sbc->arity != ARITY_MANY)
1879 dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1881 dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1883 dump (0, "goto lossage;");
1887 dump_subcommand (sbc);
1894 /* Now deal with the /ALGORITHM subcommand implicit to all commands */
1895 dump(1,"else if ( settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
1898 dump (0, "lex_match (lexer, '=');");
1900 dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
1901 dump(0,"settings_set_cmd_algorithm (COMPATIBLE);");
1903 dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))");
1904 dump(0,"settings_set_cmd_algorithm (ENHANCED);");
1911 dump (1, "if (!lex_match (lexer, '/'))");
1916 dump (1, "if (lex_token (lexer) != '.')");
1918 dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
1919 dump (0, "goto lossage;");
1926 /* Check that mandatory subcommands have been specified */
1929 for (sbc = subcommands; sbc; sbc = sbc->next)
1932 if ( sbc->arity == ARITY_ONCE_EXACTLY )
1934 dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
1936 dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
1938 dump (0, "goto lossage;");
1945 dump (-1, "return true;");
1947 dump (-1, "lossage:");
1949 dump (0, "free_%s (p);", make_identifier (cmdname));
1950 dump (0, "return false;");
1956 /* Write the output file header. */
1961 dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1963 dump (0, " Generated by q2c from %s.", ifn);
1964 dump (0, " Do not modify!");
1968 /* Write out commands to free variable state. */
1970 dump_free (int persistent)
1980 for (sbc = subcommands; sbc; sbc = sbc->next)
1981 used = (sbc->type == SBC_STRING
1982 || sbc->type == SBC_DBL_LIST
1983 || sbc->type == SBC_INT_LIST);
1986 dump (0, "static void");
1987 dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1988 make_identifier (cmdname), used ? "" : " UNUSED");
1994 for (sbc = subcommands; sbc; sbc = sbc->next)
1999 dump (0, "free (p->v_%s);", st_lower (sbc->name));
2002 dump (0, "free (p->s_%s);", st_lower (sbc->name));
2008 dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
2009 dump (1, "subc_list_%s_destroy(&p->%cl_%s[i]);",
2010 sbc->type == SBC_INT_LIST ? "int" : "double",
2011 sbc->type == SBC_INT_LIST ? 'i' : 'd',
2012 st_lower (sbc->name));
2021 for (spec = sbc->spec; spec; spec = spec->next)
2022 for (s = spec->s; s; s = s->next)
2023 if (s->value == VAL_STRING)
2024 dump (0, "free (p->%s%s);",
2025 sbc->prefix, st_lower (s->valname));
2039 /* Returns the name of a directive found on the current input line, if
2040 any, or a null pointer if none found. */
2042 recognize_directive (void)
2044 static char directive[16];
2048 if (strncmp (sp, "/*", 2))
2050 sp = skip_ws (sp + 2);
2055 ep = strchr (sp, ')');
2061 memcpy (directive, sp, ep - sp);
2062 directive[ep - sp] = '\0';
2067 main (int argc, char *argv[])
2069 program_name = argv[0];
2071 fail ("Syntax: q2c input.q output.c");
2074 in = fopen (ifn, "r");
2076 fail ("%s: open: %s.", ifn, strerror (errno));
2079 out = fopen (ofn, "w");
2081 fail ("%s: open: %s.", ofn, strerror (errno));
2084 buf = xmalloc (MAX_LINE_LEN);
2085 tokstr = xmalloc (MAX_TOK_LEN);
2091 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2094 const char *directive = recognize_directive ();
2095 if (directive == NULL)
2097 dump (0, "%s", buf);
2101 dump (0, "#line %d \"%s\"", oln + 1, ofn);
2102 if (!strcmp (directive, "specification"))
2104 /* Skip leading slash-star line. */
2110 /* Skip trailing star-slash line. */
2113 else if (!strcmp (directive, "headers"))
2117 dump (0, "#include <stdlib.h>");
2118 dump (0, "#include <libpspp/assertion.h>");
2119 dump (0, "#include <libpspp/message.h>");
2120 dump (0, "#include <language/lexer/lexer.h>");
2121 dump (0, "#include <language/lexer/variable-parser.h>");
2122 dump (0, "#include <data/settings.h>");
2123 dump (0, "#include <libpspp/str.h>");
2124 dump (0, "#include <language/lexer/subcommand-list.h>");
2125 dump (0, "#include <data/variable.h>");
2128 dump (0, "#include \"xalloc.h\"");
2131 dump (0, "#include \"gettext.h\"");
2132 dump (0, "#define _(msgid) gettext (msgid)");
2135 else if (!strcmp (directive, "declarations"))
2136 dump_declarations ();
2137 else if (!strcmp (directive, "functions"))
2142 else if (!strcmp (directive, "_functions"))
2148 error ("unknown directive `%s'", directive);
2150 dump (0, "#line %d \"%s\"", ln + 1, ifn);
2153 return EXIT_SUCCESS;