Implemented the SHOW command and massaged the SET command to fit
[pspp-builds.git] / src / q2c.c
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>.
4
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.
9
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.
14
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., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <time.h>
27 #include <errno.h>
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include "str.h"
32
33 /* Brokenness. */
34 #ifndef EXIT_SUCCESS
35 #define EXIT_SUCCESS 0
36 #endif
37
38 #ifndef EXIT_FAILURE
39 #define EXIT_FAILURE 1
40 #endif
41
42 #if !HAVE_STRERROR
43 #include "misc/strerror.c"
44 #endif
45      
46 #include "debug-print.h"
47
48 /* Max length of an input line. */
49 #define MAX_LINE_LEN 1024
50
51 /* Max token length. */
52 #define MAX_TOK_LEN 1024
53
54 /* argv[0]. */
55 char *pgmname;
56
57 /* Have the input and output files been opened yet? */
58 int is_open;
59
60 /* Input, output files. */
61 FILE *in, *out;
62
63 /* Input, output file names. */
64 char *ifn, *ofn;
65
66 /* Input, output file line number. */
67 int ln, oln = 1;
68
69 /* Input line buffer, current position. */
70 char *buf, *cp;
71
72 /* Token types. */
73 enum
74   {
75     T_STRING = 256,     /* String literal. */
76     T_ID = 257          /* Identifier.  */
77   };
78
79 /* Current token: either one of the above, or a single character. */
80 int token;
81
82 /* Token string value. */
83 char *tokstr;
84 \f
85 /* Utility functions. */
86
87 char nullstr[] = "";
88
89 /* Close all open files and delete the output file, on failure. */
90 static void
91 finish_up (void)
92 {
93   if (!is_open)
94     return;
95   is_open = 0;
96   fclose (in);
97   fclose (out);
98   if (remove (ofn) == -1)
99     fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
100 }
101
102 void hcf (void) NO_RETURN;
103
104 /* Terminate unsuccessfully. */
105 void
106 hcf (void)
107 {
108   finish_up ();
109   exit (EXIT_FAILURE);
110 }
111
112 int fail (const char *, ...) PRINTF_FORMAT (1, 2);
113 int error (const char *, ...) PRINTF_FORMAT (1, 2);
114
115 /* Output an error message and terminate unsuccessfully. */
116 int
117 fail (const char *format, ...)
118 {
119   va_list args;
120
121   va_start (args, format);
122   fprintf (stderr, "%s: ", pgmname);
123   vfprintf (stderr, format, args);
124   fprintf (stderr, "\n");
125   va_end (args);
126
127   hcf ();
128 }
129
130 /* Output a context-dependent error message and terminate
131    unsuccessfully. */
132 int
133 error (const char *format,...)
134 {
135   va_list args;
136
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");
141   va_end (args);
142
143   hcf ();
144 }
145
146 #define VME "virtual memory exhausted"
147
148 /* Allocate a block of SIZE bytes and return a pointer to its
149    beginning. */
150 static void *
151 xmalloc (size_t size)
152 {
153   void *vp;
154   
155   if (size == 0)
156     return NULL;
157   
158   vp = malloc (size);
159   if (!vp)
160     fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
161   
162   return vp;
163 }
164
165 /* Make a dynamically allocated copy of string S and return a pointer
166    to the first character. */
167 static char *
168 xstrdup (const char *s)
169 {
170   size_t size;
171   char *t;
172
173   assert (s != NULL);
174   size = strlen (s) + 1;
175   
176   t = malloc (size);
177   if (!t)
178     fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
179     
180   memcpy (t, s, size);
181   return t;
182 }
183
184 /* Returns a pointer to one of 8 static buffers.  The buffers are used
185    in rotation. */
186 static char *
187 get_buffer (void)
188 {
189   static char b[8][256];
190   static int cb;
191
192   if (++cb >= 8)
193     cb = 0;
194   
195   return b[cb];
196 }
197    
198 /* Copies a string to a static buffer, converting it to lowercase in
199    the process, and returns a pointer to the static buffer. */
200 static char *
201 st_lower (const char *s)
202 {
203   char *p, *cp;
204   
205   p = cp = get_buffer ();
206   while (*s)
207     *cp++ = tolower ((unsigned char) (*s++));
208   *cp++ = '\0';
209   
210   return p;
211 }
212
213 /* Copies a string to a static buffer, converting it to uppercase in
214    the process, and returns a pointer to the static buffer. */
215 static char *
216 st_upper (const char *s)
217 {
218   char *p, *cp;
219
220   p = cp = get_buffer ();
221   while (*s)
222     *cp++ = toupper ((unsigned char) (*s++));
223   *cp++ = '\0';
224   
225   return p;
226 }
227
228 /* Returns the address of the first non-whitespace character in S, or
229    the address of the null terminator if none. */
230 static char *
231 skip_ws (const char *s)
232 {
233   while (isspace ((unsigned char) *s))
234     s++;
235   return (char *) s;
236 }
237
238 /* Read one line from the input file into buf.  Lines having special
239    formats are handled specially. */
240 static int
241 get_line (void)
242 {
243   ln++;
244   if (0 == fgets (buf, MAX_LINE_LEN, in))
245     {
246       if (ferror (in))
247         fail ("%s: fgets: %s", ifn, strerror (errno));
248       return 0;
249     }
250
251   cp = strchr (buf, '\n');
252   if (cp != NULL)
253     *cp = '\0';
254
255   cp = buf;
256   return 1;
257 }
258 \f
259 /* Symbol table manager. */
260
261 /* Symbol table entry. */
262 typedef struct symbol symbol;
263 struct symbol
264   {
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. */
270   };
271
272 /* Symbol table. */
273 symbol *symtab;
274
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. */
280 static int
281 add_symbol (const char *name, int unique, int value)
282 {
283   symbol *iter, *sym;
284   int x;
285
286   sym = xmalloc (sizeof (symbol));
287   sym->name = xstrdup (name);
288   sym->unique = unique;
289   sym->value = value;
290   sym->next = NULL;
291   sym->ln = ln;
292   if (!symtab)
293     {
294       symtab = sym;
295       return 1;
296     }
297   iter = symtab;
298   x = 1;
299   for (;;)
300     {
301       if (!strcmp (iter->name, name))
302         {
303           if (iter->unique)
304             {
305               fprintf (stderr, "%s:%d: `%s' is already defined above\n", ifn,
306                        ln, name);
307               fprintf (stderr, "%s:%d: location of previous definition\n", ifn,
308                        iter->ln);
309               hcf ();
310             }
311           free (sym->name);
312           free (sym);
313           return x;
314         }
315       if (!iter->next)
316         break;
317       iter = iter->next;
318       x++;
319     }
320   iter->next = sym;
321   return ++x;
322 }
323
324 /* Finds the symbol having given sequence number X within the symbol
325    table, and returns the associated symbol structure. */
326 static symbol *
327 find_symbol (int x)
328 {
329   symbol *iter;
330
331   iter = symtab;
332   while (x > 1 && iter)
333     {
334       iter = iter->next;
335       x--;
336     }
337   assert (iter);
338   return iter;
339 }
340
341 #if DEBUGGING 
342 /* Writes a printable representation of the current token to
343    stdout. */
344 void
345 dump_token (void)
346 {
347   switch (token)
348     {
349     case T_TSTRING:
350       printf ("TR_STRING\t\"%s\"\n", tokstr);
351       break;
352     case T_STRING:
353       printf ("STRING\t\"%s\"\n", tokstr);
354       break;
355     case T_ID:
356       printf ("ID\t%s\n", tokstr);
357       break;
358     default:
359       printf ("PUNCT\t%c\n", token);
360     }
361 }
362 #endif /* DEBUGGING */
363
364 /* Reads a token from the input file. */
365 static int
366 lex_get (void)
367 {
368   /* Skip whitespace and check for end of file. */
369   for (;;)
370     {
371       cp = skip_ws (cp);
372       if (*cp != '\0')
373         break;
374       
375       if (!get_line ())
376         fail ("%s: Unexpected end of file.", ifn);
377     }
378   
379   if (*cp == '"')
380     {
381       char *dest = tokstr;
382       token = T_STRING;
383       cp++;
384       while (*cp != '"' && *cp)
385         {
386           if (*cp == '\\')
387             {
388               cp++;
389               if (!*cp)
390                 error ("Unterminated string literal.");
391               *dest++ = *cp++;
392             }
393           else
394             *dest++ = *cp++;
395         }
396       *dest++ = 0;
397       if (!*cp)
398         error ("Unterminated string literal.");
399       cp++;
400     }
401   else if (*cp == '_' || isalnum ((unsigned char) *cp))
402     {
403       char *dest = tokstr;
404       token = T_ID;
405       while (*cp == '_' || isalnum ((unsigned char) *cp))
406         *dest++ = toupper ((unsigned char) (*cp++));
407       *dest++ = '\0';
408     }
409   else
410     token = *cp++;
411   
412 #if DEBUGGING
413   dump_token ();
414 #endif
415   
416   return token;
417 }
418
419 /* Force the current token to be an identifier token. */
420 static void
421 force_id (void)
422 {
423   if (token != T_ID)
424     error ("Identifier expected.");
425 }
426
427 /* Force the current token to be a string token. */
428 static void
429 force_string (void)
430 {
431   if (token != T_STRING)
432     error ("String expected.");
433 }
434
435 /* Checks whether the current token is the identifier S; if so, skips
436    the token and returns 1; otherwise, returns 0. */
437 static int
438 match_id (const char *s)
439 {
440   if (token == T_ID && !strcmp (tokstr, s))
441     {
442       lex_get ();
443       return 1;
444     }
445   return 0;
446 }
447
448 /* Checks whether the current token is T.  If so, skips the token and
449    returns 1; otherwise, returns 0. */
450 static int
451 match_token (int t)
452 {
453   if (token == t)
454     {
455       lex_get ();
456       return 1;
457     }
458   return 0;
459 }
460
461 /* Force the current token to be T, and skip it. */
462 static void
463 skip_token (int t)
464 {
465   if (token != t)
466     error ("`%c' expected.", t);
467   lex_get ();
468 }
469 \f
470 /* Structures. */
471
472 /* Some specifiers have associated values. */
473 enum
474   {
475     VAL_NONE,   /* No value. */
476     VAL_INT,    /* Integer value. */
477     VAL_DBL     /* Floating point value. */
478   };
479
480 /* For those specifiers with values, the syntax of those values. */
481 enum
482   {
483     VT_PLAIN,   /* Unadorned value. */
484     VT_PAREN    /* Value must be enclosed in parentheses. */
485   };
486
487 /* Forward definition. */
488 typedef struct specifier specifier;
489
490 /* A single setting. */
491 typedef struct setting setting;
492 struct setting
493   {
494     specifier *parent;  /* Owning specifier. */
495     setting *next;      /* Next in the chain. */
496     char *specname;     /* Name of the setting. */
497     int con;            /* Sequence number. */
498
499     /* Values. */
500     int valtype;        /* One of VT_*. */
501     int value;          /* One of VAL_*. */
502     int optvalue;       /* 1=value is optional, 0=value is required. */
503     char *valname;      /* Variable name for the value. */
504     char *restriction;  /* !=NULL: expression specifying valid values. */
505   };
506
507 /* A single specifier. */
508 struct specifier
509   {
510     specifier *next;    /* Next in the chain. */
511     char *varname;      /* Variable name. */
512     setting *s;         /* Associated settings. */
513
514     setting *def;       /* Default setting. */
515     setting *omit_kw;   /* Setting for which the keyword can be omitted. */
516     
517     int index;          /* Next array index. */
518   };
519
520 /* Subcommand types. */
521 typedef enum
522   {
523     SBC_PLAIN,          /* The usual case. */
524     SBC_VARLIST,        /* Variable list. */
525     SBC_INT,            /* Integer value. */
526     SBC_PINT,           /* Integer inside parentheses. */
527     SBC_DBL,            /* Floating point value. */
528     SBC_INT_LIST,       /* List of integers (?). */
529     SBC_DBL_LIST,       /* List of floating points (?). */
530     SBC_CUSTOM,         /* Custom. */
531     SBC_ARRAY,          /* Array of boolean values. */
532     SBC_STRING,         /* String value. */
533     SBC_VAR             /* Single variable name. */
534   }
535 subcommand_type;
536
537 /* A single subcommand. */
538 typedef struct subcommand subcommand;
539 struct subcommand
540   {
541     subcommand *next;           /* Next in the chain. */
542     char *name;                 /* Subcommand name. */
543     subcommand_type type;       /* One of SBC_*. */
544     int once;                   /* 1=Subcommand may appear only once. */
545     int narray;                 /* Index of next array element. */
546     const char *prefix;         /* Prefix for variable and constant names. */
547     specifier *spec;            /* Array of specifiers. */
548     
549     /* SBC_STRING and SBC_INT only. */
550     char *restriction;          /* Expression restricting string length. */
551     char *message;              /* Error message. */
552     int translatable;           /* Error message is translatable */
553   };
554
555 typedef struct aux_subcommand aux_subcommand;
556 struct aux_subcommand
557   {
558     aux_subcommand *next;       /* Next in the chain. */
559     char *name;                 /* Subcommand name. */
560     char *value;                /* Subcommand value */
561   };
562
563 static aux_subcommand *aux_subcommands ;
564
565 /* Name of the command; i.e., DESCRIPTIVES. */
566 char *cmdname;
567
568 /* Short prefix for the command; i.e., `dsc_'. */
569 char *prefix;
570
571 /* List of subcommands. */
572 subcommand *subcommands;
573
574 /* Default subcommand if any, or NULL. */
575 subcommand *def;
576 \f
577 /* Parsing. */
578
579 void parse_subcommands (void);
580
581 /* Parse an entire specification. */
582 static void
583 parse (void)
584 {
585   /* Get the command name and prefix. */
586   if (token != T_STRING && token != T_ID)
587     error ("Command name expected.");
588   cmdname = xstrdup (tokstr);
589   lex_get ();
590   skip_token ('(');
591   force_id ();
592   prefix = xstrdup (tokstr);
593   lex_get ();
594   skip_token (')');
595   skip_token (':');
596
597   /* Read all the subcommands. */
598   subcommands = NULL;
599   def = NULL;
600   parse_subcommands ();
601 }
602
603 /* Parses a single setting into S, given subcommand information SBC
604    and specifier information SPEC. */
605 static void
606 parse_setting (setting *s, specifier *spec)
607 {
608   s->parent = spec;
609   
610   if (match_token ('*'))
611     {
612       if (spec->omit_kw)
613         error ("Cannot have two settings with omittable keywords.");
614       else
615         spec->omit_kw = s;
616     }
617   
618   if (match_token ('!'))
619     {
620       if (spec->def)
621         error ("Cannot have two default settings.");
622       else
623         spec->def = s;
624     }
625   
626   force_id ();
627   s->specname = xstrdup (tokstr);
628   s->con = add_symbol (s->specname, 0, 0);
629   s->value = VAL_NONE;
630
631   lex_get ();
632
633   /* Parse setting value info if necessary. */
634   if (token != '/' && token != ';' && token != '.' && token != ',')
635     {
636       if (token == '(')
637         {
638           s->valtype = VT_PAREN;
639           lex_get ();
640         }
641       else
642         s->valtype = VT_PLAIN;
643
644       s->optvalue = match_token ('*');
645       
646       if (match_id ("N"))
647         s->value = VAL_INT;
648       else if (match_id ("D"))
649         s->value = VAL_DBL;
650       else
651         error ("`n' or `d' expected.");
652       
653       skip_token (':');
654       
655       force_id ();
656       s->valname = xstrdup (tokstr);
657       lex_get ();
658       
659       if (token == ',')
660         {
661           lex_get ();
662           force_string ();
663           s->restriction = xstrdup (tokstr);
664           lex_get ();
665         }
666       else
667         s->restriction = NULL;
668       
669       if (s->valtype == VT_PAREN)
670         skip_token (')');
671     }
672 }
673
674 /* Parse a single specifier into SPEC, given subcommand information
675    SBC. */
676 static void
677 parse_specifier (specifier *spec, subcommand *sbc)
678 {
679   spec->index = 0;
680   spec->s = NULL;
681   spec->def = NULL;
682   spec->omit_kw = NULL;
683   spec->varname = NULL;
684
685   if (token == T_ID)
686     {
687       spec->varname = xstrdup (st_lower (tokstr));
688       lex_get ();
689     }
690   
691   /* Handle array elements. */
692   if (token != ':')
693     {
694       spec->index = sbc->narray;
695       if (sbc->type == SBC_ARRAY)
696         {
697           if (token == '|')
698             token = ',';
699           else
700             sbc->narray++;
701         }
702       spec->s = NULL;
703       return;
704     }
705   skip_token (':');
706   
707   /* Parse all the settings. */
708   {
709     setting **s = &spec->s;
710     
711     for (;;)
712       {
713         *s = xmalloc (sizeof (setting));
714         parse_setting (*s, spec);
715         if (token == ',' || token == ';' || token == '.')
716           break;
717         skip_token ('/');
718         s = &(*s)->next;
719       }
720     (*s)->next = NULL;
721   }
722 }
723
724 /* Parse a list of specifiers for subcommand SBC. */
725 static void
726 parse_specifiers (subcommand *sbc)
727 {
728   specifier **spec = &sbc->spec;
729
730   if (token == ';' || token == '.')
731     {
732       *spec = NULL;
733       return;
734     }
735   
736   for (;;)
737     {
738       *spec = xmalloc (sizeof (specifier));
739       parse_specifier (*spec, sbc);
740       if (token == ';' || token == '.')
741         break;
742       skip_token (',');
743       spec = &(*spec)->next;
744     }
745   (*spec)->next = NULL;
746 }
747
748 /* Parse a subcommand into SBC. */
749 static void
750 parse_subcommand (subcommand *sbc)
751 {
752   if (match_token ('*'))
753     {
754       if (def)
755         error ("Multiple default subcommands.");
756       def = sbc;
757     }
758
759   sbc->once = match_token ('+');
760
761   force_id ();
762   sbc->name = xstrdup (tokstr);
763   lex_get ();
764   
765   sbc->narray = 0;
766   sbc->type = SBC_PLAIN;
767   sbc->spec = NULL;
768   sbc->translatable = 0;
769
770   if (match_token ('['))
771     {
772       force_id ();
773       sbc->prefix = xstrdup (st_lower (tokstr));
774       lex_get ();
775       
776       skip_token (']');
777       skip_token ('=');
778       
779       sbc->type = SBC_ARRAY;
780       parse_specifiers (sbc);
781     }
782   else
783     {
784       if (match_token ('('))
785         {
786           force_id ();
787           sbc->prefix = xstrdup (st_lower (tokstr));
788           lex_get ();
789           
790           skip_token (')');
791         }
792       else
793         sbc->prefix = "";
794       
795       skip_token ('=');
796
797       if (match_id ("VAR"))
798         sbc->type = SBC_VAR;
799       if (match_id ("VARLIST"))
800         {
801           if (match_token ('('))
802             {
803               force_string ();
804               sbc->message = xstrdup (tokstr);
805               lex_get();
806               
807               skip_token (')');
808             }
809           else sbc->message = NULL;
810
811           sbc->type = SBC_VARLIST;
812         }
813       else if (match_id ("INTEGER"))
814        {
815         sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
816         if ( token == T_STRING) 
817          {
818               sbc->restriction = xstrdup (tokstr);
819               lex_get ();
820               if ( match_id("N_") )
821                {
822                 skip_token('(');
823                 force_string ();
824                 lex_get();
825                 skip_token(')');
826                 sbc->translatable = 1;
827                }
828               else {
829                 force_string ();
830                 lex_get ();
831               }
832               sbc->message = xstrdup (tokstr);
833          }
834         else
835             sbc->restriction = NULL;
836        }
837       else if (match_id ("PINT"))
838         sbc->type = SBC_PINT;
839       else if (match_id ("DOUBLE"))
840         sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
841       else if (match_id ("STRING"))
842         {
843           sbc->type = SBC_STRING;
844           if (token == T_STRING)
845             {
846               sbc->restriction = xstrdup (tokstr);
847               lex_get ();
848               force_string ();
849               sbc->message = xstrdup (tokstr);
850               lex_get ();
851             }
852           else
853             sbc->restriction = NULL;
854         }
855       else if (match_id ("CUSTOM"))
856         sbc->type = SBC_CUSTOM;
857       else
858         parse_specifiers (sbc);
859     }
860 }
861
862 /* Parse all the subcommands. */
863 void
864 parse_subcommands (void)
865 {
866   subcommand **sbc = &subcommands;
867   
868   for (;;)
869     {
870       *sbc = xmalloc (sizeof (subcommand));
871       (*sbc)->next = NULL;
872
873       parse_subcommand (*sbc);
874
875       if (token == '.')
876         return;
877
878       skip_token (';');
879       sbc = &(*sbc)->next;
880     }
881 }
882 \f
883 /* Output. */
884
885 #define BASE_INDENT 2           /* Starting indent. */
886 #define INC_INDENT 2            /* Indent increment. */
887
888 /* Increment the indent. */
889 #define indent() indent += INC_INDENT
890 #define outdent() indent -= INC_INDENT
891
892 /* Size of the indent from the left margin. */
893 int indent;
894
895 void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
896
897 /* Write line FORMAT to the output file, formatted as with printf,
898    indented `indent' characters from the left margin.  If INDENTION is
899    greater than 0, indents BASE_INDENT * INDENTION characters after
900    writing the line; if INDENTION is less than 0, dedents BASE_INDENT
901    * INDENTION characters _before_ writing the line. */
902 void
903 dump (int indention, const char *format, ...)
904 {
905   va_list args;
906   int i;
907
908   if (indention < 0)
909     indent += BASE_INDENT * indention;
910   
911   oln++;
912   va_start (args, format);
913   for (i = 0; i < indent; i++)
914     putc (' ', out);
915   vfprintf (out, format, args);
916   putc ('\n', out);
917   va_end (args);
918
919   if (indention > 0)
920     indent += BASE_INDENT * indention;
921 }
922
923 /* Write the structure members for specifier SPEC to the output file.
924    SBC is the including subcommand. */
925 static void
926 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
927 {
928   if (spec->varname)
929     dump (0, "long %s%s;", sbc->prefix, spec->varname);
930   
931   {
932     setting *s;
933
934     for (s = spec->s; s; s = s->next)
935       {
936         if (s->value != VAL_NONE)
937           {
938             const char *typename;
939
940             assert (s->value == VAL_INT || s->value == VAL_DBL);
941             typename = s->value == VAL_INT ? "long" : "double";
942
943             dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
944           }
945       }
946   }
947 }
948
949 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
950 static int
951 is_keyword (const char *t)
952 {
953   static const char *kw[] =
954     {
955       "AND", "OR", "NOT", "EQ", "GE", "GT", "LE", "LT",
956       "NE", "ALL", "BY", "TO", "WITH", 0,
957     };
958   const char **cp;
959
960   for (cp = kw; *cp; cp++)
961     if (!strcmp (t, *cp))
962       return 1;
963   return 0;
964 }
965
966 /* Transforms a string NAME into a valid C identifier: makes
967    everything lowercase and maps nonalphabetic characters to
968    underscores.  Returns a pointer to a static buffer. */
969 static char *
970 make_identifier (const char *name)
971 {
972   char *p = get_buffer ();
973   char *cp;
974
975   for (cp = p; *name; name++)
976     if (isalpha ((unsigned char) *name))
977       *cp++ = tolower ((unsigned char) (*name));
978     else
979       *cp++ = '_';
980   *cp = '\0';
981   
982   return p;
983 }
984
985 /* Writes the struct and enum declarations for the parser. */
986 static void
987 dump_declarations (void)
988 {
989   indent = 0;
990
991   /* Write out enums for all the identifiers in the symbol table. */
992   {
993     int f, k;
994     symbol *sym;
995     char *buf = NULL;
996
997     /* Note the squirmings necessary to make sure that the last enum
998        is not followed by a comma, as mandated by ANSI C89. */
999     for (sym = symtab, f = k = 0; sym; sym = sym->next)
1000       if (!sym->unique && !is_keyword (sym->name))
1001         {
1002           if (!f)
1003             {
1004               dump (0, "/* Settings for subcommand specifiers. */");
1005               dump (1, "enum");
1006               dump (1, "{");
1007               f = 1;
1008             }
1009
1010           if (buf == NULL)
1011             buf = xmalloc (1024);
1012           else
1013             dump (0, buf);
1014           
1015           if (k)
1016             sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
1017           else
1018             {
1019               k = 1;
1020               sprintf (buf, "%s%s = 1000,", st_upper (prefix), sym->name);
1021             }
1022         }
1023     if (buf)
1024       {
1025         buf[strlen (buf) - 1] = 0;
1026         dump (0, buf);
1027         free (buf);
1028       }
1029     if (f)
1030       {
1031         dump (-1, "};");
1032         dump (-1, nullstr);
1033       }
1034   }
1035
1036   /* For every array subcommand, write out the associated enumerated
1037      values. */
1038   {
1039     subcommand *sbc;
1040
1041     for (sbc = subcommands; sbc; sbc = sbc->next)
1042       if (sbc->type == SBC_ARRAY && sbc->narray)
1043         {
1044           dump (0, "/* Array indices for %s subcommand. */", sbc->name);
1045           
1046           dump (1, "enum");
1047           dump (1, "{");
1048
1049           {
1050             specifier *spec;
1051
1052             for (spec = sbc->spec; spec; spec = spec->next)
1053               if (!spec->s)
1054                 dump (0, "%s%s%s = %d,",
1055                       st_upper (prefix), st_upper (sbc->prefix),
1056                       st_upper (spec->varname), spec->index);
1057
1058             dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
1059
1060             dump (-1, "};");
1061             dump (-1, nullstr);
1062           }
1063         }
1064   }
1065
1066   /* Write out structure declaration. */
1067   {
1068     subcommand *sbc;
1069
1070     dump (0, "/* %s structure. */", cmdname);
1071     dump (1, "struct cmd_%s", make_identifier (cmdname));
1072     dump (1, "{");
1073     for (sbc = subcommands; sbc; sbc = sbc->next)
1074       {
1075         int f = 0;
1076
1077         if (sbc != subcommands)
1078           dump (0, nullstr);
1079         
1080         dump (0, "/* %s subcommand. */", sbc->name);
1081         dump (0, "int sbc_%s;", st_lower (sbc->name));
1082
1083         switch (sbc->type)
1084           {
1085           case SBC_ARRAY:
1086           case SBC_PLAIN:
1087             {
1088               specifier *spec;
1089             
1090               for (spec = sbc->spec; spec; spec = spec->next)
1091                 {
1092                   if (spec->s == 0)
1093                     {
1094                       if (sbc->type == SBC_PLAIN)
1095                         dump (0, "long int %s%s;", st_lower (sbc->prefix),
1096                               spec->varname);
1097                       else if (f == 0)
1098                         {
1099                           dump (0, "int a_%s[%d];", 
1100                                 st_lower (sbc->name), sbc->narray);
1101                           f = 1;
1102                         }
1103                     }
1104                   else
1105                     dump_specifier_vars (spec, sbc);
1106                 }
1107             }
1108             break;
1109
1110           case SBC_VARLIST:
1111             dump (0, "int %sn_%s;", st_lower (sbc->prefix),
1112                   st_lower (sbc->name));
1113             dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
1114                   st_lower (sbc->name));
1115             break;
1116
1117           case SBC_VAR:
1118             dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
1119                   st_lower (sbc->name));
1120             break;
1121
1122           case SBC_STRING:
1123             dump (0, "char *s_%s;", st_lower (sbc->name));
1124             break;
1125
1126           case SBC_INT:
1127           case SBC_PINT:
1128             dump (0, "long n_%s;", st_lower (sbc->name));
1129             break;
1130
1131           case SBC_DBL:
1132             dump (0, "double n_%s;", st_lower (sbc->name));
1133             break;
1134
1135           default:;
1136             /* nothing */
1137           }
1138       }
1139
1140     dump (-1, "};");
1141     dump (-1, nullstr);
1142   }
1143
1144   /* Write out prototypes for custom_*() functions as necessary. */
1145   {
1146     int seen = 0;
1147     subcommand *sbc;
1148
1149     for (sbc = subcommands; sbc; sbc = sbc->next)
1150       if (sbc->type == SBC_CUSTOM)
1151         {
1152           if (!seen)
1153             {
1154               seen = 1;
1155               dump (0, "/* Prototype for custom subcommands of %s. */",
1156                     cmdname);
1157             }
1158           dump (0, "static int %scustom_%s (struct cmd_%s *);",
1159                 st_lower (prefix), st_lower (sbc->name),
1160                 make_identifier (cmdname));
1161         }
1162
1163     if (seen)
1164       dump (0, nullstr);
1165   }
1166
1167   /* Prototypes for parsing and freeing functions. */
1168   {
1169     dump (0, "/* Command parsing functions. */");
1170     dump (0, "static int parse_%s (struct cmd_%s *);",
1171           make_identifier (cmdname), make_identifier (cmdname));
1172     dump (0, "static void free_%s (struct cmd_%s *);",
1173           make_identifier (cmdname), make_identifier (cmdname));
1174     dump (0, nullstr);
1175   }
1176 }
1177
1178 /* Writes out code to initialize all the variables that need
1179    initialization for particular specifier SPEC inside subcommand SBC. */
1180 static void
1181 dump_specifier_init (const specifier *spec, const subcommand *sbc)
1182 {
1183   if (spec->varname)
1184     {
1185       char s[256];
1186
1187       if (spec->def)
1188         sprintf (s, "%s%s",
1189                  st_upper (prefix), find_symbol (spec->def->con)->name);
1190       else
1191         strcpy (s, "-1");
1192       dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
1193     }
1194   
1195   {
1196     setting *s;
1197
1198     for (s = spec->s; s; s = s->next)
1199       {
1200         if (s->value != VAL_NONE)
1201           {
1202             const char *init;
1203
1204             assert (s->value == VAL_INT || s->value == VAL_DBL);
1205             init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
1206
1207             dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
1208           }
1209       }
1210   }
1211 }
1212
1213 /* Write code to initialize all variables. */
1214 static void
1215 dump_vars_init (int persistent)
1216 {
1217   /* Loop through all the subcommands. */
1218   {
1219     subcommand *sbc;
1220     
1221     for (sbc = subcommands; sbc; sbc = sbc->next)
1222       {
1223         int f = 0;
1224         
1225         dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
1226         if ( ! persistent ) 
1227           {
1228             switch (sbc->type)
1229               {
1230               case SBC_DBL:
1231               case SBC_INT_LIST:
1232               case SBC_DBL_LIST:
1233               case SBC_CUSTOM:
1234                 /* nothing */
1235                 break;
1236             
1237               case SBC_PLAIN:
1238               case SBC_ARRAY:
1239                 {
1240                   specifier *spec;
1241             
1242                   for (spec = sbc->spec; spec; spec = spec->next)
1243                     if (spec->s == NULL)
1244                       {
1245                         if (sbc->type == SBC_PLAIN)
1246                           dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
1247                         else if (f == 0)
1248                           {
1249                             dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
1250                                   st_lower (sbc->name), st_lower (sbc->name));
1251                             f = 1;
1252                           }
1253                       }
1254                     else
1255                       dump_specifier_init (spec, sbc);
1256                 }
1257                 break;
1258
1259               case SBC_VARLIST:
1260                 dump (0, "p->%sn_%s = 0;",
1261                       st_lower (sbc->prefix), st_lower (sbc->name));
1262                 dump (0, "p->%sv_%s = NULL;",
1263                       st_lower (sbc->prefix), st_lower (sbc->name));
1264                 break;
1265             
1266               case SBC_VAR:
1267                 dump (0, "p->%sv_%s = NULL;",
1268                       st_lower (sbc->prefix), st_lower (sbc->name));
1269                 break;
1270
1271               case SBC_STRING:
1272                 dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
1273                 break;
1274
1275               case SBC_INT:
1276               case SBC_PINT:
1277                 dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
1278                 break;
1279
1280               default:
1281                 assert (0);
1282               }
1283           }
1284       }
1285   }
1286 }
1287
1288 /* Return a pointer to a static buffer containing an expression that
1289    will match token T. */
1290 static char *
1291 make_match (const char *t)
1292 {
1293   char *s;
1294
1295   s = get_buffer ();
1296
1297   while (*t == '_')
1298     t++;
1299       
1300   if (is_keyword (t))
1301     sprintf (s, "lex_match (T_%s)", t);
1302   else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
1303     strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
1304             "|| lex_match_id (\"TRUE\"))");
1305   else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
1306     strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
1307             "|| lex_match_id (\"FALSE\"))");
1308   else if (isdigit ((unsigned char) t[0]))
1309     sprintf (s, "lex_match_int (%s)", t);
1310   else
1311     sprintf (s, "lex_match_id (\"%s\")", t);
1312   
1313   return s;
1314 }
1315
1316 /* Write out the parsing code for specifier SPEC within subcommand
1317    SBC. */
1318 static void
1319 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
1320 {
1321   setting *s;
1322
1323   if (spec->omit_kw && spec->omit_kw->next)
1324     error ("Omittable setting is not last setting in `%s' specifier.",
1325            spec->varname);
1326   if (spec->omit_kw && spec->omit_kw->parent->next)
1327     error ("Default specifier is not in last specifier in `%s' "
1328            "subcommand.", sbc->name);
1329   
1330   for (s = spec->s; s; s = s->next)
1331     {
1332       int first = spec == sbc->spec && s == spec->s;
1333
1334       /* Match the setting's keyword. */
1335       if (spec->omit_kw == s)
1336         {
1337           if (!first)
1338             {
1339               dump (1, "else");
1340               dump (1, "{");
1341             }
1342           dump (1, "%s;", make_match (s->specname));
1343         }
1344       else
1345         dump (1, "%sif (%s)", first ? "" : "else ",
1346               make_match (s->specname));
1347
1348       /* Handle values. */
1349       if (s->value == VAL_NONE)
1350         dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1351               st_upper (prefix), find_symbol (s->con)->name);
1352       else
1353         {
1354           if (spec->omit_kw != s)
1355             dump (1, "{");
1356           
1357           if (spec->varname)
1358             dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
1359                   st_upper (prefix), find_symbol (s->con)->name);
1360           
1361           if (s->valtype == VT_PAREN)
1362             {
1363               if (s->optvalue)
1364                 {
1365                   dump (1, "if (lex_match ('('))");
1366                   dump (1, "{");
1367                 }
1368               else
1369                 {
1370                   dump (1, "if (!lex_match ('('))");
1371                   dump (1, "{");
1372                   dump (0, "msg (SE, _(\"`(' expected after %s "
1373                         "specifier of %s subcommand.\"));",
1374                         s->specname, sbc->name);
1375                   dump (0, "goto lossage;");
1376                   dump (-1, "}");
1377                   outdent ();
1378                 }
1379             }
1380
1381           if (s->value == VAL_INT)
1382             {
1383               dump (1, "if (!lex_integer_p ())");
1384               dump (1, "{");
1385               dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
1386                     "requires an integer argument.\"));",
1387                     s->specname, sbc->name);
1388               dump (0, "goto lossage;");
1389               dump (-1, "}");
1390               dump (-1, "p->%s%s = lex_integer ();",
1391                     sbc->prefix, st_lower (s->valname));
1392             }
1393           else
1394             {
1395               dump (1, "if (token != T_NUM)");
1396               dump (1, "{");
1397               dump (0, "msg (SE, _(\"Number expected after %s "
1398                     "specifier of %s subcommand.\"));",
1399                     s->specname, sbc->name);
1400               dump (0, "goto lossage;");
1401               dump (-1, "}");
1402               dump (-1, "p->%s%s = tokval;", sbc->prefix,
1403                     st_lower (s->valname));
1404             }
1405           
1406           if (s->restriction)
1407             {
1408               {
1409                 char *str, *str2;
1410                 str = xmalloc (MAX_TOK_LEN);
1411                 str2 = xmalloc (MAX_TOK_LEN);
1412                 sprintf (str2, "p->%s%s", sbc->prefix, st_lower (s->valname));
1413                 sprintf (str, s->restriction, str2, str2, str2, str2,
1414                          str2, str2, str2, str2);
1415                 dump (1, "if (!(%s))", str);
1416                 free (str);
1417                 free (str2);
1418               }
1419               
1420               dump (1, "{");
1421               dump (0, "msg (SE, _(\"Bad argument for %s "
1422                     "specifier of %s subcommand.\"));",
1423                     s->specname, sbc->name);
1424               dump (0, "goto lossage;");
1425               dump (-1, "}");
1426               outdent ();
1427             }
1428           
1429           dump (0, "lex_get ();");
1430           
1431           if (s->valtype == VT_PAREN)
1432             {
1433               dump (1, "if (!lex_match (')'))");
1434               dump (1, "{");
1435               dump (0, "msg (SE, _(\"`)' expected after argument for "
1436                     "%s specifier of %s.\"));",
1437                     s->specname, sbc->name);
1438               dump (0, "goto lossage;");
1439               dump (-1, "}");
1440               outdent ();
1441               if (s->optvalue)
1442                 {
1443                   dump (-1, "}");
1444                   outdent ();
1445                 }
1446             }
1447           
1448           if (s != spec->omit_kw)
1449             dump (-1, "}");
1450         }
1451       
1452       if (s == spec->omit_kw)
1453         {
1454           dump (-1, "}");
1455           outdent ();
1456         }
1457       outdent ();
1458     }
1459 }
1460
1461 /* Write out the code to parse subcommand SBC. */
1462 static void
1463 dump_subcommand (const subcommand *sbc)
1464 {
1465   if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
1466     {
1467       int count;
1468
1469       dump (1, "while (token != '/' && token != '.')");
1470       dump (1, "{");
1471       
1472       {
1473         specifier *spec;
1474
1475         for (count = 0, spec = sbc->spec; spec; spec = spec->next)
1476           {
1477             if (spec->s)
1478               dump_specifier_parse (spec, sbc);
1479             else
1480               {
1481                 count++;
1482                 dump (1, "%sif (%s)", spec != sbc->spec ? "else " : "",
1483                       make_match (st_upper (spec->varname)));
1484                 if (sbc->type == SBC_PLAIN)
1485                   dump (0, "p->%s%s = 1;", st_lower (sbc->prefix),
1486                         spec->varname);
1487                 else
1488                   dump (0, "p->a_%s[%s%s%s] = 1;",
1489                         st_lower (sbc->name),
1490                         st_upper (prefix), st_upper (sbc->prefix),
1491                         st_upper (spec->varname));
1492                 outdent ();
1493               }
1494           }
1495       }
1496       
1497       {
1498         specifier *spec;
1499         setting *s;
1500
1501         /* This code first finds the last specifier in sbc.  Then it
1502            finds the last setting within that last specifier.  Either
1503            or both might be NULL. */
1504         spec = sbc->spec;
1505         s = NULL;
1506         if (spec)
1507           {
1508             while (spec->next)
1509               spec = spec->next;
1510             s = spec->s;
1511             if (s)
1512               while (s->next)
1513                 s = s->next;
1514           }
1515
1516         if (spec && (!spec->s || !spec->omit_kw))
1517           {
1518             dump (1, "else");
1519             dump (1, "{");
1520             dump (0, "lex_error (NULL);");
1521             dump (0, "goto lossage;");
1522             dump (-1, "}");
1523             outdent ();
1524           }
1525       }
1526
1527       dump (0, "lex_match (',');");
1528       dump (-1, "}");
1529       outdent ();
1530     }
1531   else if (sbc->type == SBC_VARLIST)
1532     {
1533       dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1534             "PV_APPEND%s%s))",
1535             st_lower (sbc->prefix), st_lower (sbc->name),
1536             st_lower (sbc->prefix), st_lower (sbc->name),
1537             sbc->message ? " |" : "",
1538             sbc->message ? sbc->message : "");
1539       dump (0, "goto lossage;");
1540       outdent ();
1541     }
1542   else if (sbc->type == SBC_VAR)
1543     {
1544       dump (0, "p->%sv_%s = parse_variable ();",
1545             st_lower (sbc->prefix), st_lower (sbc->name));
1546       dump (1, "if (p->%sv_%s)",
1547             st_lower (sbc->prefix), st_lower (sbc->name));
1548       dump (0, "goto lossage;");
1549       outdent ();
1550     }
1551   else if (sbc->type == SBC_STRING)
1552     {
1553       if (sbc->restriction)
1554         {
1555           dump (1, "{");
1556           dump (0, "int x;");
1557         }
1558       dump (1, "if (!lex_force_string ())");
1559       dump (0, "return 0;");
1560       outdent ();
1561       if (sbc->restriction)
1562         {
1563           dump (0, "x = ds_length (&tokstr);");
1564           dump (1, "if (!(%s))", sbc->restriction);
1565           dump (1, "{");
1566           dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
1567                 sbc->name, sbc->message);
1568           dump (0, "goto lossage;");
1569           dump (-1, "}");
1570           outdent ();
1571         }
1572       dump (0, "free(p->s_%s);", st_lower(sbc->name) );
1573       dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
1574             st_lower (sbc->name));
1575       dump (0, "lex_get ();");
1576       if (sbc->restriction)
1577         dump (-1, "}");
1578     }
1579   else if (sbc->type == SBC_DBL)
1580     {
1581       dump (1, "if (!lex_force_num ())");
1582       dump (0, "goto lossage;");
1583       dump (-1, "p->n_%s = lex_double ();", st_lower (sbc->name));
1584       dump (0, "lex_get();");
1585     }
1586   else if (sbc->type == SBC_INT)
1587     {
1588       dump(1, "{");
1589       dump(0, "int x;");
1590       dump (1, "if (!lex_force_int ())");
1591       dump (0, "goto lossage;");
1592       dump (-1, "x = lex_integer ();");
1593       dump (0, "lex_get();");
1594       if (sbc->restriction)
1595        {
1596           char buf[1024];
1597           dump (1, "if (!(%s))", sbc->restriction);
1598           dump (1, "{");
1599           sprintf(buf,sbc->message,sbc->name);
1600           if ( sbc->translatable ) 
1601                   dump (0, "msg (SE, gettext(\"%s\"));",buf);
1602           else
1603                   dump (0, "msg (SE, \"%s\");",buf);
1604           dump (0, "goto lossage;");
1605           dump (-1, "}");
1606       }
1607       dump (-1, "p->n_%s = x;", st_lower (sbc->name));
1608       dump (-1,"}");
1609     }
1610   else if (sbc->type == SBC_PINT)
1611     {
1612       dump (0, "lex_match ('(');");
1613       dump (1, "if (!lex_force_int ())");
1614       dump (0, "goto lossage;");
1615       dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
1616       dump (0, "lex_match (')');");
1617     }
1618   else if (sbc->type == SBC_CUSTOM)
1619     {
1620       dump (1, "switch (%scustom_%s (p))",
1621             st_lower (prefix), st_lower (sbc->name));
1622       dump (0, "{");
1623       dump (1, "case 0:");
1624       dump (0, "goto lossage;");
1625       dump (-1, "case 1:");
1626       indent ();
1627       dump (0, "break;");
1628       dump (-1, "case 2:");
1629       indent ();
1630       dump (0, "lex_error (NULL);");
1631       dump (0, "goto lossage;");
1632       dump (-1, "default:");
1633       indent ();
1634       dump (0, "assert (0);");
1635       dump (-1, "}");
1636       outdent ();
1637     }
1638 }
1639
1640 /* Write out entire parser. */
1641 static void
1642 dump_parser (int persistent)
1643 {
1644   int f;
1645
1646   indent = 0;
1647
1648   dump (0, "static int");
1649   dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1650         make_identifier (cmdname));
1651   dump (1, "{");
1652
1653   dump_vars_init (persistent);
1654
1655   dump (1, "for (;;)");
1656   dump (1, "{");
1657
1658   f = 0;
1659   if (def && (def->type == SBC_VARLIST))
1660     {
1661       if (def->type == SBC_VARLIST)
1662         dump (1, "if (token == T_ID "
1663               "&& dict_lookup_var (default_dict, tokid) != NULL "
1664               "&& lex_look_ahead () != '=')");
1665       else
1666         {
1667           dump (0, "if ((token == T_ID "
1668                 "&& dict_lookup_var (default_dict, tokid) "
1669                 "&& lex_look_ahead () != '=')");
1670           dump (1, "     || token == T_ALL)");
1671         }
1672       dump (1, "{");
1673       dump (0, "p->sbc_%s++;", st_lower (def->name));
1674       dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
1675             "PV_APPEND))",
1676             st_lower (def->prefix), st_lower (def->name),
1677             st_lower (def->prefix), st_lower (def->name));
1678       dump (0, "goto lossage;");
1679       dump (-2, "}");
1680       outdent ();
1681       f = 1;
1682     }
1683   else if (def && def->type == SBC_CUSTOM)
1684     {
1685       dump (1, "switch (%scustom_%s (p))",
1686             st_lower (prefix), st_lower (def->name));
1687       dump (0, "{");
1688       dump (1, "case 0:");
1689       dump (0, "goto lossage;");
1690       dump (-1, "case 1:");
1691       indent ();
1692       dump (0, "p->sbc_%s++;", st_lower (def->name));
1693       dump (0, "continue;");
1694       dump (-1, "case 2:");
1695       indent ();
1696       dump (0, "break;");
1697       dump (-1, "default:");
1698       indent ();
1699       dump (0, "assert (0);");
1700       dump (-1, "}");
1701       outdent ();
1702     }
1703   
1704   {
1705     subcommand *sbc;
1706
1707     for (sbc = subcommands; sbc; sbc = sbc->next)
1708       {
1709         dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1710         f = 1;
1711         dump (1, "{");
1712
1713         dump (0, "lex_match ('=');");
1714         dump (0, "p->sbc_%s++;", st_lower (sbc->name));
1715         if (sbc->once)
1716           {
1717             dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
1718             dump (1, "{");
1719             dump (0, "msg (SE, _(\"%s subcommand may be given only once.\"));",
1720                   sbc->name);
1721             dump (0, "goto lossage;");
1722             dump (-1, "}");
1723             outdent ();
1724           }
1725         dump_subcommand (sbc);
1726         dump (-1, "}");
1727         outdent ();
1728       }
1729   }
1730   
1731   dump (1, "if (!lex_match ('/'))");
1732   dump (0, "break;");
1733   dump (-2, "}");
1734   outdent ();
1735   dump (0, nullstr);
1736   dump (1, "if (token != '.')");
1737   dump (1, "{");
1738   dump (0, "lex_error (_(\"expecting end of command\"));");
1739   dump (0, "goto lossage;");
1740   dump (-1, "}");
1741   dump (0, nullstr);
1742   dump (-1, "return 1;");
1743   dump (0, nullstr);
1744   dump (-1, "lossage:");
1745   indent ();
1746   dump (0, "free_%s (p);", make_identifier (cmdname));
1747   dump (0, "return 0;");
1748   dump (-1, "}");
1749   dump (0, nullstr);
1750 }
1751
1752
1753 /* Write out the code to parse aux subcommand SBC. */
1754 static void
1755 dump_aux_subcommand (const subcommand *sbc)
1756 {
1757   if (sbc->type == SBC_PLAIN )
1758     {
1759       specifier *spec;
1760         
1761       for (spec = sbc->spec; spec; spec = spec->next)
1762         {
1763           char buf[80];
1764           sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
1765
1766           dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
1767           dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
1768       
1769           dump (0, ");");
1770         }
1771     }
1772   else if (sbc->type == SBC_STRING)
1773     {
1774       dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
1775     }
1776   else if (sbc->type == SBC_INT)
1777     {
1778       dump (0, "msg(MM,\"%s is %%ld\",p->n_%s);", sbc->name,st_lower(sbc->name) ); 
1779     }
1780   else if (sbc->type == SBC_CUSTOM)
1781     {
1782       dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
1783     }
1784   else
1785     assert(0);
1786 }
1787
1788
1789
1790 /* Write out auxilliary parser. */
1791 static void
1792 dump_aux_parser (void)
1793 {
1794   int f=0;
1795   subcommand *sbc;
1796   aux_subcommand *asbc;
1797
1798   /* Write out English strings for all the identifiers in the symbol table. */
1799   {
1800     int f, k;
1801     symbol *sym;
1802     char *buf = NULL;
1803
1804     /* Note the squirmings necessary to make sure that the last string
1805        is not followed by a comma (is it necessary to do that ?? ) */
1806     for (sym = symtab, f = k = 0; sym; sym = sym->next)
1807       if (!sym->unique && !is_keyword (sym->name))
1808         {
1809           if (!f)
1810             {
1811               dump (0, "/* Strings for subcommand specifiers. */");
1812               dump (1, "static const char *settings[]=");
1813               dump (1, "{");
1814               f = 1;
1815             }
1816
1817           if (buf == NULL)
1818             buf = xmalloc (1024);
1819           else
1820             dump (0, buf);
1821
1822           sprintf (buf, "\"%s\",",sym->name);
1823         }
1824     if (buf)
1825       {
1826         buf[strlen (buf) - 1] = 0;
1827         dump (0, buf);
1828         free (buf);
1829       }
1830     if (f)
1831       {
1832         dump (-1, "};");
1833         dump (-1, nullstr);
1834       }
1835   }
1836
1837   
1838   indent = 0;
1839
1840   dump (0, "static int");
1841   dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
1842         make_identifier (cmdname));
1843   dump (1, "{");
1844
1845   dump (1, "for (;;)");
1846   dump (1, "{");
1847
1848
1849   for (sbc = subcommands; sbc; sbc = sbc->next)
1850     {
1851       dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
1852       f = 1;
1853       dump (1, "{");
1854
1855       dump_aux_subcommand (sbc);
1856
1857       dump (-1, "}");
1858       outdent ();
1859     }
1860
1861   for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
1862     {
1863       dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
1864       f = 1;
1865       dump (1, "{");
1866       dump(0,"aux_%s();",make_identifier(asbc->value));
1867       dump (-1, "}");
1868       outdent ();
1869     }
1870   
1871   dump (1, "if (!lex_match ('/'))");
1872   dump (0, "break;");
1873   dump (-2, "}");
1874   outdent ();
1875   dump (0, nullstr);
1876   dump (1, "if (token != '.')");
1877   dump (1, "{");
1878   dump (0, "lex_error (_(\"expecting end of command\"));");
1879   dump (0, "goto lossage;");
1880   dump (-1, "}");
1881   dump (0, nullstr);
1882   dump (-1, "return 1;");
1883   dump (0, nullstr);
1884   dump (-1, "lossage:");
1885   indent ();
1886   dump (0, "free_%s (p);", make_identifier (cmdname));
1887   dump (0, "return 0;");
1888   dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */", 
1889         make_identifier (cmdname), make_identifier (cmdname));
1890   dump (0, nullstr);
1891 }
1892
1893
1894 /* Write the output file header. */
1895 static void
1896 dump_header (void)
1897 {
1898   time_t curtime;
1899   struct tm *loctime;
1900   char *timep;
1901
1902   indent = 0;
1903   curtime = time (NULL);
1904   loctime = localtime (&curtime);
1905   timep = asctime (loctime);
1906   timep[strlen (timep) - 1] = 0;
1907   dump (0,   "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
1908   dump (0, nullstr);
1909   dump (0, "   Generated by q2c from %s on %s.", ifn, timep);
1910   dump (0, "   Do not modify!");
1911   dump (0, " */");
1912   dump (0, nullstr);
1913 }
1914
1915 /* Write out commands to free variable state. */
1916 static void
1917 dump_free (int persistent)
1918 {
1919   subcommand *sbc;
1920   int used;
1921
1922   indent = 0;
1923
1924   used = 0;
1925   if ( ! persistent ) 
1926     {
1927       for (sbc = subcommands; sbc; sbc = sbc->next)
1928         if (sbc->type == SBC_STRING)
1929           used = 1;
1930     }
1931
1932   dump (0, "static void");
1933   dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
1934         make_identifier (cmdname), used ? "" : " UNUSED");
1935   dump (1, "{");
1936
1937   if ( ! persistent ) 
1938     {
1939
1940       for (sbc = subcommands; sbc; sbc = sbc->next)
1941         if (sbc->type == SBC_STRING)
1942           dump (0, "free (p->s_%s);", st_lower (sbc->name));
1943     }
1944
1945   dump (-1, "}");
1946
1947 }
1948
1949
1950
1951 /* Returns the name of a directive found on the current input line, if
1952    any, or a null pointer if none found. */
1953 static const char *
1954 recognize_directive (void)
1955 {
1956   static char directive[16];
1957   char *sp, *ep;
1958   
1959   sp = skip_ws (buf);
1960   if (strncmp (sp, "/*", 2))
1961     return NULL;
1962   sp = skip_ws (sp + 2);
1963   if (*sp != '(')
1964     return NULL;
1965   sp++;
1966
1967   ep = strchr (sp, ')');
1968   if (ep == NULL)
1969     return NULL;
1970
1971   if (ep - sp > 15)
1972     ep = sp + 15;
1973   memcpy (directive, sp, ep - sp);
1974   directive[ep - sp] = '\0';
1975   return directive;
1976 }
1977   
1978 static void aux_parse (void);
1979
1980 int
1981 main (int argc, char *argv[])
1982 {
1983   pgmname = argv[0];
1984   if (argc != 3)
1985     fail ("Syntax: q2c input.q output.c");
1986
1987   ifn = argv[1];
1988   in = fopen (ifn, "r");
1989   if (!in)
1990     fail ("%s: open: %s.", ifn, strerror (errno));
1991
1992   ofn = argv[2];
1993   out = fopen (ofn, "w");
1994   if (!out)
1995     fail ("%s: open: %s.", ofn, strerror (errno));
1996
1997   is_open = 1;
1998   buf = xmalloc (MAX_LINE_LEN);
1999   tokstr = xmalloc (MAX_TOK_LEN);
2000
2001   dump_header ();
2002
2003   indent = 0;
2004   dump (0, "#line %d \"%s\"", ln + 1, ifn);
2005   while (get_line ())
2006     {
2007       const char *directive = recognize_directive ();
2008       if (directive == NULL)
2009         {
2010           dump (0, "%s", buf);
2011           continue;
2012         }
2013       
2014       dump (0, "#line %d \"%s\"", oln - 1, ofn);
2015       if (!strcmp (directive, "specification"))
2016         {
2017           /* Skip leading slash-star line. */
2018           get_line ();
2019           lex_get ();
2020
2021           parse ();
2022
2023           /* Skip trailing star-slash line. */
2024           get_line ();
2025         }
2026       else if (!strcmp (directive, "headers"))
2027         {
2028           indent = 0;
2029
2030           dump (0, "#include <assert.h>");
2031           dump (0, "#include <stdlib.h>");
2032           dump (0, "#include \"alloc.h\"");
2033           dump (0, "#include \"error.h\"");
2034           dump (0, "#include \"lexer.h\"");
2035           dump (0, "#include \"str.h\"");
2036           dump (0, "#include \"var.h\"");
2037           dump (0, nullstr);
2038         }
2039       else if (!strcmp (directive, "declarations"))
2040         dump_declarations ();
2041       else if (!strcmp (directive, "functions"))
2042         {
2043           dump_parser (0);
2044           dump_free (0); 
2045         }
2046       else if (!strcmp (directive, "_functions"))
2047         {
2048           dump_parser (1);
2049           dump_free (1); 
2050         }
2051       else if (!strcmp (directive, "aux_functions"))
2052         {
2053           aux_parse();
2054           dump_aux_parser ();
2055         }
2056       else
2057         error ("unknown directive `%s'", directive);
2058       indent = 0;
2059       dump (0, "#line %d \"%s\"", ln + 1, ifn);
2060     }
2061
2062   return EXIT_SUCCESS;
2063 }
2064
2065 /* Parse an entire auxilliary specification. */
2066 static void
2067 aux_parse (void)
2068 {
2069   aux_subcommand *sbc;
2070   aux_subcommand *prevsbc = 0 ;
2071   get_line();
2072   lex_get();
2073
2074   for (;;)
2075     {
2076         sbc = xmalloc(sizeof(aux_subcommand));
2077         sbc->next = prevsbc;
2078         sbc->name = xstrdup (tokstr);
2079         lex_get();
2080         skip_token('=');
2081         sbc->value = xstrdup (tokstr);
2082         lex_get();
2083       if (token == '.')
2084         break;
2085         skip_token(';');
2086         prevsbc = sbc;
2087
2088     }
2089   /* Skip trailing star-slash line. */
2090   get_line ();
2091   aux_subcommands = sbc;
2092 }
2093
2094