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