Index: doc/q2c.texi
===================================================================
RCS file: /cvsroot/pspp/pspp/doc/q2c.texi,v
retrieving revision 1.5
diff -u -p -r1.5 q2c.texi
--- doc/q2c.texi	5 Jul 2006 05:14:30 -0000	1.5
+++ doc/q2c.texi	14 Apr 2007 04:53:20 -0000
@@ -112,15 +112,23 @@ themselves.
 The syntax of the grammar rules is as follows:
 
 @example
-grammar-rules ::= ID : subcommands .
+grammar-rules ::= command-name opt-prefix : subcommands .
+command-name ::= ID
+             ::= STRING
+opt-prefix ::=
+           ::= ( ID )
 subcommands ::= subcommand
             ::= subcommands ; subcommand
 @end example
 
-The syntax begins with an ID or STRING token that gives the name of the
-procedure to be parsed.  The rest of the syntax consists of subcommands
-separated by semicolons (@samp{;}) and terminated with a full stop
-(@samp{.}).
+The syntax begins with an ID token that gives the name of the
+procedure to be parsed.  For command names that contain multiple
+words, a STRING token may be used instead, e.g.@: @samp{"FILE
+HANDLE"}.  Optionally, an ID in parentheses specifies a prefix used
+for all file-scope identifiers declared by the emitted code.
+
+The rest of the syntax consists of subcommands separated by semicolons
+(@samp{;}) and terminated with a full stop (@samp{.}).
 
 @example
 subcommand ::= default-opt arity-opt ID sbc-defn
@@ -132,8 +140,6 @@ arity-opt ::=
 sbc-defn ::= opt-prefix = specifiers
          ::= [ ID ] = array-sbc
          ::= opt-prefix = sbc-special-form
-opt-prefix ::=
-           ::= ( ID )
 @end example
 
 A subcommand that begins with an asterisk (@samp{*}) is the default
@@ -211,14 +217,16 @@ setting-value-options ::=
                       ::= *
 setting-value-type ::= N
                    ::= D
+                   ::= S
 setting-value-restriction ::= 
                           ::= , STRING
 @end example
 
 Settings may have values.  If the value must be enclosed in parentheses,
 then enclose the value declaration in parentheses.  Declare the setting
-type as @samp{n} or @samp{d} for integer or floating point type,
-respectively.  The given @code{ID} is used to construct a variable name.
+type as @samp{n}, @samp{d}, or @samp{s} for integer, floating-point,
+or string type, respectively.  The given @code{ID} is used to
+construct a variable name.
 If option @samp{*} is given, then the value is optional; otherwise it
 must be specified whenever the corresponding setting is specified.  A
 ``restriction'' can also be specified which is a string giving a C
Index: src/language/lexer/q2c.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/lexer/q2c.c,v
retrieving revision 1.21
diff -u -p -r1.21 q2c.c
--- src/language/lexer/q2c.c	16 Feb 2007 19:24:25 -0000	1.21
+++ src/language/lexer/q2c.c	14 Apr 2007 04:53:21 -0000
@@ -472,7 +472,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. */
@@ -642,8 +643,10 @@ parse_setting (setting *s, specifier *sp
 	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 (':');
       
@@ -952,8 +955,11 @@ dump_specifier_vars (const specifier *sp
 	  {
 	    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));
 	  }
@@ -1003,6 +1009,8 @@ dump_declarations (void)
 {
   indent = 0;
 
+  dump (0, "struct dataset;");
+
   /* Write out enums for all the identifiers in the symbol table. */
   {
     int f, k;
@@ -1236,8 +1244,11 @@ dump_specifier_init (const specifier *sp
 	  {
 	    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 ? "NOT_LONG"
+                    : s->value == VAL_DBL ? "SYSMIS"
+                    : "NULL");
 
 	    dump (0, "p->%s%s = %s;", sbc->prefix, st_lower (s->valname), init);
 	  }
@@ -1457,7 +1468,7 @@ dump_specifier_parse (const specifier *s
 	      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 (lexer))");
 	      dump (1, "{");
@@ -1469,6 +1480,22 @@ dump_specifier_parse (const specifier *s
 	      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_token (lexer) != T_STRING)");
+              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 = xstrdup (ds_cstr (lex_tokstr (lexer)));",
+                    sbc->prefix, st_lower (s->valname));
+            }
+          else
+            abort ();
 	  
 	  if (s->restriction)
 	    {
@@ -1911,10 +1938,10 @@ dump_free (int persistent)
     {
       for (sbc = subcommands; sbc; sbc = sbc->next)
 	{
-	if (sbc->type == SBC_STRING)
-	  used = 1;
-	if (sbc->type == SBC_DBL_LIST)
-	  used = 1;
+          if (sbc->type == SBC_STRING)
+            used = 1;
+          if (sbc->type == SBC_DBL_LIST)
+            used = 1;
 	}
 
     }
@@ -1945,6 +1972,17 @@ dump_free (int persistent)
               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;
 	    }
@@ -2042,6 +2080,7 @@ main (int argc, char *argv[])
 	  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/magic.h>");
 	  dump (0, "#include <libpspp/str.h>");
           dump (0, "#include <language/lexer/subcommand-list.h>");
 	  dump (0, "#include <data/variable.h>");
