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