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