q2c: T_RPAREN should be T_LPAREN for matching a left parenthesis.
[pspp-builds.git] / src / language / lexer / q2c.c
index 50a0856a0012ab8f7bce137997891d8ed3466f5d..4858a25706133a5303b48b8b5184ca2dc2b1804a 100644 (file)
@@ -1,37 +1,49 @@
-/* q2c - parser generator for PSPP procedures.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2008, 2010, 2011 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
-
-#include <config.h>
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <assert.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <time.h>
+#include <stdbool.h>
+#include <string.h>
 #include <errno.h>
 #include <unistd.h>
-#include <libpspp/compiler.h>
-#include <libpspp/str.h>
-#include "exit.h"
 
-     
+/* GNU C allows the programmer to declare that certain functions take
+   printf-like arguments, never return, etc.  Conditionalize these
+   declarations on whether gcc is in use. */
+#if __GNUC__ > 1
+#define ATTRIBUTE(X) __attribute__ (X)
+#else
+#define ATTRIBUTE(X)
+#endif
+
+/* Marks a function argument as possibly not used. */
+#define UNUSED ATTRIBUTE ((unused))
+
+/* Marks a function that will never return. */
+#define NO_RETURN ATTRIBUTE ((noreturn))
+
+/* Mark a function as taking a printf- or scanf-like format
+   string as its FMT'th argument and that the FIRST'th argument
+   is the first one to be checked against the format string. */
+#define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (__printf__, FMT, FIRST)))
+
 /* Max length of an input line. */
 #define MAX_LINE_LEN 1024
 
 #define MAX_TOK_LEN 1024
 
 /* argv[0]. */
-char *program_name;
+static char *program_name;
 
 /* Have the input and output files been opened yet? */
-int is_open;
+static bool is_open;
 
 /* Input, output files. */
-FILE *in, *out;
+static FILE *in, *out;
 
 /* Input, output file names. */
-char *ifn, *ofn;
+static char *ifn, *ofn;
 
 /* Input, output file line number. */
-int ln, oln = 1;
+static int ln, oln = 1;
 
 /* Input line buffer, current position. */
-char *buf, *cp;
+static char *buf, *cp;
 
 /* Token types. */
 enum
@@ -64,22 +76,20 @@ enum
   };
 
 /* Current token: either one of the above, or a single character. */
-int token;
+static int token;
 
 /* Token string value. */
-char *tokstr;
+static char *tokstr;
 \f
 /* Utility functions. */
 
-char nullstr[] = "";
-
 /* Close all open files and delete the output file, on failure. */
 static void
 finish_up (void)
 {
   if (!is_open)
     return;
-  is_open = 0;
+  is_open = false;
   fclose (in);
   fclose (out);
   if (remove (ofn) == -1)
@@ -96,8 +106,8 @@ hcf (void)
   exit (EXIT_FAILURE);
 }
 
-int fail (const char *, ...) PRINTF_FORMAT (1, 2);
-int error (const char *, ...) PRINTF_FORMAT (1, 2);
+int fail (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN;
+int error (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN;
 
 /* Output an error message and terminate unsuccessfully. */
 int
@@ -138,14 +148,14 @@ static void *
 xmalloc (size_t size)
 {
   void *vp;
-  
+
   if (size == 0)
     return NULL;
-  
+
   vp = malloc (size);
   if (!vp)
     fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
-  
+
   return vp;
 }
 
@@ -159,11 +169,11 @@ xstrdup (const char *s)
 
   assert (s != NULL);
   size = strlen (s) + 1;
-  
+
   t = malloc (size);
   if (!t)
     fail ("xstrdup(%lu): %s", (unsigned long) strlen (s), VME);
-    
+
   memcpy (t, s, size);
   return t;
 }
@@ -178,22 +188,22 @@ get_buffer (void)
 
   if (++cb >= 8)
     cb = 0;
-  
+
   return b[cb];
 }
-   
+
 /* Copies a string to a static buffer, converting it to lowercase in
    the process, and returns a pointer to the static buffer. */
 static char *
 st_lower (const char *s)
 {
   char *p, *cp;
-  
+
   p = cp = get_buffer ();
   while (*s)
     *cp++ = tolower ((unsigned char) (*s++));
   *cp++ = '\0';
-  
+
   return p;
 }
 
@@ -208,23 +218,23 @@ st_upper (const char *s)
   while (*s)
     *cp++ = toupper ((unsigned char) (*s++));
   *cp++ = '\0';
-  
+
   return p;
 }
 
 /* Returns the address of the first non-whitespace character in S, or
    the address of the null terminator if none. */
 static char *
-skip_ws (const char *s)
+skip_ws (char *s)
 {
   while (isspace ((unsigned char) *s))
     s++;
-  return (char *) s;
+  return s;
 }
 
 /* Read one line from the input file into buf.  Lines having special
    formats are handled specially. */
-static int
+static bool
 get_line (void)
 {
   ln++;
@@ -232,7 +242,7 @@ get_line (void)
     {
       if (ferror (in))
        fail ("%s: fgets: %s", ifn, strerror (errno));
-      return 0;
+      return false;
     }
 
   cp = strchr (buf, '\n');
@@ -240,7 +250,7 @@ get_line (void)
     *cp = '\0';
 
   cp = buf;
-  return 1;
+  return true;
 }
 \f
 /* Symbol table manager. */
@@ -325,7 +335,7 @@ find_symbol (int x)
   return iter;
 }
 
-#if DUMP_TOKENS 
+#if DUMP_TOKENS
 /* Writes a printable representation of the current token to
    stdout. */
 static void
@@ -345,6 +355,45 @@ dump_token (void)
 }
 #endif /* DUMP_TOKENS */
 
+
+const char hyphen_proxy = '_';
+
+static void
+id_cpy (char **cp)
+{
+  char *dest = tokstr;
+  char *src = *cp;
+
+  while (*src == '_' || *src == '-' || isalnum ((unsigned char) *src))
+    {
+      *dest++ = *src == '-' ? hyphen_proxy :toupper ((unsigned char) (*src));
+      src++;
+    }
+
+  *cp = src;
+  *dest++ = '\0';
+}
+
+static char *
+unmunge (const char *s)
+{
+  char *dest = xmalloc (strlen (s) + 1);
+  char *d = dest;
+
+  while (*s)
+    {
+      if (*s == hyphen_proxy)
+       *d = '-';
+      else
+       *d = *s;
+      s++;
+      d++;
+    }
+  *d = '\0';
+
+  return dest;
+}
+
 /* Reads a token from the input file. */
 static int
 lex_get (void)
@@ -355,11 +404,11 @@ lex_get (void)
       cp = skip_ws (cp);
       if (*cp != '\0')
        break;
-      
+
       if (!get_line ())
        fail ("%s: Unexpected end of file.", ifn);
     }
-  
+
   if (*cp == '"')
     {
       char *dest = tokstr;
@@ -386,17 +435,16 @@ lex_get (void)
     {
       char *dest = tokstr;
       token = T_ID;
-      while (*cp == '_' || isalnum ((unsigned char) *cp))
-       *dest++ = toupper ((unsigned char) (*cp++));
-      *dest++ = '\0';
+
+      id_cpy (&cp);
     }
   else
     token = *cp++;
-  
+
 #if DUMP_TOKENS
   dump_token ();
 #endif
-  
+
   return token;
 }
 
@@ -417,29 +465,29 @@ force_string (void)
 }
 
 /* Checks whether the current token is the identifier S; if so, skips
-   the token and returns 1; otherwise, returns 0. */
-static int
+   the token and returns true; otherwise, returns false. */
+static bool
 match_id (const char *s)
 {
   if (token == T_ID && !strcmp (tokstr, s))
     {
       lex_get ();
-      return 1;
+      return true;
     }
-  return 0;
+  return false;
 }
 
 /* Checks whether the current token is T.  If so, skips the token and
-   returns 1; otherwise, returns 0. */
-static int
+   returns true; otherwise, returns false. */
+static bool
 match_token (int t)
 {
   if (token == t)
     {
       lex_get ();
-      return 1;
+      return true;
     }
-  return 0;
+  return false;
 }
 
 /* Force the current token to be T, and skip it. */
@@ -458,7 +506,8 @@ enum
   {
     VAL_NONE,  /* No value. */
     VAL_INT,   /* Integer value. */
-    VAL_DBL    /* Floating point value. */
+    VAL_DBL,   /* Floating point value. */
+    VAL_STRING  /* String value. */
   };
 
 /* For those specifiers with values, the syntax of those values. */
@@ -497,7 +546,7 @@ struct specifier
 
     setting *def;      /* Default setting. */
     setting *omit_kw;  /* Setting for which the keyword can be omitted. */
-    
+
     int index;         /* Next array index. */
   };
 
@@ -536,7 +585,7 @@ struct subcommand
     int narray;                        /* Index of next array element. */
     const char *prefix;                /* Prefix for variable and constant names. */
     specifier *spec;           /* Array of specifiers. */
-    
+
     /* SBC_STRING and SBC_INT only. */
     char *restriction;         /* Expression restricting string length. */
     char *message;             /* Error message. */
@@ -587,7 +636,7 @@ static void
 parse_setting (setting *s, specifier *spec)
 {
   s->parent = spec;
-  
+
   if (match_token ('*'))
     {
       if (spec->omit_kw)
@@ -595,7 +644,7 @@ parse_setting (setting *s, specifier *spec)
       else
        spec->omit_kw = s;
     }
-  
+
   if (match_token ('!'))
     {
       if (spec->def)
@@ -603,7 +652,7 @@ parse_setting (setting *s, specifier *spec)
       else
        spec->def = s;
     }
-  
+
   force_id ();
   s->specname = xstrdup (tokstr);
   s->con = add_symbol (s->specname, 0, 0);
@@ -623,20 +672,22 @@ parse_setting (setting *s, specifier *spec)
        s->valtype = VT_PLAIN;
 
       s->optvalue = match_token ('*');
-      
+
       if (match_id ("N"))
        s->value = VAL_INT;
       else if (match_id ("D"))
        s->value = VAL_DBL;
+      else if (match_id ("S"))
+        s->value = VAL_STRING;
       else
-       error ("`n' or `d' expected.");
-      
+       error ("`n', `d', or `s' expected.");
+
       skip_token (':');
-      
+
       force_id ();
       s->valname = xstrdup (tokstr);
       lex_get ();
-      
+
       if (token == ',')
        {
          lex_get ();
@@ -646,7 +697,7 @@ parse_setting (setting *s, specifier *spec)
        }
       else
        s->restriction = NULL;
-      
+
       if (s->valtype == VT_PAREN)
        skip_token (')');
     }
@@ -668,7 +719,7 @@ parse_specifier (specifier *spec, subcommand *sbc)
       spec->varname = xstrdup (st_lower (tokstr));
       lex_get ();
     }
-  
+
   /* Handle array elements. */
   if (token != ':')
     {
@@ -684,20 +735,20 @@ parse_specifier (specifier *spec, subcommand *sbc)
       return;
     }
   skip_token (':');
-  
-  if ( sbc->type == SBC_ARRAY && token == T_ID ) 
+
+  if ( sbc->type == SBC_ARRAY && token == T_ID )
     {
        spec->varname = xstrdup (st_lower (tokstr));
        spec->index = sbc->narray;
        sbc->narray++;
     }
-    
-  
-  
+
+
+
   /* Parse all the settings. */
   {
     setting **s = &spec->s;
-    
+
     for (;;)
       {
        *s = xmalloc (sizeof **s);
@@ -722,7 +773,7 @@ parse_specifiers (subcommand *sbc)
       *spec = NULL;
       return;
     }
-  
+
   for (;;)
     {
       *spec = xmalloc (sizeof **spec);
@@ -739,8 +790,6 @@ parse_specifiers (subcommand *sbc)
 static void
 parse_subcommand (subcommand *sbc)
 {
-  sbc->arity = ARITY_MANY;
-
   if (match_token ('*'))
     {
       if (def)
@@ -748,8 +797,9 @@ parse_subcommand (subcommand *sbc)
       def = sbc;
     }
 
+  sbc->arity = ARITY_ONCE_ONLY;
   if ( match_token('+'))
-    sbc->arity = ARITY_ONCE_ONLY ;
+    sbc->arity = ARITY_MANY;
   else if (match_token('^'))
     sbc->arity = ARITY_ONCE_EXACTLY ;
 
@@ -757,7 +807,7 @@ parse_subcommand (subcommand *sbc)
   force_id ();
   sbc->name = xstrdup (tokstr);
   lex_get ();
-  
+
   sbc->narray = 0;
   sbc->type = SBC_PLAIN;
   sbc->spec = NULL;
@@ -768,10 +818,10 @@ parse_subcommand (subcommand *sbc)
       force_id ();
       sbc->prefix = xstrdup (st_lower (tokstr));
       lex_get ();
-      
+
       skip_token (']');
       skip_token ('=');
-      
+
       sbc->type = SBC_ARRAY;
       parse_specifiers (sbc);
 
@@ -783,12 +833,12 @@ parse_subcommand (subcommand *sbc)
          force_id ();
          sbc->prefix = xstrdup (st_lower (tokstr));
          lex_get ();
-         
+
          skip_token (')');
        }
       else
        sbc->prefix = "";
-      
+
       skip_token ('=');
 
       if (match_id ("VAR"))
@@ -800,7 +850,7 @@ parse_subcommand (subcommand *sbc)
              force_string ();
              sbc->message = xstrdup (tokstr);
              lex_get();
-             
+
              skip_token (')');
            }
          else sbc->message = NULL;
@@ -810,7 +860,7 @@ parse_subcommand (subcommand *sbc)
       else if (match_id ("INTEGER"))
        {
        sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
-        if ( token == T_STRING) 
+        if ( token == T_STRING)
          {
              sbc->restriction = xstrdup (tokstr);
              lex_get ();
@@ -866,7 +916,7 @@ void
 parse_subcommands (void)
 {
   subcommand **sbc = &subcommands;
-  
+
   for (;;)
     {
       *sbc = xmalloc (sizeof **sbc);
@@ -909,7 +959,7 @@ dump (int indention, const char *format, ...)
 
   if (indention < 0)
     indent += BASE_INDENT * indention;
-  
+
   oln++;
   va_start (args, format);
   for (i = 0; i < indent; i++)
@@ -922,6 +972,19 @@ dump (int indention, const char *format, ...)
     indent += BASE_INDENT * indention;
 }
 
+/* Writes a blank line to the output file and adjusts 'indent' by BASE_INDENT
+   * INDENTION characters.
+
+   (This is only useful because GCC complains about using "" as a format
+   string, for whatever reason.) */
+static void
+dump_blank_line (int indention)
+{
+  oln++;
+  indent += BASE_INDENT * indention;
+  putc ('\n', out);
+}
+
 /* Write the structure members for specifier SPEC to the output file.
    SBC is the including subcommand. */
 static void
@@ -929,7 +992,7 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc)
 {
   if (spec->varname)
     dump (0, "long %s%s;", sbc->prefix, spec->varname);
-  
+
   {
     setting *s;
 
@@ -939,8 +1002,11 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc)
          {
            const char *typename;
 
-           assert (s->value == VAL_INT || s->value == VAL_DBL);
-           typename = s->value == VAL_INT ? "long" : "double";
+           assert (s->value == VAL_INT || s->value == VAL_DBL
+                    || s->value == VAL_STRING);
+           typename = (s->value == VAL_INT ? "long"
+                        : s->value == VAL_DBL ? "double"
+                        : "char *");
 
            dump (0, "%s %s%s;", typename, sbc->prefix, st_lower (s->valname));
          }
@@ -948,8 +1014,8 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc)
   }
 }
 
-/* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
-static int
+/* Returns true if string T is a PSPP keyword, false otherwise. */
+static bool
 is_keyword (const char *t)
 {
   static const char *kw[] =
@@ -961,8 +1027,8 @@ is_keyword (const char *t)
 
   for (cp = kw; *cp; cp++)
     if (!strcmp (t, *cp))
-      return 1;
-  return 0;
+      return true;
+  return false;
 }
 
 /* Transforms a string NAME into a valid C identifier: makes
@@ -980,7 +1046,7 @@ make_identifier (const char *name)
     else
       *cp++ = '_';
   *cp = '\0';
-  
+
   return p;
 }
 
@@ -990,6 +1056,8 @@ dump_declarations (void)
 {
   indent = 0;
 
+  dump (0, "struct dataset;");
+
   /* Write out enums for all the identifiers in the symbol table. */
   {
     int f, k;
@@ -1012,8 +1080,8 @@ dump_declarations (void)
          if (buf == NULL)
            buf = xmalloc (1024);
          else
-           dump (0, buf);
-         
+           dump (0, "%s", buf);
+
          if (k)
            sprintf (buf, "%s%s,", st_upper (prefix), sym->name);
          else
@@ -1025,13 +1093,13 @@ dump_declarations (void)
     if (buf)
       {
        buf[strlen (buf) - 1] = 0;
-       dump (0, buf);
+       dump (0, "%s", buf);
        free (buf);
       }
     if (f)
       {
        dump (-1, "};");
-       dump (-1, nullstr);
+       dump_blank_line (-1);
       }
   }
 
@@ -1050,7 +1118,7 @@ dump_declarations (void)
       if (sbc->type == SBC_ARRAY && sbc->narray)
        {
          dump (0, "/* Array indices for %s subcommand. */", sbc->name);
-         
+
          dump (1, "enum");
          dump (1, "{");
 
@@ -1065,7 +1133,7 @@ dump_declarations (void)
            dump (0, "%s%scount", st_upper (prefix), st_upper (sbc->prefix));
 
            dump (-1, "};");
-           dump (-1, nullstr);
+           dump_blank_line (-1);
          }
        }
   }
@@ -1082,8 +1150,8 @@ dump_declarations (void)
        int f = 0;
 
        if (sbc != subcommands)
-         dump (0, nullstr);
-       
+         dump_blank_line (0);
+
        dump (0, "/* %s subcommand. */", sbc->name);
        dump (0, "int sbc_%s;", st_lower (sbc->name));
 
@@ -1093,7 +1161,7 @@ dump_declarations (void)
          case SBC_PLAIN:
            {
              specifier *spec;
-           
+
              for (spec = sbc->spec; spec; spec = spec->next)
                {
                  if (spec->s == 0)
@@ -1103,8 +1171,8 @@ dump_declarations (void)
                              spec->varname);
                      else if (f == 0)
                        {
-                         dump (0, "int a_%s[%s%scount];", 
-                               st_lower (sbc->name), 
+                         dump (0, "int a_%s[%s%scount];",
+                               st_lower (sbc->name),
                                st_upper (prefix),
                                st_upper (sbc->prefix)
                                );
@@ -1121,12 +1189,12 @@ dump_declarations (void)
          case SBC_VARLIST:
            dump (0, "size_t %sn_%s;", st_lower (sbc->prefix),
                  st_lower (sbc->name));
-           dump (0, "struct variable **%sv_%s;", st_lower (sbc->prefix),
+           dump (0, "const struct variable **%sv_%s;", st_lower (sbc->prefix),
                  st_lower (sbc->name));
            break;
 
          case SBC_VAR:
-           dump (0, "struct variable *%sv_%s;", st_lower (sbc->prefix),
+           dump (0, "const struct variable *%sv_%s;", st_lower (sbc->prefix),
                  st_lower (sbc->name));
            break;
 
@@ -1160,12 +1228,12 @@ dump_declarations (void)
       }
 
     dump (-1, "};");
-    dump (-1, nullstr);
+    dump_blank_line (-1);
   }
 
   /* Write out prototypes for custom_*() functions as necessary. */
   {
-    int seen = 0;
+    bool seen = false;
     subcommand *sbc;
 
     for (sbc = subcommands; sbc; sbc = sbc->next)
@@ -1173,27 +1241,27 @@ dump_declarations (void)
        {
          if (!seen)
            {
-             seen = 1;
+             seen = true;
              dump (0, "/* Prototype for custom subcommands of %s. */",
                    cmdname);
            }
-         dump (0, "static int %scustom_%s (struct cmd_%s *);",
+         dump (0, "static int %scustom_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
                st_lower (prefix), st_lower (sbc->name),
                make_identifier (cmdname));
        }
 
     if (seen)
-      dump (0, nullstr);
+      dump_blank_line (0);
   }
 
   /* Prototypes for parsing and freeing functions. */
   {
     dump (0, "/* Command parsing functions. */");
-    dump (0, "static int parse_%s (struct cmd_%s *);",
+    dump (0, "static int parse_%s (struct lexer *, struct dataset *, struct cmd_%s *, void *);",
          make_identifier (cmdname), make_identifier (cmdname));
     dump (0, "static void free_%s (struct cmd_%s *);",
          make_identifier (cmdname), make_identifier (cmdname));
-    dump (0, nullstr);
+    dump_blank_line (0);
   }
 }
 
@@ -1213,7 +1281,7 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc)
        strcpy (s, "-1");
       dump (0, "p->%s%s = %s;", sbc->prefix, spec->varname, s);
     }
-  
+
   {
     setting *s;
 
@@ -1223,8 +1291,11 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc)
          {
            const char *init;
 
-           assert (s->value == VAL_INT || s->value == VAL_DBL);
-           init = s->value == VAL_INT ? "NOT_LONG" : "SYSMIS";
+           assert (s->value == VAL_INT || s->value == VAL_DBL
+                    || s->value == VAL_STRING);
+           init = (s->value == VAL_INT ? "LONG_MIN"
+                    : s->value == VAL_DBL ? "SYSMIS"
+                    : "NULL");
 
            dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
          }
@@ -1239,24 +1310,24 @@ dump_vars_init (int persistent)
   /* Loop through all the subcommands. */
   {
     subcommand *sbc;
-    
+
     for (sbc = subcommands; sbc; sbc = sbc->next)
       {
        int f = 0;
-       
+
        dump (0, "p->sbc_%s = 0;", st_lower (sbc->name));
-       if ( ! persistent ) 
+       if ( ! persistent )
          {
            switch (sbc->type)
              {
              case SBC_INT_LIST:
-               break;
-
              case SBC_DBL_LIST:
                dump (1, "{");
                dump (0, "int i;");
                dump (1, "for (i = 0; i < MAXLISTS; ++i)");
-               dump (0, "subc_list_double_create(&p->dl_%s[i]) ;",
+               dump (0, "subc_list_%s_create(&p->%cl_%s[i]) ;",
+                      sbc->type == SBC_INT_LIST ? "int" : "double",
+                      sbc->type == SBC_INT_LIST ? 'i' : 'd',
                      st_lower (sbc->name)
                      );
                dump (-2, "}");
@@ -1273,12 +1344,12 @@ dump_vars_init (int persistent)
              case SBC_CUSTOM:
                /* nothing */
                break;
-           
+
              case SBC_PLAIN:
              case SBC_ARRAY:
                {
                  specifier *spec;
-           
+
                  for (spec = sbc->spec; spec; spec = spec->next)
                    if (spec->s == NULL)
                      {
@@ -1302,7 +1373,7 @@ dump_vars_init (int persistent)
                dump (0, "p->%sv_%s = NULL;",
                      st_lower (sbc->prefix), st_lower (sbc->name));
                break;
-           
+
              case SBC_VAR:
                dump (0, "p->%sv_%s = NULL;",
                      st_lower (sbc->prefix), st_lower (sbc->name));
@@ -1317,12 +1388,12 @@ dump_vars_init (int persistent)
                dump (1, "{");
                dump (0, "int i;");
                dump (1, "for (i = 0; i < MAXLISTS; ++i)");
-               dump (0, "p->n_%s[i] = NOT_LONG;", st_lower (sbc->name));
+               dump (0, "p->n_%s[i] = LONG_MIN;", st_lower (sbc->name));
                dump (-2, "}");
                break;
 
              default:
-               assert (0);
+               abort ();
              }
          }
       }
@@ -1340,20 +1411,26 @@ make_match (const char *t)
 
   while (*t == '_')
     t++;
-      
+
   if (is_keyword (t))
-    sprintf (s, "lex_match (T_%s)", t);
+    sprintf (s, "lex_match (lexer, T_%s)", t);
   else if (!strcmp (t, "ON") || !strcmp (t, "YES"))
-    strcpy (s, "(lex_match_id (\"ON\") || lex_match_id (\"YES\") "
-           "|| lex_match_id (\"TRUE\"))");
+    strcpy (s, "(lex_match_id (lexer, \"ON\") || lex_match_id (lexer, \"YES\") "
+           "|| lex_match_id (lexer, \"TRUE\"))");
   else if (!strcmp (t, "OFF") || !strcmp (t, "NO"))
-    strcpy (s, "(lex_match_id (\"OFF\") || lex_match_id (\"NO\") "
-           "|| lex_match_id (\"FALSE\"))");
+    strcpy (s, "(lex_match_id (lexer, \"OFF\") || lex_match_id (lexer, \"NO\") "
+           "|| lex_match_id (lexer, \"FALSE\"))");
   else if (isdigit ((unsigned char) t[0]))
-    sprintf (s, "lex_match_int (%s)", t);
+    sprintf (s, "lex_match_int (lexer, %s)", t);
+  else if (strchr (t, hyphen_proxy))
+    {
+      char *c = unmunge (t);
+      sprintf (s, "lex_match_hyphenated_word (lexer, \"%s\")", c);
+      free (c);
+    }
   else
-    sprintf (s, "lex_match_id (\"%s\")", t);
-  
+    sprintf (s, "lex_match_id (lexer, \"%s\")", t);
+
   return s;
 }
 
@@ -1370,7 +1447,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
   if (spec->omit_kw && spec->omit_kw->parent->next)
     error ("Default specifier is not in last specifier in `%s' "
           "subcommand.", sbc->name);
-  
+
   for (s = spec->s; s; s = s->next)
     {
       int first = spec == sbc->spec && s == spec->s;
@@ -1398,13 +1475,13 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
        {
          if (spec->omit_kw != s)
            dump (1, "{");
-         
+
          if (spec->varname)
            {
              dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
                    st_upper (prefix), find_symbol (s->con)->name);
 
-             if ( sbc->type == SBC_ARRAY ) 
+             if ( sbc->type == SBC_ARRAY )
                dump (0, "p->a_%s[%s%s%s] = 1;",
                      st_lower (sbc->name),
                      st_upper (prefix), st_upper (sbc->prefix),
@@ -1416,12 +1493,12 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
            {
              if (s->optvalue)
                {
-                 dump (1, "if (lex_match ('('))");
+                 dump (1, "if (lex_match (lexer, T_LPAREN))");
                  dump (1, "{");
                }
              else
                {
-                 dump (1, "if (!lex_match ('('))");
+                 dump (1, "if (!lex_match (lexer, T_LPAREN))");
                  dump (1, "{");
                  dump (0, "msg (SE, _(\"`(' expected after %s "
                        "specifier of %s subcommand.\"));",
@@ -1434,29 +1511,45 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
 
          if (s->value == VAL_INT)
            {
-             dump (1, "if (!lex_is_integer ())");
+             dump (1, "if (!lex_is_integer (lexer))");
              dump (1, "{");
              dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
                    "requires an integer argument.\"));",
                    s->specname, sbc->name);
              dump (0, "goto lossage;");
              dump (-1, "}");
-             dump (-1, "p->%s%s = lex_integer ();",
+             dump (-1, "p->%s%s = lex_integer (lexer);",
                    sbc->prefix, st_lower (s->valname));
            }
-         else
+         else if (s->value == VAL_DBL)
            {
-             dump (1, "if (!lex_is_number ())");
+             dump (1, "if (!lex_is_number (lexer))");
              dump (1, "{");
              dump (0, "msg (SE, _(\"Number expected after %s "
                    "specifier of %s subcommand.\"));",
                    s->specname, sbc->name);
              dump (0, "goto lossage;");
              dump (-1, "}");
-             dump (-1, "p->%s%s = tokval;", sbc->prefix,
+             dump (-1, "p->%s%s = lex_tokval (lexer);", sbc->prefix,
                    st_lower (s->valname));
            }
-         
+          else if (s->value == VAL_STRING)
+            {
+              dump (1, "if (lex_token (lexer) != T_ID "
+                    "&& !lex_is_string (lexer))");
+              dump (1, "{");
+              dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
+                    "requires a string argument.\"));",
+                   s->specname, sbc->name);
+             dump (0, "goto lossage;");
+             dump (-1, "}");
+              dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
+              dump (0, "p->%s%s = ss_xstrdup (ss_tokss (lexer));",
+                    sbc->prefix, st_lower (s->valname));
+            }
+          else
+            abort ();
+
          if (s->restriction)
            {
              {
@@ -1470,7 +1563,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
                free (str);
                free (str2);
              }
-             
+
              dump (1, "{");
              dump (0, "msg (SE, _(\"Bad argument for %s "
                    "specifier of %s subcommand.\"));",
@@ -1479,12 +1572,12 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
              dump (-1, "}");
              outdent ();
            }
-         
-         dump (0, "lex_get ();");
-         
+
+         dump (0, "lex_get (lexer);");
+
          if (s->valtype == VT_PAREN)
            {
-             dump (1, "if (!lex_match (')'))");
+             dump (1, "if (!lex_match (lexer, T_RPAREN))");
              dump (1, "{");
              dump (0, "msg (SE, _(\"`)' expected after argument for "
                    "%s specifier of %s.\"));",
@@ -1498,11 +1591,11 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
                  outdent ();
                }
            }
-         
+
          if (s != spec->omit_kw)
            dump (-1, "}");
        }
-      
+
       if (s == spec->omit_kw)
        {
          dump (-1, "}");
@@ -1520,9 +1613,9 @@ dump_subcommand (const subcommand *sbc)
     {
       int count;
 
-      dump (1, "while (token != '/' && token != '.')");
+      dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
       dump (1, "{");
-      
+
       {
        specifier *spec;
 
@@ -1547,7 +1640,7 @@ dump_subcommand (const subcommand *sbc)
              }
          }
       }
-      
+
       {
        specifier *spec;
        setting *s;
@@ -1571,20 +1664,20 @@ dump_subcommand (const subcommand *sbc)
          {
            dump (1, "else");
            dump (1, "{");
-           dump (0, "lex_error (NULL);");
+           dump (0, "lex_error (lexer, NULL);");
            dump (0, "goto lossage;");
            dump (-1, "}");
            outdent ();
          }
       }
 
-      dump (0, "lex_match (',');");
+      dump (0, "lex_match (lexer, T_COMMA);");
       dump (-1, "}");
       outdent ();
     }
   else if (sbc->type == SBC_VARLIST)
     {
-      dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
+      dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
            "PV_APPEND%s%s))",
            st_lower (sbc->prefix), st_lower (sbc->name),
            st_lower (sbc->prefix), st_lower (sbc->name),
@@ -1595,7 +1688,7 @@ dump_subcommand (const subcommand *sbc)
     }
   else if (sbc->type == SBC_VAR)
     {
-      dump (0, "p->%sv_%s = parse_variable ();",
+      dump (0, "p->%sv_%s = parse_variable (lexer, dataset_dict (ds));",
            st_lower (sbc->prefix), st_lower (sbc->name));
       dump (1, "if (!p->%sv_%s)",
            st_lower (sbc->prefix), st_lower (sbc->name));
@@ -1609,12 +1702,12 @@ dump_subcommand (const subcommand *sbc)
          dump (1, "{");
          dump (0, "int x;");
        }
-      dump (1, "if (!lex_force_string ())");
-      dump (0, "return 0;");
+      dump (1, "if (!lex_force_string (lexer))");
+      dump (0, "return false;");
       outdent ();
       if (sbc->restriction)
        {
-         dump (0, "x = ds_length (&tokstr);");
+         dump (0, "x = ss_length (lex_tokss (lexer));");
          dump (1, "if (!(%s))", sbc->restriction);
          dump (1, "{");
          dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
@@ -1624,35 +1717,35 @@ dump_subcommand (const subcommand *sbc)
          outdent ();
        }
       dump (0, "free(p->s_%s);", st_lower(sbc->name) );
-      dump (0, "p->s_%s = ds_xstrdup (&tokstr);",
+      dump (0, "p->s_%s = ss_xstrdup (lex_tokss (lexer));",
            st_lower (sbc->name));
-      dump (0, "lex_get ();");
+      dump (0, "lex_get (lexer);");
       if (sbc->restriction)
        dump (-1, "}");
     }
   else if (sbc->type == SBC_DBL)
     {
-      dump (1, "if (!lex_force_num ())");
+      dump (1, "if (!lex_force_num (lexer))");
       dump (0, "goto lossage;");
-      dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();", 
+      dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number (lexer);",
            st_lower (sbc->name), st_lower (sbc->name) );
-      dump (0, "lex_get();");
+      dump (0, "lex_get(lexer);");
     }
   else if (sbc->type == SBC_INT)
     {
       dump(1, "{");
       dump(0, "int x;");
-      dump (1, "if (!lex_force_int ())");
+      dump (1, "if (!lex_force_int (lexer))");
       dump (0, "goto lossage;");
-      dump (-1, "x = lex_integer ();");
-      dump (0, "lex_get();");
+      dump (-1, "x = lex_integer (lexer);");
+      dump (0, "lex_get(lexer);");
       if (sbc->restriction)
        {
          char buf[1024];
          dump (1, "if (!(%s))", sbc->restriction);
-         dump (1, "{"); 
+         dump (1, "{");
           sprintf(buf,sbc->message,sbc->name);
-         if ( sbc->translatable ) 
+         if ( sbc->translatable )
                  dump (0, "msg (SE, gettext(\"%s\"));",buf);
          else
                  dump (0, "msg (SE, \"%s\");",buf);
@@ -1664,13 +1757,13 @@ dump_subcommand (const subcommand *sbc)
     }
   else if (sbc->type == SBC_PINT)
     {
-      dump (0, "lex_match ('(');");
-      dump (1, "if (!lex_force_int ())");
+      dump (0, "lex_match (lexer, T_LPAREN);");
+      dump (1, "if (!lex_force_int (lexer))");
       dump (0, "goto lossage;");
-      dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
-      dump (0, "lex_match (')');");
+      dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
+      dump (0, "lex_match (lexer, T_RPAREN);");
     }
-  else if (sbc->type == SBC_DBL_LIST)
+  else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST)
     {
       dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
       dump (1, "{");
@@ -1678,25 +1771,26 @@ dump_subcommand (const subcommand *sbc)
       dump (0, "goto lossage;");
       dump (-1,"}");
 
-      dump (1, "while (token != '/' && token != '.')");
+      dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
       dump (1, "{");
-      dump (0, "lex_match(',');");
-      dump (0, "if (!lex_force_num ())");
+      dump (0, "lex_match (lexer, T_COMMA);");
+      dump (0, "if (!lex_force_num (lexer))");
       dump (1, "{");
       dump (0, "goto lossage;");
       dump (-1,"}");
 
-      dump (0, "subc_list_double_push(&p->dl_%s[p->sbc_%s-1],lex_number ());", 
-           st_lower (sbc->name),st_lower (sbc->name)
-           );
+      dump (0, "subc_list_%s_push (&p->%cl_%s[p->sbc_%s-1], lex_number (lexer));",
+            sbc->type == SBC_INT_LIST ? "int" : "double",
+            sbc->type == SBC_INT_LIST ? 'i' : 'd',
+            st_lower (sbc->name), st_lower (sbc->name));
 
-      dump (0, "lex_get();");
+      dump (0, "lex_get (lexer);");
       dump (-1,"}");
 
     }
   else if (sbc->type == SBC_CUSTOM)
     {
-      dump (1, "switch (%scustom_%s (p))",
+      dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
            st_lower (prefix), st_lower (sbc->name));
       dump (0, "{");
       dump (1, "case 0:");
@@ -1706,11 +1800,11 @@ dump_subcommand (const subcommand *sbc)
       dump (0, "break;");
       dump (-1, "case 2:");
       indent ();
-      dump (0, "lex_error (NULL);");
+      dump (0, "lex_error (lexer, NULL);");
       dump (0, "goto lossage;");
       dump (-1, "default:");
       indent ();
-      dump (0, "assert (0);");
+      dump (0, "NOT_REACHED ();");
       dump (-1, "}");
       outdent ();
     }
@@ -1725,7 +1819,9 @@ dump_parser (int persistent)
   indent = 0;
 
   dump (0, "static int");
-  dump (0, "parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
+  dump (0, "parse_%s (struct lexer *lexer, struct dataset *ds%s, struct cmd_%s *p, void *aux UNUSED)",
+        make_identifier (cmdname),
+       (def && ( def->type == SBC_VARLIST && def->type == SBC_CUSTOM))?"":" UNUSED",
        make_identifier (cmdname));
   dump (1, "{");
 
@@ -1738,19 +1834,19 @@ dump_parser (int persistent)
   if (def && (def->type == SBC_VARLIST))
     {
       if (def->type == SBC_VARLIST)
-       dump (1, "if (token == T_ID "
-              "&& dict_lookup_var (default_dict, tokid) != NULL "
-             "&& lex_look_ahead () != '=')");
+       dump (1, "if (lex_token (lexer) == T_ID "
+              "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) != NULL "
+             "&& lex_look_ahead (lexer) != '=')");
       else
        {
-         dump (0, "if ((token == T_ID "
-                "&& dict_lookup_var (default_dict, tokid) "
+         dump (0, "if ((lex_token (lexer) == T_ID "
+                "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) "
                "&& lex_look_ahead () != '=')");
          dump (1, "     || token == T_ALL)");
        }
       dump (1, "{");
       dump (0, "p->sbc_%s++;", st_lower (def->name));
-      dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
+      dump (1, "if (!parse_variables_const (lexer, dataset_dict (ds), &p->%sv_%s, &p->%sn_%s, "
            "PV_APPEND))",
            st_lower (def->prefix), st_lower (def->name),
            st_lower (def->prefix), st_lower (def->name));
@@ -1761,7 +1857,7 @@ dump_parser (int persistent)
     }
   else if (def && def->type == SBC_CUSTOM)
     {
-      dump (1, "switch (%scustom_%s (p))",
+      dump (1, "switch (%scustom_%s (lexer, ds, p, aux))",
            st_lower (prefix), st_lower (def->name));
       dump (0, "{");
       dump (1, "case 0:");
@@ -1775,11 +1871,11 @@ dump_parser (int persistent)
       dump (0, "break;");
       dump (-1, "default:");
       indent ();
-      dump (0, "assert (0);");
+      dump (0, "NOT_REACHED ();");
       dump (-1, "}");
       outdent ();
     }
-  
+
   {
     subcommand *sbc;
 
@@ -1789,7 +1885,7 @@ dump_parser (int persistent)
        f = 1;
        dump (1, "{");
 
-       dump (0, "lex_match ('=');");
+       dump (0, "lex_match (lexer, T_EQUALS);");
        dump (0, "p->sbc_%s++;", st_lower (sbc->name));
        if (sbc->arity != ARITY_MANY)
          {
@@ -1809,33 +1905,33 @@ dump_parser (int persistent)
 
 
   /* Now deal with the /ALGORITHM subcommand implicit to all commands */
-  dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
+  dump(1,"else if ( settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
   dump(1,"{");
 
-  dump (0, "lex_match ('=');");
+  dump (0, "lex_match (lexer, T_EQUALS);");
 
-  dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
-  dump(0,"set_cmd_algorithm(COMPATIBLE);");
+  dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
+  dump(0,"settings_set_cmd_algorithm (COMPATIBLE);");
   outdent();
-  dump(1,"else if (lex_match_id(\"ENHANCED\"))");
-  dump(0,"set_cmd_algorithm(ENHANCED);");
+  dump(1,"else if (lex_match_id(lexer, \"ENHANCED\"))");
+  dump(0,"settings_set_cmd_algorithm (ENHANCED);");
 
   dump (-1, "}");
   outdent ();
 
 
-  
-  dump (1, "if (!lex_match ('/'))");
+
+  dump (1, "if (!lex_match (lexer, T_SLASH))");
   dump (0, "break;");
   dump (-2, "}");
   outdent ();
-  dump (0, nullstr);
-  dump (1, "if (token != '.')");
+  dump_blank_line (0);
+  dump (1, "if (lex_token (lexer) != T_ENDCMD)");
   dump (1, "{");
-  dump (0, "lex_error (_(\"expecting end of command\"));");
+  dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
   dump (0, "goto lossage;");
   dump (-1, "}");
-  dump (0, nullstr);
+  dump_blank_line (0);
 
   outdent ();
 
@@ -1846,7 +1942,7 @@ dump_parser (int persistent)
     for (sbc = subcommands; sbc; sbc = sbc->next)
       {
 
-       if ( sbc->arity == ARITY_ONCE_EXACTLY ) 
+       if ( sbc->arity == ARITY_ONCE_EXACTLY )
          {
            dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
            dump (1, "{");
@@ -1854,19 +1950,19 @@ dump_parser (int persistent)
                  sbc->name);
            dump (0, "goto lossage;");
            dump (-1, "}");
-           dump (0, nullstr);
+           dump_blank_line (0);
          }
       }
   }
 
-  dump (-1, "return 1;");
-  dump (0, nullstr);
+  dump (-1, "return true;");
+  dump_blank_line (0);
   dump (-1, "lossage:");
   indent ();
   dump (0, "free_%s (p);", make_identifier (cmdname));
-  dump (0, "return 0;");
+  dump (0, "return false;");
   dump (-1, "}");
-  dump (0, nullstr);
+  dump_blank_line (0);
 }
 
 
@@ -1874,18 +1970,10 @@ dump_parser (int persistent)
 static void
 dump_header (void)
 {
-  time_t curtime;
-  struct tm *loctime;
-  char *timep;
-
   indent = 0;
-  curtime = time (NULL);
-  loctime = localtime (&curtime);
-  timep = asctime (loctime);
-  timep[strlen (timep) - 1] = 0;
   dump (0,   "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
-  dump (0, nullstr);
-  dump (0, "   Generated by q2c from %s on %s.", ifn, timep);
+  dump_blank_line (0);
+  dump (0, "   Generated by q2c from %s.", ifn);
   dump (0, "   Do not modify!");
   dump (0, " */");
 }
@@ -1900,16 +1988,12 @@ dump_free (int persistent)
   indent = 0;
 
   used = 0;
-  if ( ! persistent ) 
+  if ( ! persistent )
     {
       for (sbc = subcommands; sbc; sbc = sbc->next)
-       {
-       if (sbc->type == SBC_STRING)
-         used = 1;
-       if (sbc->type == SBC_DBL_LIST)
-         used = 1;
-       }
-
+        used = (sbc->type == SBC_STRING
+                || sbc->type == SBC_DBL_LIST
+                || sbc->type == SBC_INT_LIST);
     }
 
   dump (0, "static void");
@@ -1917,12 +2001,12 @@ dump_free (int persistent)
        make_identifier (cmdname), used ? "" : " UNUSED");
   dump (1, "{");
 
-  if ( ! persistent ) 
+  if ( ! persistent )
     {
 
       for (sbc = subcommands; sbc; sbc = sbc->next)
        {
-         switch (sbc->type) 
+         switch (sbc->type)
            {
             case SBC_VARLIST:
              dump (0, "free (p->v_%s);", st_lower (sbc->name));
@@ -1931,13 +2015,28 @@ dump_free (int persistent)
              dump (0, "free (p->s_%s);", st_lower (sbc->name));
              break;
            case SBC_DBL_LIST:
+           case SBC_INT_LIST:
               dump (0, "{");
              dump (1, "int i;");
              dump (2, "for(i = 0; i < MAXLISTS ; ++i)");
-             dump (1, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
+             dump (1, "subc_list_%s_destroy(&p->%cl_%s[i]);",
+                    sbc->type == SBC_INT_LIST ? "int" : "double",
+                    sbc->type == SBC_INT_LIST ? 'i' : 'd',
+                    st_lower (sbc->name));
               dump (0, "}");
              outdent();
              break;
+            case SBC_PLAIN:
+              {
+                specifier *spec;
+                setting *s;
+
+                for (spec = sbc->spec; spec; spec = spec->next)
+                  for (s = spec->s; s; s = s->next)
+                    if (s->value == VAL_STRING)
+                      dump (0, "free (p->%s%s);",
+                            sbc->prefix, st_lower (s->valname));
+              }
            default:
              break;
            }
@@ -1957,7 +2056,7 @@ recognize_directive (void)
 {
   static char directive[16];
   char *sp, *ep;
-  
+
   sp = skip_ws (buf);
   if (strncmp (sp, "/*", 2))
     return NULL;
@@ -1976,7 +2075,7 @@ recognize_directive (void)
   directive[ep - sp] = '\0';
   return directive;
 }
-  
+
 int
 main (int argc, char *argv[])
 {
@@ -1994,7 +2093,7 @@ main (int argc, char *argv[])
   if (!out)
     fail ("%s: open: %s.", ofn, strerror (errno));
 
-  is_open = 1;
+  is_open = true;
   buf = xmalloc (MAX_LINE_LEN);
   tokstr = xmalloc (MAX_TOK_LEN);
 
@@ -2011,7 +2110,7 @@ main (int argc, char *argv[])
          dump (0, "%s", buf);
          continue;
        }
-      
+
       dump (0, "#line %d \"%s\"", oln + 1, ofn);
       if (!strcmp (directive, "specification"))
        {
@@ -2029,30 +2128,34 @@ main (int argc, char *argv[])
          indent = 0;
 
          dump (0, "#include <stdlib.h>");
-         dump (0, "#include <libpspp/alloc.h>");
+         dump (0, "#include <libpspp/assertion.h>");
          dump (0, "#include <libpspp/message.h>");
          dump (0, "#include <language/lexer/lexer.h>");
+         dump (0, "#include <language/lexer/variable-parser.h>");
           dump (0, "#include <data/settings.h>");
          dump (0, "#include <libpspp/str.h>");
           dump (0, "#include <language/lexer/subcommand-list.h>");
          dump (0, "#include <data/variable.h>");
-         dump (0, nullstr);
+         dump_blank_line (0);
+
+          dump (0, "#include \"xalloc.h\"");
+         dump_blank_line (0);
 
           dump (0, "#include \"gettext.h\"");
           dump (0, "#define _(msgid) gettext (msgid)");
-         dump (0, nullstr);
+         dump_blank_line (0);
        }
       else if (!strcmp (directive, "declarations"))
        dump_declarations ();
       else if (!strcmp (directive, "functions"))
        {
          dump_parser (0);
-         dump_free (0); 
+         dump_free (0);
        }
       else if (!strcmp (directive, "_functions"))
        {
          dump_parser (1);
-         dump_free (1); 
+         dump_free (1);
        }
       else
        error ("unknown directive `%s'", directive);
@@ -2060,7 +2163,5 @@ main (int argc, char *argv[])
       dump (0, "#line %d \"%s\"", ln + 1, ifn);
     }
 
-
-
   return EXIT_SUCCESS;
 }