Changed all the licence notices in all the files.
[pspp-builds.git] / src / q2c.c
index 839d4a779022f6677496b4542c9bf71dea574392..a62e62d40942d9bc506e4763b41cfaca4bebf2a2 100644 (file)
--- a/src/q2c.c
+++ b/src/q2c.c
@@ -14,8 +14,8 @@
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
 #include <assert.h>
@@ -30,6 +30,7 @@
 #endif
 #include "str.h"
 
+
 /* Brokenness. */
 #ifndef EXIT_SUCCESS
 #define EXIT_SUCCESS 0
@@ -43,8 +44,6 @@
 #include "misc/strerror.c"
 #endif
      
-#undef DEBUGGING
-/*#define DEBUGGING 1*/
 #include "debug-print.h"
 
 /* Max length of an input line. */
@@ -86,14 +85,10 @@ char *tokstr;
 \f
 /* Utility functions. */
 
-#if !(__GNUC__ >= 2)
-#define nullstr ""
-#else
-const char nullstr[] = "";
-#endif
+char nullstr[] = "";
 
 /* Close all open files and delete the output file, on failure. */
-void
+static void
 finish_up (void)
 {
   if (!is_open)
@@ -105,9 +100,7 @@ finish_up (void)
     fprintf (stderr, "%s: %s: remove: %s\n", pgmname, ofn, strerror (errno));
 }
 
-#if __GNUC__ >= 2
-void hcf (void) __attribute__ ((noreturn));
-#endif
+void hcf (void) NO_RETURN;
 
 /* Terminate unsuccessfully. */
 void
@@ -117,10 +110,8 @@ hcf (void)
   exit (EXIT_FAILURE);
 }
 
-#if __GNUC__ >= 2
-int fail (const char *, ...) __attribute__ ((format (printf, 1, 2)));
-int error (const char *, ...) __attribute__ ((format (printf, 1, 2)));
-#endif
+int fail (const char *, ...) PRINTF_FORMAT (1, 2);
+int error (const char *, ...) PRINTF_FORMAT (1, 2);
 
 /* Output an error message and terminate unsuccessfully. */
 int
@@ -157,7 +148,7 @@ error (const char *format,...)
 
 /* Allocate a block of SIZE bytes and return a pointer to its
    beginning. */
-void *
+static void *
 xmalloc (size_t size)
 {
   void *vp;
@@ -167,45 +158,14 @@ xmalloc (size_t size)
   
   vp = malloc (size);
   if (!vp)
-    {
-#if DEBUGGING && __CHECKER__
-      error ("xmalloc(%lu): Inducing segfault.", (unsigned long) size);
-      *((int *) 0) = 0;
-#endif
-      fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
-    }
-  
-  return vp;
-}
-
-/* Resize the block at PTR to size SIZE and return a pointer to the
-   beginning of the new block. */
-void *
-xrealloc (void *ptr, size_t size)
-{
-  void *vp;
-  
-  if (!size)
-    {
-      if (ptr)
-       free (ptr);
-      return NULL;
-    }
-  
-  if (ptr)
-    vp = realloc (ptr, size);
-  else
-    vp = malloc (size);
-  
-  if (!vp)
-    fail ("xrealloc(%lu): %s", (unsigned long) size, VME);
+    fail ("xmalloc(%lu): %s", (unsigned long) size, VME);
   
   return vp;
 }
 
 /* Make a dynamically allocated copy of string S and return a pointer
    to the first character. */
-char *
+static char *
 xstrdup (const char *s)
 {
   size_t size;
@@ -224,7 +184,7 @@ xstrdup (const char *s)
 
 /* Returns a pointer to one of 8 static buffers.  The buffers are used
    in rotation. */
-char *
+static char *
 get_buffer (void)
 {
   static char b[8][256];
@@ -238,7 +198,7 @@ get_buffer (void)
    
 /* Copies a string to a static buffer, converting it to lowercase in
    the process, and returns a pointer to the static buffer. */
-char *
+static char *
 st_lower (const char *s)
 {
   char *p, *cp;
@@ -253,7 +213,7 @@ st_lower (const char *s)
 
 /* Copies a string to a static buffer, converting it to uppercase in
    the process, and returns a pointer to the static buffer. */
-char *
+static char *
 st_upper (const char *s)
 {
   char *p, *cp;
@@ -268,7 +228,7 @@ st_upper (const char *s)
 
 /* Returns the address of the first non-whitespace character in S, or
    the address of the null terminator if none. */
-char *
+static char *
 skip_ws (const char *s)
 {
   while (isspace ((unsigned char) *s))
@@ -278,7 +238,7 @@ skip_ws (const char *s)
 
 /* Read one line from the input file into buf.  Lines having special
    formats are handled specially. */
-int
+static int
 get_line (void)
 {
   ln++;
@@ -318,7 +278,7 @@ symbol *symtab;
    in the symbol table, its sequence number is returned and the symbol
    table is not modified.  Otherwise, the symbol is added and the next
    available sequence number is returned. */
-int
+static int
 add_symbol (const char *name, int unique, int value)
 {
   symbol *iter, *sym;
@@ -364,7 +324,7 @@ add_symbol (const char *name, int unique, int value)
 
 /* Finds the symbol having given sequence number X within the symbol
    table, and returns the associated symbol structure. */
-symbol *
+static symbol *
 find_symbol (int x)
 {
   symbol *iter;
@@ -379,10 +339,10 @@ find_symbol (int x)
   return iter;
 }
 
-#if DEBUGGING
+#if DEBUGGING 
 /* Writes a printable representation of the current token to
    stdout. */
-void
+static void
 dump_token (void)
 {
   switch (token)
@@ -400,7 +360,7 @@ dump_token (void)
 #endif /* DEBUGGING */
 
 /* Reads a token from the input file. */
-int
+static int
 lex_get (void)
 {
   /* Skip whitespace and check for end of file. */
@@ -414,15 +374,7 @@ lex_get (void)
        fail ("%s: Unexpected end of file.", ifn);
     }
   
-  if (*cp == '_' || isalnum ((unsigned char) *cp))
-    {
-      char *dest = tokstr;
-      token = T_ID;
-      while (*cp == '_' || isalnum ((unsigned char) *cp))
-       *dest++ = toupper ((unsigned char) (*cp++));
-      *dest++ = '\0';
-    }
-  else if (*cp == '"')
+  if (*cp == '"')
     {
       char *dest = tokstr;
       token = T_STRING;
@@ -444,6 +396,14 @@ lex_get (void)
        error ("Unterminated string literal.");
       cp++;
     }
+  else if (*cp == '_' || isalnum ((unsigned char) *cp))
+    {
+      char *dest = tokstr;
+      token = T_ID;
+      while (*cp == '_' || isalnum ((unsigned char) *cp))
+       *dest++ = toupper ((unsigned char) (*cp++));
+      *dest++ = '\0';
+    }
   else
     token = *cp++;
   
@@ -455,7 +415,7 @@ lex_get (void)
 }
 
 /* Force the current token to be an identifier token. */
-void
+static void
 force_id (void)
 {
   if (token != T_ID)
@@ -463,7 +423,7 @@ force_id (void)
 }
 
 /* Force the current token to be a string token. */
-void
+static void
 force_string (void)
 {
   if (token != T_STRING)
@@ -472,7 +432,7 @@ force_string (void)
 
 /* Checks whether the current token is the identifier S; if so, skips
    the token and returns 1; otherwise, returns 0. */
-int
+static int
 match_id (const char *s)
 {
   if (token == T_ID && !strcmp (tokstr, s))
@@ -485,7 +445,7 @@ match_id (const char *s)
 
 /* Checks whether the current token is T.  If so, skips the token and
    returns 1; otherwise, returns 0. */
-int
+static int
 match_token (int t)
 {
   if (token == t)
@@ -497,7 +457,7 @@ match_token (int t)
 }
 
 /* Force the current token to be T, and skip it. */
-void
+static void
 skip_token (int t)
 {
   if (token != t)
@@ -572,6 +532,13 @@ typedef enum
   }
 subcommand_type;
 
+typedef enum
+  {
+    ARITY_ONCE_EXACTLY,  /* must occur exactly once */
+    ARITY_ONCE_ONLY,     /* zero or once */
+    ARITY_MANY           /* 0, 1, ... , inf */
+  }subcommand_arity;
+
 /* A single subcommand. */
 typedef struct subcommand subcommand;
 struct subcommand
@@ -579,16 +546,27 @@ struct subcommand
     subcommand *next;          /* Next in the chain. */
     char *name;                        /* Subcommand name. */
     subcommand_type type;      /* One of SBC_*. */
-    int once;                  /* 1=Subcommand may appear only once. */
+    subcommand_arity arity;    /* How many times should the subcommand occur*/
     int narray;                        /* Index of next array element. */
     const char *prefix;                /* Prefix for variable and constant names. */
     specifier *spec;           /* Array of specifiers. */
     
-    /* SBC_STRING only. */
+    /* SBC_STRING and SBC_INT only. */
     char *restriction;         /* Expression restricting string length. */
     char *message;             /* Error message. */
+    int translatable;           /* Error message is translatable */
   };
 
+typedef struct aux_subcommand aux_subcommand;
+struct aux_subcommand
+  {
+    aux_subcommand *next;      /* Next in the chain. */
+    char *name;                        /* Subcommand name. */
+    char *value;                /* Subcommand value */
+  };
+
+static aux_subcommand *aux_subcommands ;
+
 /* Name of the command; i.e., DESCRIPTIVES. */
 char *cmdname;
 
@@ -606,7 +584,7 @@ subcommand *def;
 void parse_subcommands (void);
 
 /* Parse an entire specification. */
-void
+static void
 parse (void)
 {
   /* Get the command name and prefix. */
@@ -629,7 +607,7 @@ parse (void)
 
 /* Parses a single setting into S, given subcommand information SBC
    and specifier information SPEC. */
-void
+static void
 parse_setting (setting *s, specifier *spec)
 {
   s->parent = spec;
@@ -700,7 +678,7 @@ parse_setting (setting *s, specifier *spec)
 
 /* Parse a single specifier into SPEC, given subcommand information
    SBC. */
-void
+static void
 parse_specifier (specifier *spec, subcommand *sbc)
 {
   spec->index = 0;
@@ -731,6 +709,15 @@ parse_specifier (specifier *spec, subcommand *sbc)
     }
   skip_token (':');
   
+  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;
@@ -749,7 +736,7 @@ parse_specifier (specifier *spec, subcommand *sbc)
 }
 
 /* Parse a list of specifiers for subcommand SBC. */
-void
+static void
 parse_specifiers (subcommand *sbc)
 {
   specifier **spec = &sbc->spec;
@@ -773,9 +760,11 @@ parse_specifiers (subcommand *sbc)
 }
 
 /* Parse a subcommand into SBC. */
-void
+static void
 parse_subcommand (subcommand *sbc)
 {
+  sbc->arity = ARITY_MANY;
+
   if (match_token ('*'))
     {
       if (def)
@@ -783,7 +772,11 @@ parse_subcommand (subcommand *sbc)
       def = sbc;
     }
 
-  sbc->once = match_token ('+');
+  if ( match_token('+'))
+    sbc->arity = ARITY_ONCE_ONLY ;
+  else if (match_token('^'))
+    sbc->arity = ARITY_ONCE_EXACTLY ;
+
 
   force_id ();
   sbc->name = xstrdup (tokstr);
@@ -792,6 +785,7 @@ parse_subcommand (subcommand *sbc)
   sbc->narray = 0;
   sbc->type = SBC_PLAIN;
   sbc->spec = NULL;
+  sbc->translatable = 0;
 
   if (match_token ('['))
     {
@@ -804,6 +798,7 @@ parse_subcommand (subcommand *sbc)
       
       sbc->type = SBC_ARRAY;
       parse_specifiers (sbc);
+
     }
   else
     {
@@ -837,11 +832,38 @@ parse_subcommand (subcommand *sbc)
          sbc->type = SBC_VARLIST;
        }
       else if (match_id ("INTEGER"))
+       {
        sbc->type = match_id ("LIST") ? SBC_INT_LIST : SBC_INT;
+        if ( token == T_STRING) 
+         {
+             sbc->restriction = xstrdup (tokstr);
+             lex_get ();
+              if ( match_id("N_") )
+              {
+               skip_token('(');
+               force_string ();
+               lex_get();
+               skip_token(')');
+               sbc->translatable = 1;
+              }
+             else {
+               force_string ();
+               lex_get ();
+              }
+             sbc->message = xstrdup (tokstr);
+         }
+       else
+           sbc->restriction = NULL;
+       }
       else if (match_id ("PINT"))
        sbc->type = SBC_PINT;
       else if (match_id ("DOUBLE"))
-       sbc->type = match_id ("LIST") ? SBC_DBL_LIST : SBC_DBL;
+       {
+         if ( match_id ("LIST") )
+           sbc->type = SBC_DBL_LIST;
+         else
+           sbc->type = SBC_DBL;
+       }
       else if (match_id ("STRING"))
        {
          sbc->type = SBC_STRING;
@@ -896,9 +918,7 @@ parse_subcommands (void)
 /* Size of the indent from the left margin. */
 int indent;
 
-#if __GNUC__ >= 2
-void dump (int, const char *, ...) __attribute__ ((format (printf, 2, 3)));
-#endif
+void dump (int, const char *, ...) PRINTF_FORMAT (2, 3);
 
 /* Write line FORMAT to the output file, formatted as with printf,
    indented `indent' characters from the left margin.  If INDENTION is
@@ -928,7 +948,7 @@ dump (int indention, const char *format, ...)
 
 /* Write the structure members for specifier SPEC to the output file.
    SBC is the including subcommand. */
-void
+static void
 dump_specifier_vars (const specifier *spec, const subcommand *sbc)
 {
   if (spec->varname)
@@ -953,7 +973,7 @@ dump_specifier_vars (const specifier *spec, const subcommand *sbc)
 }
 
 /* Returns 1 if string T is a PSPP keyword, 0 otherwise. */
-int
+static int
 is_keyword (const char *t)
 {
   static const char *kw[] =
@@ -972,7 +992,7 @@ is_keyword (const char *t)
 /* Transforms a string NAME into a valid C identifier: makes
    everything lowercase and maps nonalphabetic characters to
    underscores.  Returns a pointer to a static buffer. */
-char *
+static char *
 make_identifier (const char *name)
 {
   char *p = get_buffer ();
@@ -989,7 +1009,7 @@ make_identifier (const char *name)
 }
 
 /* Writes the struct and enum declarations for the parser. */
-void
+static void
 dump_declarations (void)
 {
   indent = 0;
@@ -1039,6 +1059,12 @@ dump_declarations (void)
       }
   }
 
+  /* Write out some type definitions */
+  {
+    dump (0, "#define MAXLISTS 10");
+  }
+
+
   /* For every array subcommand, write out the associated enumerated
      values. */
   {
@@ -1056,7 +1082,6 @@ dump_declarations (void)
            specifier *spec;
 
            for (spec = sbc->spec; spec; spec = spec->next)
-             if (!spec->s)
                dump (0, "%s%s%s = %d,",
                      st_upper (prefix), st_upper (sbc->prefix),
                      st_upper (spec->varname), spec->index);
@@ -1102,8 +1127,12 @@ dump_declarations (void)
                              spec->varname);
                      else if (f == 0)
                        {
-                         dump (0, "int a_%s[%d];", 
-                               st_lower (sbc->name), sbc->narray);
+                         dump (0, "int a_%s[%s%scount];", 
+                               st_lower (sbc->name), 
+                               st_upper (prefix),
+                               st_upper (sbc->prefix)
+                               );
+
                          f = 1;
                        }
                    }
@@ -1131,10 +1160,25 @@ dump_declarations (void)
 
          case SBC_INT:
          case SBC_PINT:
-           dump (0, "long n_%s;", st_lower (sbc->name));
+           dump (0, "long n_%s[MAXLISTS];", st_lower (sbc->name));
+           break;
+
+         case SBC_DBL:
+           dump (0, "double n_%s[MAXLISTS];", st_lower (sbc->name));
            break;
 
-         default:
+         case SBC_DBL_LIST:
+           dump (0, "subc_list_double dl_%s[MAXLISTS];",
+                 st_lower(sbc->name));
+           break;
+
+         case SBC_INT_LIST:
+           dump (0, "subc_list_int il_%s[MAXLISTS];",
+                 st_lower(sbc->name));
+           break;
+
+
+         default:;
            /* nothing */
          }
       }
@@ -1179,7 +1223,7 @@ dump_declarations (void)
 
 /* Writes out code to initialize all the variables that need
    initialization for particular specifier SPEC inside subcommand SBC. */
-void
+static void
 dump_specifier_init (const specifier *spec, const subcommand *sbc)
 {
   if (spec->varname)
@@ -1213,72 +1257,97 @@ dump_specifier_init (const specifier *spec, const subcommand *sbc)
 }
 
 /* Write code to initialize all variables. */
-void
-dump_vars_init (void)
+static void
+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));
-       switch (sbc->type)
+       if ( ! persistent ) 
          {
-         case SBC_DBL:
-         case SBC_INT_LIST:
-         case SBC_DBL_LIST:
-         case SBC_CUSTOM:
-           /* nothing */
-           break;
+           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]) ;",
+                     st_lower (sbc->name)
+                     );
+               dump (-2, "}");
+               break;
+
+             case SBC_DBL:
+               dump (1, "{");
+               dump (0, "int i;");
+               dump (1, "for (i = 0; i < MAXLISTS; ++i)");
+               dump (0, "p->n_%s[i] = SYSMIS;", st_lower (sbc->name));
+               dump (-2, "}");
+               break;
+
+             case SBC_CUSTOM:
+               /* nothing */
+               break;
            
-         case SBC_PLAIN:
-         case SBC_ARRAY:
-           {
-             specifier *spec;
+             case SBC_PLAIN:
+             case SBC_ARRAY:
+               {
+                 specifier *spec;
            
-             for (spec = sbc->spec; spec; spec = spec->next)
-               if (spec->s == NULL)
-                 {
-                   if (sbc->type == SBC_PLAIN)
-                     dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
-                   else if (f == 0)
+                 for (spec = sbc->spec; spec; spec = spec->next)
+                   if (spec->s == NULL)
                      {
-                       dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
-                             st_lower (sbc->name), st_lower (sbc->name));
-                       f = 1;
+                       if (sbc->type == SBC_PLAIN)
+                         dump (0, "p->%s%s = 0;", sbc->prefix, spec->varname);
+                       else if (f == 0)
+                         {
+                           dump (0, "memset (p->a_%s, 0, sizeof p->a_%s);",
+                                 st_lower (sbc->name), st_lower (sbc->name));
+                           f = 1;
+                         }
                      }
-                 }
-               else
-                 dump_specifier_init (spec, sbc);
-           }
-           break;
-
-         case SBC_VARLIST:
-           dump (0, "p->%sn_%s = 0;",
-                 st_lower (sbc->prefix), st_lower (sbc->name));
-           dump (0, "p->%sv_%s = NULL;",
-                 st_lower (sbc->prefix), st_lower (sbc->name));
-           break;
+                   else
+                     dump_specifier_init (spec, sbc);
+               }
+               break;
+
+             case SBC_VARLIST:
+               dump (0, "p->%sn_%s = 0;",
+                     st_lower (sbc->prefix), st_lower (sbc->name));
+               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));
-           break;
-
-         case SBC_STRING:
-           dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
-           break;
-
-         case SBC_INT:
-         case SBC_PINT:
-           dump (0, "p->n_%s = NOT_LONG;", st_lower (sbc->name));
-           break;
-
-         default:
-           assert (0);
+             case SBC_VAR:
+               dump (0, "p->%sv_%s = NULL;",
+                     st_lower (sbc->prefix), st_lower (sbc->name));
+               break;
+
+             case SBC_STRING:
+               dump (0, "p->s_%s = NULL;", st_lower (sbc->name));
+               break;
+
+             case SBC_INT:
+             case SBC_PINT:
+               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 (-2, "}");
+               break;
+
+             default:
+               assert (0);
+             }
          }
       }
   }
@@ -1286,7 +1355,7 @@ dump_vars_init (void)
 
 /* Return a pointer to a static buffer containing an expression that
    will match token T. */
-char *
+static char *
 make_match (const char *t)
 {
   char *s;
@@ -1314,7 +1383,7 @@ make_match (const char *t)
 
 /* Write out the parsing code for specifier SPEC within subcommand
    SBC. */
-void
+static void
 dump_specifier_parse (const specifier *spec, const subcommand *sbc)
 {
   setting *s;
@@ -1344,6 +1413,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
        dump (1, "%sif (%s)", first ? "" : "else ",
              make_match (s->specname));
 
+
       /* Handle values. */
       if (s->value == VAL_NONE)
        dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
@@ -1354,9 +1424,18 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
            dump (1, "{");
          
          if (spec->varname)
-           dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
-                 st_upper (prefix), find_symbol (s->con)->name);
-         
+           {
+             dump (0, "p->%s%s = %s%s;", sbc->prefix, spec->varname,
+                   st_upper (prefix), find_symbol (s->con)->name);
+
+             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),
+                     st_upper (spec->varname));
+           }
+
+
          if (s->valtype == VT_PAREN)
            {
              if (s->optvalue)
@@ -1379,7 +1458,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
 
          if (s->value == VAL_INT)
            {
-             dump (1, "if (!lex_integer_p ())");
+             dump (1, "if (!lex_is_integer ())");
              dump (1, "{");
              dump (0, "msg (SE, _(\"%s specifier of %s subcommand "
                    "requires an integer argument.\"));",
@@ -1391,7 +1470,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
            }
          else
            {
-             dump (1, "if (token != T_NUM)");
+             dump (1, "if (!lex_is_number ())");
              dump (1, "{");
              dump (0, "msg (SE, _(\"Number expected after %s "
                    "specifier of %s subcommand.\"));",
@@ -1458,7 +1537,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
 }
 
 /* Write out the code to parse subcommand SBC. */
-void
+static void
 dump_subcommand (const subcommand *sbc)
 {
   if (sbc->type == SBC_PLAIN || sbc->type == SBC_ARRAY)
@@ -1529,7 +1608,7 @@ dump_subcommand (const subcommand *sbc)
     }
   else if (sbc->type == SBC_VARLIST)
     {
-      dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
+      dump (1, "if (!parse_variables (default_dict, &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),
@@ -1542,7 +1621,7 @@ dump_subcommand (const subcommand *sbc)
     {
       dump (0, "p->%sv_%s = parse_variable ();",
            st_lower (sbc->prefix), st_lower (sbc->name));
-      dump (1, "if (p->%sv_%s)",
+      dump (1, "if (!p->%sv_%s)",
            st_lower (sbc->prefix), st_lower (sbc->name));
       dump (0, "goto lossage;");
       outdent ();
@@ -1568,17 +1647,44 @@ dump_subcommand (const subcommand *sbc)
          dump (-1, "}");
          outdent ();
        }
-      dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
+      dump (0, "free(p->s_%s);", st_lower(sbc->name) );
+      dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
            st_lower (sbc->name));
       dump (0, "lex_get ();");
       if (sbc->restriction)
        dump (-1, "}");
     }
+  else if (sbc->type == SBC_DBL)
+    {
+      dump (1, "if (!lex_force_num ())");
+      dump (0, "goto lossage;");
+      dump (-1, "p->n_%s[p->sbc_%s - 1] = lex_number ();", 
+           st_lower (sbc->name), st_lower (sbc->name) );
+      dump (0, "lex_get();");
+    }
   else if (sbc->type == SBC_INT)
     {
+      dump(1, "{");
+      dump(0, "int x;");
       dump (1, "if (!lex_force_int ())");
       dump (0, "goto lossage;");
-      dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
+      dump (-1, "x = lex_integer ();");
+      dump (0, "lex_get();");
+      if (sbc->restriction)
+       {
+         char buf[1024];
+         dump (1, "if (!(%s))", sbc->restriction);
+         dump (1, "{"); 
+          sprintf(buf,sbc->message,sbc->name);
+         if ( sbc->translatable ) 
+                 dump (0, "msg (SE, gettext(\"%s\"));",buf);
+         else
+                 dump (0, "msg (SE, \"%s\");",buf);
+         dump (0, "goto lossage;");
+         dump (-1, "}");
+      }
+      dump (0, "p->n_%s[p->sbc_%s - 1] = x;", st_lower (sbc->name), st_lower(sbc->name) );
+      dump (-1,"}");
     }
   else if (sbc->type == SBC_PINT)
     {
@@ -1588,6 +1694,30 @@ dump_subcommand (const subcommand *sbc)
       dump (-1, "p->n_%s = lex_integer ();", st_lower (sbc->name));
       dump (0, "lex_match (')');");
     }
+  else if (sbc->type == SBC_DBL_LIST)
+    {
+      dump (0, "if ( p->sbc_%s > MAXLISTS)",st_lower(sbc->name));
+      dump (1, "{");
+      dump (0, "msg (SE, \"No more than %%d %s subcommands allowed\",MAXLISTS);",st_lower(sbc->name));
+      dump (0, "goto lossage;");
+      dump (-1,"}");
+
+      dump (1, "while (token != '/' && token != '.')");
+      dump (1, "{");
+      dump (0, "lex_match(',');");
+      dump (0, "if (!lex_force_num ())");
+      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, "lex_get();");
+      dump (-1,"}");
+
+    }
   else if (sbc->type == SBC_CUSTOM)
     {
       dump (1, "switch (%scustom_%s (p))",
@@ -1611,8 +1741,8 @@ dump_subcommand (const subcommand *sbc)
 }
 
 /* Write out entire parser. */
-void
-dump_parser (void)
+static void
+dump_parser (int persistent)
 {
   int f;
 
@@ -1623,7 +1753,7 @@ dump_parser (void)
        make_identifier (cmdname));
   dump (1, "{");
 
-  dump_vars_init ();
+  dump_vars_init (persistent);
 
   dump (1, "for (;;)");
   dump (1, "{");
@@ -1632,17 +1762,19 @@ dump_parser (void)
   if (def && (def->type == SBC_VARLIST))
     {
       if (def->type == SBC_VARLIST)
-       dump (1, "if (token == T_ID && is_varname (tokid) && "
-             "lex_look_ahead () != '=')");
+       dump (1, "if (token == T_ID "
+              "&& dict_lookup_var (default_dict, tokid) != NULL "
+             "&& lex_look_ahead () != '=')");
       else
        {
-         dump (0, "if ((token == T_ID && is_varname (tokid) && "
-               "lex_look_ahead () != '=')");
+         dump (0, "if ((token == T_ID "
+                "&& dict_lookup_var (default_dict, tokid) "
+               "&& lex_look_ahead () != '=')");
          dump (1, "     || token == T_ALL)");
        }
       dump (1, "{");
       dump (0, "p->sbc_%s++;", st_lower (def->name));
-      dump (1, "if (!parse_variables (NULL, &p->%sv_%s, &p->%sn_%s, "
+      dump (1, "if (!parse_variables (default_dict, &p->%sv_%s, &p->%sn_%s, "
            "PV_APPEND))",
            st_lower (def->prefix), st_lower (def->name),
            st_lower (def->prefix), st_lower (def->name));
@@ -1683,7 +1815,7 @@ dump_parser (void)
 
        dump (0, "lex_match ('=');");
        dump (0, "p->sbc_%s++;", st_lower (sbc->name));
-       if (sbc->once)
+       if (sbc->arity != ARITY_MANY)
          {
            dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
            dump (1, "{");
@@ -1698,6 +1830,24 @@ dump_parser (void)
        outdent ();
       }
   }
+
+
+  /* Now deal with the /ALGORITHM subcommand implicit to all commands */
+  dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
+  dump(1,"{");
+
+  dump (0, "lex_match ('=');");
+
+  dump(1,"if (lex_match_id(\"COMPATIBLE\"))");
+  dump(0,"set_cmd_algorithm(COMPATIBLE);");
+  outdent();
+  dump(1,"else if (lex_match_id(\"ENHANCED\"))");
+  dump(0,"set_cmd_algorithm(ENHANCED);");
+
+  dump (-1, "}");
+  outdent ();
+
+
   
   dump (1, "if (!lex_match ('/'))");
   dump (0, "break;");
@@ -1710,6 +1860,29 @@ dump_parser (void)
   dump (0, "goto lossage;");
   dump (-1, "}");
   dump (0, nullstr);
+
+  outdent ();
+
+  {
+    /*  Check that mandatory subcommands have been specified  */
+    subcommand *sbc;
+
+    for (sbc = subcommands; sbc; sbc = sbc->next)
+      {
+
+       if ( sbc->arity == ARITY_ONCE_EXACTLY ) 
+         {
+           dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
+           dump (1, "{");
+           dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
+                 sbc->name);
+           dump (0, "goto lossage;");
+           dump (-1, "}");
+           dump (0, nullstr);
+         }
+      }
+  }
+
   dump (-1, "return 1;");
   dump (0, nullstr);
   dump (-1, "lossage:");
@@ -1720,8 +1893,155 @@ dump_parser (void)
   dump (0, nullstr);
 }
 
+
+/* Write out the code to parse aux subcommand SBC. */
+static void
+dump_aux_subcommand (const subcommand *sbc)
+{
+  if (sbc->type == SBC_PLAIN )
+    {
+      specifier *spec;
+       
+      for (spec = sbc->spec; spec; spec = spec->next)
+       {
+         char buf[80];
+         sprintf(buf,"p->%s%s",st_lower(sbc->prefix),spec->varname);
+
+         dump (0, "msg(MM,\"%s is %%s\",",sbc->name);
+         dump (0, "(%s < 1000)?\"not set\":settings[%s - 1000]", buf, buf);
+      
+         dump (0, ");");
+       }
+    }
+  else if (sbc->type == SBC_STRING)
+    {
+      dump (0, "msg(MM,\"%s is \\\"%%s\\\"\",p->s_%s);", sbc->name,st_lower(sbc->name) );
+    }
+  else if (sbc->type == SBC_INT)
+    {
+      dump (1, "{");
+      dump (0, "int i;");
+      dump (1, "for (i = 0; i < MAXLISTS; ++i)");
+      dump (0, "msg(MM,\"%s is %%ld\",p->n_%s[i]);", sbc->name,st_lower(sbc->name) ); 
+      outdent();
+      dump (-1, "}");
+    }
+  else if (sbc->type == SBC_CUSTOM)
+    {
+      dump (0, "aux_%scustom_%s(p);",st_lower(prefix),make_identifier(sbc->name));
+    }
+  else
+    assert(0);
+}
+
+
+
+/* Write out auxilliary parser. */
+static void
+dump_aux_parser (void)
+{
+  int f=0;
+  subcommand *sbc;
+  aux_subcommand *asbc;
+
+  /* Write out English strings for all the identifiers in the symbol table. */
+  {
+    int f, k;
+    symbol *sym;
+    char *buf = NULL;
+
+    /* Note the squirmings necessary to make sure that the last string
+       is not followed by a comma (is it necessary to do that ?? ) */
+    for (sym = symtab, f = k = 0; sym; sym = sym->next)
+      if (!sym->unique && !is_keyword (sym->name))
+       {
+         if (!f)
+           {
+             dump (0, "/* Strings for subcommand specifiers. */");
+             dump (1, "static const char *settings[]=");
+             dump (1, "{");
+             f = 1;
+           }
+
+         if (buf == NULL)
+           buf = xmalloc (1024);
+         else
+           dump (0, buf);
+
+         sprintf (buf, "\"%s\",",sym->name);
+       }
+    if (buf)
+      {
+       buf[strlen (buf) - 1] = 0;
+       dump (0, buf);
+       free (buf);
+      }
+    if (f)
+      {
+       dump (-1, "};");
+       dump (-1, nullstr);
+      }
+  }
+
+  
+  indent = 0;
+
+  dump (0, "static int");
+  dump (0, "aux_parse_%s (struct cmd_%s *p)", make_identifier (cmdname),
+       make_identifier (cmdname));
+  dump (1, "{");
+
+  dump (1, "for (;;)");
+  dump (1, "{");
+
+
+  for (sbc = subcommands; sbc; sbc = sbc->next)
+    {
+      dump (1, "%sif (%s)", f ? "else " : "", make_match (sbc->name));
+      f = 1;
+      dump (1, "{");
+
+      dump_aux_subcommand (sbc);
+
+      dump (-1, "}");
+      outdent ();
+    }
+
+  for (asbc = aux_subcommands ; asbc ; asbc = asbc->next)
+    {
+      dump (1, "%sif (%s)", f ? "else " : "", make_match (asbc->name));
+      f = 1;
+      dump (1, "{");
+      dump(0,"aux_%s();",make_identifier(asbc->value));
+      dump (-1, "}");
+      outdent ();
+    }
+  
+  dump (1, "if (!lex_match ('/'))");
+  dump (0, "break;");
+  dump (-2, "}");
+  outdent ();
+  dump (0, nullstr);
+  dump (1, "if (token != '.')");
+  dump (1, "{");
+  dump (0, "lex_error (_(\"expecting end of command\"));");
+  dump (0, "goto lossage;");
+  dump (-1, "}");
+  dump (0, nullstr);
+  dump (-1, "return 1;");
+  dump (0, nullstr);
+  dump (-1, "lossage:");
+  indent ();
+  dump (0, "free_%s (p);", make_identifier (cmdname));
+  dump (0, "return 0;");
+  dump (-1, "} /* aux_parse_%s (struct cmd_%s *p) */", 
+       make_identifier (cmdname), make_identifier (cmdname));
+  dump (0, nullstr);
+}
+
+
 /* Write the output file header. */
-void
+static void
 dump_header (void)
 {
   time_t curtime;
@@ -1733,17 +2053,16 @@ dump_header (void)
   loctime = localtime (&curtime);
   timep = asctime (loctime);
   timep[strlen (timep) - 1] = 0;
-  dump (0,   "/* %s", ofn);
+  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 (0, "   Do not modify!");
   dump (0, " */");
-  dump (0, nullstr);
 }
 
 /* Write out commands to free variable state. */
-void
-dump_free (void)
+static void
+dump_free (int persistent)
 {
   subcommand *sbc;
   int used;
@@ -1751,25 +2070,57 @@ dump_free (void)
   indent = 0;
 
   used = 0;
-  for (sbc = subcommands; sbc; sbc = sbc->next)
-    if (sbc->type == SBC_STRING)
-      used = 1;
+  if ( ! persistent ) 
+    {
+      for (sbc = subcommands; sbc; sbc = sbc->next)
+       {
+       if (sbc->type == SBC_STRING)
+         used = 1;
+       if (sbc->type == SBC_DBL_LIST)
+         used = 1;
+       }
+
+    }
 
   dump (0, "static void");
   dump (0, "free_%s (struct cmd_%s *p%s)", make_identifier (cmdname),
-       make_identifier (cmdname), used ? "" : " unused");
+       make_identifier (cmdname), used ? "" : " UNUSED");
   dump (1, "{");
 
-  for (sbc = subcommands; sbc; sbc = sbc->next)
-    if (sbc->type == SBC_STRING)
-      dump (0, "free (p->s_%s);", st_lower (sbc->name));
+  if ( ! persistent ) 
+    {
+
+      for (sbc = subcommands; sbc; sbc = sbc->next)
+       {
+         switch (sbc->type) 
+           {
+            case SBC_VARLIST:
+             dump (0, "free (p->v_variables);");
+              break;
+           case SBC_STRING:
+             dump (0, "free (p->s_%s);", st_lower (sbc->name));
+             break;
+           case SBC_DBL_LIST:
+             dump (0, "int i;");
+             dump (1, "for(i = 0; i < MAXLISTS ; ++i)");
+             dump (0, "subc_list_double_destroy(&p->dl_%s[i]);", st_lower (sbc->name));
+             outdent();
+             break;
+           default:
+             break;
+           }
+       }
+    }
 
   dump (-1, "}");
+
 }
 
+
+
 /* Returns the name of a directive found on the current input line, if
    any, or a null pointer if none found. */
-const char *
+static const char *
 recognize_directive (void)
 {
   static char directive[16];
@@ -1794,6 +2145,8 @@ recognize_directive (void)
   return directive;
 }
   
+static void aux_parse (void);
+
 int
 main (int argc, char *argv[])
 {
@@ -1817,6 +2170,7 @@ main (int argc, char *argv[])
 
   dump_header ();
 
+
   indent = 0;
   dump (0, "#line %d \"%s\"", ln + 1, ifn);
   while (get_line ())
@@ -1828,7 +2182,7 @@ main (int argc, char *argv[])
          continue;
        }
       
-      dump (0, "#line %d \"%s\"", oln - 1, ofn);
+      dump (0, "#line %d \"%s\"", oln + 1, ofn);
       if (!strcmp (directive, "specification"))
        {
          /* Skip leading slash-star line. */
@@ -1844,21 +2198,33 @@ main (int argc, char *argv[])
        {
          indent = 0;
 
-         dump (0, "#include <assert.h>");
          dump (0, "#include <stdlib.h>");
          dump (0, "#include \"alloc.h\"");
          dump (0, "#include \"error.h\"");
          dump (0, "#include \"lexer.h\"");
+          dump (0, "#include \"settings.h\"");
          dump (0, "#include \"str.h\"");
+          dump (0, "#include \"subclist.h\"");
          dump (0, "#include \"var.h\"");
+
          dump (0, nullstr);
        }
       else if (!strcmp (directive, "declarations"))
        dump_declarations ();
       else if (!strcmp (directive, "functions"))
        {
-         dump_parser ();
-         dump_free ();
+         dump_parser (0);
+         dump_free (0); 
+       }
+      else if (!strcmp (directive, "_functions"))
+       {
+         dump_parser (1);
+         dump_free (1); 
+       }
+      else if (!strcmp (directive, "aux_functions"))
+       {
+         aux_parse();
+         dump_aux_parser ();
        }
       else
        error ("unknown directive `%s'", directive);
@@ -1866,6 +2232,38 @@ main (int argc, char *argv[])
       dump (0, "#line %d \"%s\"", ln + 1, ifn);
     }
 
+
+
   return EXIT_SUCCESS;
 }
 
+/* Parse an entire auxilliary specification. */
+static void
+aux_parse (void)
+{
+  aux_subcommand *sbc;
+  aux_subcommand *prevsbc = 0 ;
+  get_line();
+  lex_get();
+
+  for (;;)
+    {
+       sbc = xmalloc(sizeof(aux_subcommand));
+       sbc->next = prevsbc;
+        sbc->name = xstrdup (tokstr);
+       lex_get();
+       skip_token('=');
+       sbc->value = xstrdup (tokstr);
+       lex_get();
+      if (token == '.')
+       break;
+       skip_token(';');
+       prevsbc = sbc;
+
+    }
+  /* Skip trailing star-slash line. */
+  get_line ();
+  aux_subcommands = sbc;
+}
+
+