]> git.saurik.com Git - bison.git/blobdiff - src/reader.c
* src/lex.c (percent_table): Add tok_define.
[bison.git] / src / reader.c
index 1dfe020b588343831a07b5ea140c5873fab6c1a4..7e23c0ef94a6537c4554bc9b29928734e6635eda 100644 (file)
@@ -1,5 +1,5 @@
 /* Input parser for bison
 /* Input parser for bison
-   Copyright (C) 1984, 1986, 1989, 1992, 1998, 2000
+   Copyright 1984, 1986, 1989, 1992, 1998, 2000
    Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
    Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
@@ -21,6 +21,9 @@
 
 
 #include "system.h"
 
 
 #include "system.h"
+#include "obstack.h"
+#include "quotearg.h"
+#include "quote.h"
 #include "getargs.h"
 #include "files.h"
 #include "xalloc.h"
 #include "getargs.h"
 #include "files.h"
 #include "xalloc.h"
 #include "reader.h"
 #include "conflicts.h"
 
 #include "reader.h"
 #include "conflicts.h"
 
-extern char *printable_version PARAMS ((int));
-
-#define        LTYPESTR        "\
-\n\
-#ifndef YYLTYPE\n\
-typedef\n\
-  struct yyltype\n\
-\
-    {\n\
-      int timestamp;\n\
-      int first_line;\n\
-      int first_column;\
-\n\
-      int last_line;\n\
-      int last_column;\n\
-      char *text;\n\
-   }\n\
-\
-  yyltype;\n\
-\n\
-#define YYLTYPE yyltype\n\
-#endif\n\
-\n"
-
 /* Number of slots allocated (but not necessarily used yet) in `rline'  */
 static int rline_allocated;
 
 /* Number of slots allocated (but not necessarily used yet) in `rline'  */
 static int rline_allocated;
 
@@ -78,17 +57,14 @@ static bucket *startval;
    they must be unions.  */
 static int value_components_used;
 
    they must be unions.  */
 static int value_components_used;
 
-static int typed;              /* nonzero if %union has been seen.  */
-
-static int lastprec;           /* incremented for each %left, %right or %nonassoc seen */
+/* Nonzero if %union has been seen.  */
+static int typed;
 
 
-static int gensym_count;       /* incremented for each generated symbol */
+/* Incremented for each %left, %right or %nonassoc seen */
+static int lastprec;
 
 static bucket *errtoken;
 static bucket *undeftoken;
 
 static bucket *errtoken;
 static bucket *undeftoken;
-
-/* Nonzero if any action or guard uses the @n construct.  */
-static int yylsp_needed;
 \f
 
 /*===================\
 \f
 
 /*===================\
@@ -140,17 +116,52 @@ read_signed_integer (FILE *stream)
   return sign * n;
 }
 \f
   return sign * n;
 }
 \f
-/*-------------------------------------------------------------------.
-| Dump the string from FINPUT to FOUTPUT.  MATCH is the delimiter of |
-| the string (either ' or ").                                        |
-`-------------------------------------------------------------------*/
+/*--------------------------------------------------------------.
+| Get the data type (alternative in the union) of the value for |
+| symbol N in rule RULE.                                        |
+`--------------------------------------------------------------*/
+
+static char *
+get_type_name (int n, symbol_list * rule)
+{
+  int i;
+  symbol_list *rp;
+
+  if (n < 0)
+    {
+      complain (_("invalid $ value"));
+      return NULL;
+    }
+
+  rp = rule;
+  i = 0;
+
+  while (i < n)
+    {
+      rp = rp->next;
+      if (rp == NULL || rp->sym == NULL)
+       {
+         complain (_("invalid $ value"));
+         return NULL;
+       }
+      i++;
+    }
+
+  return rp->sym->type_name;
+}
+\f
+/*------------------------------------------------------------.
+| Dump the string from FIN to OOUT if non null.  MATCH is the |
+| delimiter of the string (either ' or ").                    |
+`------------------------------------------------------------*/
 
 static inline void
 
 static inline void
-copy_string (FILE *fin, FILE *fout, int match)
+copy_string (FILE *fin, struct obstack *oout, int match)
 {
   int c;
 
 {
   int c;
 
-  putc (match, fout);
+  obstack_1grow (oout, match);
+
   c = getc (fin);
 
   while (c != match)
   c = getc (fin);
 
   while (c != match)
@@ -165,14 +176,15 @@ copy_string (FILE *fin, FILE *fout, int match)
          continue;
        }
 
          continue;
        }
 
-      putc (c, fout);
+      obstack_1grow (oout, c);
 
       if (c == '\\')
        {
          c = getc (fin);
          if (c == EOF)
            fatal (_("unterminated string at end of file"));
 
       if (c == '\\')
        {
          c = getc (fin);
          if (c == EOF)
            fatal (_("unterminated string at end of file"));
-         putc (c, fout);
+         obstack_1grow (oout, c);
+
          if (c == '\n')
            lineno++;
        }
          if (c == '\n')
            lineno++;
        }
@@ -180,27 +192,47 @@ copy_string (FILE *fin, FILE *fout, int match)
       c = getc (fin);
     }
 
       c = getc (fin);
     }
 
-  putc (c, fout);
+  obstack_1grow (oout, c);
 }
 
 
 }
 
 
-/*---------------------------------------------------------------.
-| Dump the comment from IN to OUT1 and OUT2.  C is either `*' or |
-| `/', depending upon the type of comments used.  OUT2 might be  |
-| NULL.                                                          |
-`---------------------------------------------------------------*/
+/*-----------------------------------------------------------------.
+| Dump the wannabee comment from IN to OUT1 and OUT2 (which can be |
+| NULL).  In fact we just saw a `/', which might or might not be a |
+| comment.  In any case, copy what we saw.                         |
+|                                                                  |
+| OUT2 might be NULL.                                              |
+`-----------------------------------------------------------------*/
 
 static inline void
 
 static inline void
-copy_comment2 (FILE *in, FILE *out1, FILE *out2, int c)
+copy_comment2 (FILE *fin, struct obstack *oout1, struct obstack *oout2)
 {
   int cplus_comment;
   int ended;
 {
   int cplus_comment;
   int ended;
+  int c;
+
+  /* We read a `/', output it. */
+  obstack_1grow (oout1, '/');
+  if (oout2)
+    obstack_1grow (oout2, '/');
+
+  switch ((c = getc (fin)))
+    {
+    case '/':
+      cplus_comment = 1;
+      break;
+    case '*':
+      cplus_comment = 0;
+      break;
+    default:
+      ungetc (c, fin);
+      return;
+    }
 
 
-  cplus_comment = (c == '/');
-  putc (c, out1);
-  if (out2)
-    putc (c, out2);
-  c = getc (in);
+  obstack_1grow (oout1, c);
+  if (oout2)
+    obstack_1grow (oout2, c);
+  c = getc (fin);
 
   ended = 0;
   while (!ended)
 
   ended = 0;
   while (!ended)
@@ -209,73 +241,73 @@ copy_comment2 (FILE *in, FILE *out1, FILE *out2, int c)
        {
          while (c == '*')
            {
        {
          while (c == '*')
            {
-             putc (c, out1);
-             if (out2)
-               putc (c, out2);
-             c = getc (in);
+             obstack_1grow (oout1, c);
+             if (oout2)
+               obstack_1grow (oout2, c);
+             c = getc (fin);
            }
 
          if (c == '/')
            {
            }
 
          if (c == '/')
            {
-             putc (c, out1);
-             if (out2)
-               putc (c, out2);
+             obstack_1grow (oout1, c);
+             if (oout2)
+               obstack_1grow (oout2, c);
              ended = 1;
            }
        }
       else if (c == '\n')
        {
          lineno++;
              ended = 1;
            }
        }
       else if (c == '\n')
        {
          lineno++;
-         putc (c, out1);
-         if (out2)
-           putc (c, out2);
+         obstack_1grow (oout1, c);
+         if (oout2)
+           obstack_1grow (oout2, c);
          if (cplus_comment)
            ended = 1;
          else
          if (cplus_comment)
            ended = 1;
          else
-           c = getc (in);
+           c = getc (fin);
        }
       else if (c == EOF)
        fatal (_("unterminated comment"));
       else
        {
        }
       else if (c == EOF)
        fatal (_("unterminated comment"));
       else
        {
-         putc (c, out1);
-         if (out2)
-           putc (c, out2);
-         c = getc (in);
+         obstack_1grow (oout1, c);
+         if (oout2)
+           obstack_1grow (oout2, c);
+         c = getc (fin);
        }
     }
 }
 
 
        }
     }
 }
 
 
-/*------------------------------------------------------------.
-| Dump the comment from FIN to FOUT.  C is either `*' or `/', |
-| depending upon the type of comments used.                   |
-`------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Dump the comment (actually the current string starting with a `/') |
+| from FIN to OOUT.                                                  |
+`-------------------------------------------------------------------*/
 
 static inline void
 
 static inline void
-copy_comment (FILE *fin, FILE *fout, int c)
+copy_comment (FILE *fin, struct obstack *oout)
 {
 {
-  copy_comment2 (fin, fout, NULL, c);
+  copy_comment2 (fin, oout, NULL);
 }
 
 
 /*-----------------------------------------------------------------.
 }
 
 
 /*-----------------------------------------------------------------.
-| FIN is pointing to a location (i.e., a `@').  Output to FOUT a   |
+| FIN is pointing to a location (i.e., a `@').  Output to OOUT a   |
 | reference to this location. STACK_OFFSET is the number of values |
 | in the current rule so far, which says where to find `$0' with   |
 | respect to the top of the stack.                                 |
 `-----------------------------------------------------------------*/
 
 static inline void
 | reference to this location. STACK_OFFSET is the number of values |
 | in the current rule so far, which says where to find `$0' with   |
 | respect to the top of the stack.                                 |
 `-----------------------------------------------------------------*/
 
 static inline void
-copy_at (FILE *fin, FILE *fout, int stack_offset)
+copy_at (FILE *fin, struct obstack *oout, int stack_offset)
 {
   int c;
 
   c = getc (fin);
   if (c == '$')
     {
 {
   int c;
 
   c = getc (fin);
   if (c == '$')
     {
-      fprintf (fout, "yyloc");
-      yylsp_needed = 1;
+      obstack_sgrow (oout, "yyloc");
+      locations_flag = 1;
     }
   else if (isdigit (c) || c == '-')
     {
     }
   else if (isdigit (c) || c == '-')
     {
@@ -284,11 +316,79 @@ copy_at (FILE *fin, FILE *fout, int stack_offset)
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
-      fprintf (fout, "yylsp[%d]", n - stack_offset);
-      yylsp_needed = 1;
+      obstack_fgrow1 (oout, "yylsp[%d]", n - stack_offset);
+      locations_flag = 1;
     }
   else
     }
   else
-    complain (_("@%s is invalid"), printable_version (c));
+    {
+      char buf[] = "@c";
+      buf[1] = c;
+      complain (_("%s is invalid"), quote (buf));
+    }
+}
+
+
+/*-------------------------------------------------------------------.
+| FIN is pointing to a wannabee semantic value (i.e., a `$').        |
+|                                                                    |
+| Possible inputs: $[<TYPENAME>]($|integer)                          |
+|                                                                    |
+| Output to OOUT a reference to this semantic value. STACK_OFFSET is |
+| the number of values in the current rule so far, which says where  |
+| to find `$0' with respect to the top of the stack.                 |
+`-------------------------------------------------------------------*/
+
+static inline void
+copy_dollar (FILE *fin, struct obstack *oout,
+            symbol_list *rule, int stack_offset)
+{
+  int c = getc (fin);
+  const char *type_name = NULL;
+
+  /* Get the type name if explicit. */
+  if (c == '<')
+    {
+      read_type_name (fin);
+      type_name = token_buffer;
+      value_components_used = 1;
+      c = getc (fin);
+    }
+
+  if (c == '$')
+    {
+      obstack_sgrow (oout, "yyval");
+
+      if (!type_name)
+       type_name = get_type_name (0, rule);
+      if (type_name)
+       obstack_fgrow1 (oout, ".%s", type_name);
+      if (!type_name && typed)
+       complain (_("$$ of `%s' has no declared type"),
+                 rule->sym->tag);
+    }
+  else if (isdigit (c) || c == '-')
+    {
+      int n;
+      ungetc (c, fin);
+      n = read_signed_integer (fin);
+
+      if (!type_name && n > 0)
+       type_name = get_type_name (n, rule);
+
+      obstack_fgrow1 (oout, "yyvsp[%d]", n - stack_offset);
+
+      if (type_name)
+       obstack_fgrow1 (oout, ".%s", type_name);
+      if (!type_name && typed)
+       complain (_("$%d of `%s' has no declared type"),
+                 n, rule->sym->tag);
+    }
+  else
+    {
+      char buf[] = "$c";
+      buf[1] = c;
+      complain (_("%s is invalid"), quote (buf));
+    }
 }
 \f
 /*-------------------------------------------------------------------.
 }
 \f
 /*-------------------------------------------------------------------.
@@ -303,8 +403,9 @@ copy_definition (void)
   /* -1 while reading a character if prev char was %. */
   int after_percent;
 
   /* -1 while reading a character if prev char was %. */
   int after_percent;
 
-  if (!nolinesflag)
-    fprintf (fattrs, "#line %d \"%s\"\n", lineno, infile);
+  if (!no_lines_flag)
+    obstack_fgrow2 (&attrs_obstack, "#line %d %s\n",
+                   lineno, quotearg_style (c_quoting_style, infile));
 
   after_percent = 0;
 
 
   after_percent = 0;
 
@@ -315,7 +416,7 @@ copy_definition (void)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         putc (c, fattrs);
+         obstack_1grow (&attrs_obstack, c);
          lineno++;
          break;
 
          lineno++;
          break;
 
@@ -325,22 +426,18 @@ copy_definition (void)
 
        case '\'':
        case '"':
 
        case '\'':
        case '"':
-         copy_string (finput, fattrs, c);
+         copy_string (finput, &attrs_obstack, c);
          break;
 
        case '/':
          break;
 
        case '/':
-         putc (c, fattrs);
-         c = getc (finput);
-         if (c != '*' && c != '/')
-           continue;
-         copy_comment (finput, fattrs, c);
+         copy_comment (finput, &attrs_obstack);
          break;
 
        case EOF:
          fatal ("%s", _("unterminated `%{' definition"));
 
        default:
          break;
 
        case EOF:
          fatal ("%s", _("unterminated `%{' definition"));
 
        default:
-         putc (c, fattrs);
+         obstack_1grow (&attrs_obstack, c);
        }
 
       c = getc (finput);
        }
 
       c = getc (finput);
@@ -349,67 +446,76 @@ copy_definition (void)
        {
          if (c == '}')
            return;
        {
          if (c == '}')
            return;
-         putc ('%', fattrs);
+         obstack_1grow (&attrs_obstack, '%');
        }
       after_percent = 0;
        }
       after_percent = 0;
-
     }
     }
-
 }
 
 
 }
 
 
-/*-----------------------------------------------------------------.
-| Parse what comes after %token or %nterm.  For %token, what_is is |
-| STOKEN and what_is_not is SNTERM.  For %nterm, the arguments are |
-| reversed.                                                        |
-`-----------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Parse what comes after %token or %nterm.  For %token, WHAT_IS is   |
+| token_sym and WHAT_IS_NOT is nterm_sym.  For %nterm, the arguments |
+| are reversed.                                                      |
+`-------------------------------------------------------------------*/
 
 static void
 
 static void
-parse_token_decl (int what_is, int what_is_not)
+parse_token_decl (symbol_class what_is, symbol_class what_is_not)
 {
 {
-  int token = 0;
+  token_t token = 0;
   char *typename = 0;
   char *typename = 0;
-  struct bucket *symbol = NULL;        /* pts to symbol being defined */
-  int k;
 
 
+  /* The symbol being defined.  */
+  struct bucket *symbol = NULL;
+
+  /* After `%token' and `%nterm', any number of symbols maybe be
+     defined.  */
   for (;;)
     {
       int tmp_char = ungetc (skip_white_space (), finput);
 
   for (;;)
     {
       int tmp_char = ungetc (skip_white_space (), finput);
 
+      /* `%' (for instance from `%token', or from `%%' etc.) is the
+        only valid means to end this declaration.  */
       if (tmp_char == '%')
        return;
       if (tmp_char == EOF)
        fatal (_("Premature EOF after %s"), token_buffer);
 
       token = lex ();
       if (tmp_char == '%')
        return;
       if (tmp_char == EOF)
        fatal (_("Premature EOF after %s"), token_buffer);
 
       token = lex ();
-      if (token == COMMA)
+      if (token == tok_comma)
        {
          symbol = NULL;
          continue;
        }
        {
          symbol = NULL;
          continue;
        }
-      if (token == TYPENAME)
+      if (token == tok_typename)
        {
        {
-         k = strlen (token_buffer);
-         typename = XCALLOC (char, k + 1);
-         strcpy (typename, token_buffer);
+         typename = xstrdup (token_buffer);
          value_components_used = 1;
          symbol = NULL;
        }
          value_components_used = 1;
          symbol = NULL;
        }
-      else if (token == IDENTIFIER && *symval->tag == '\"' && symbol)
+      else if (token == tok_identifier && *symval->tag == '\"' && symbol)
        {
        {
+         if (symval->alias)
+           warn (_("symbol `%s' used more than once as a literal string"),
+                 symval->tag);
+         else if (symbol->alias)
+           warn (_("symbol `%s' given more than one literal string"),
+                 symbol->tag);
+         else
+           {
+             symval->class = token_sym;
+             symval->type_name = typename;
+             symval->user_token_number = symbol->user_token_number;
+             symbol->user_token_number = SALIAS;
+             symval->alias = symbol;
+             symbol->alias = symval;
+             /* symbol and symval combined are only one symbol */
+             nsyms--;
+           }
          translations = 1;
          translations = 1;
-         symval->class = STOKEN;
-         symval->type_name = typename;
-         symval->user_token_number = symbol->user_token_number;
-         symbol->user_token_number = SALIAS;
-
-         symval->alias = symbol;
-         symbol->alias = symval;
-         symbol = NULL;
-
-         nsyms--;              /* symbol and symval combined are only one symbol */
+         symbol = NULL;
        }
        }
-      else if (token == IDENTIFIER)
+      else if (token == tok_identifier)
        {
          int oldclass = symval->class;
          symbol = symval;
        {
          int oldclass = symval->class;
          symbol = symval;
@@ -417,7 +523,7 @@ parse_token_decl (int what_is, int what_is_not)
          if (symbol->class == what_is_not)
            complain (_("symbol %s redefined"), symbol->tag);
          symbol->class = what_is;
          if (symbol->class == what_is_not)
            complain (_("symbol %s redefined"), symbol->tag);
          symbol->class = what_is;
-         if (what_is == SNTERM && oldclass != SNTERM)
+         if (what_is == nterm_sym && oldclass != nterm_sym)
            symbol->value = nvars++;
 
          if (typename)
            symbol->value = nvars++;
 
          if (typename)
@@ -428,7 +534,7 @@ parse_token_decl (int what_is, int what_is_not)
                complain (_("type redeclaration for %s"), symbol->tag);
            }
        }
                complain (_("type redeclaration for %s"), symbol->tag);
            }
        }
-      else if (symbol && token == NUMBER)
+      else if (symbol && token == tok_number)
        {
          symbol->user_token_number = numval;
          translations = 1;
        {
          symbol->user_token_number = numval;
          translations = 1;
@@ -436,7 +542,7 @@ parse_token_decl (int what_is, int what_is_not)
       else
        {
          complain (_("`%s' is invalid in %s"),
       else
        {
          complain (_("`%s' is invalid in %s"),
-                   token_buffer, (what_is == STOKEN) ? "%token" : "%nterm");
+                   token_buffer, (what_is == token_sym) ? "%token" : "%nterm");
          skip_to_char ('%');
        }
     }
          skip_to_char ('%');
        }
     }
@@ -444,14 +550,16 @@ parse_token_decl (int what_is, int what_is_not)
 }
 
 
 }
 
 
-/* Parse what comes after %start */
+/*------------------------------.
+| Parse what comes after %start |
+`------------------------------*/
 
 static void
 parse_start_decl (void)
 {
   if (start_flag)
     complain (_("multiple %s declarations"), "%start");
 
 static void
 parse_start_decl (void)
 {
   if (start_flag)
     complain (_("multiple %s declarations"), "%start");
-  if (lex () != IDENTIFIER)
+  if (lex () != tok_identifier)
     complain (_("invalid %s declaration"), "%start");
   else
     {
     complain (_("invalid %s declaration"), "%start");
   else
     {
@@ -460,43 +568,6 @@ parse_start_decl (void)
     }
 }
 
     }
 }
 
-
-
-/*--------------------------------------------------------------.
-| Get the data type (alternative in the union) of the value for |
-| symbol n in rule rule.                                        |
-`--------------------------------------------------------------*/
-
-static char *
-get_type_name (int n, symbol_list * rule)
-{
-  int i;
-  symbol_list *rp;
-
-  if (n < 0)
-    {
-      complain (_("invalid $ value"));
-      return NULL;
-    }
-
-  rp = rule;
-  i = 0;
-
-  while (i < n)
-    {
-      rp = rp->next;
-      if (rp == NULL || rp->sym == NULL)
-       {
-         complain (_("invalid $ value"));
-         return NULL;
-       }
-      i++;
-    }
-
-  return rp->sym->type_name;
-}
-
-
 /*-----------------------------------------------------------.
 | read in a %type declaration and record its information for |
 | get_type_name to access                                    |
 /*-----------------------------------------------------------.
 | read in a %type declaration and record its information for |
 | get_type_name to access                                    |
@@ -505,23 +576,20 @@ get_type_name (int n, symbol_list * rule)
 static void
 parse_type_decl (void)
 {
 static void
 parse_type_decl (void)
 {
-  int k;
   char *name;
 
   char *name;
 
-  if (lex () != TYPENAME)
+  if (lex () != tok_typename)
     {
       complain ("%s", _("%type declaration has no <typename>"));
       skip_to_char ('%');
       return;
     }
 
     {
       complain ("%s", _("%type declaration has no <typename>"));
       skip_to_char ('%');
       return;
     }
 
-  k = strlen (token_buffer);
-  name = XCALLOC (char, k + 1);
-  strcpy (name, token_buffer);
+  name = xstrdup (token_buffer);
 
   for (;;)
     {
 
   for (;;)
     {
-      int t;
+      token_t t;
       int tmp_char = ungetc (skip_white_space (), finput);
 
       if (tmp_char == '%')
       int tmp_char = ungetc (skip_white_space (), finput);
 
       if (tmp_char == '%')
@@ -534,11 +602,11 @@ parse_type_decl (void)
       switch (t)
        {
 
       switch (t)
        {
 
-       case COMMA:
-       case SEMICOLON:
+       case tok_comma:
+       case tok_semicolon:
          break;
 
          break;
 
-       case IDENTIFIER:
+       case tok_identifier:
          if (symval->type_name == NULL)
            symval->type_name = name;
          else if (strcmp (name, symval->type_name) != 0)
          if (symval->type_name == NULL)
            symval->type_name = name;
          else if (strcmp (name, symval->type_name) != 0)
@@ -556,13 +624,14 @@ parse_type_decl (void)
 
 
 
 
 
 
-/* read in a %left, %right or %nonassoc declaration and record its information.  */
-/* assoc is either LEFT_ASSOC, RIGHT_ASSOC or NON_ASSOC.  */
+/*----------------------------------------------------------------.
+| Read in a %left, %right or %nonassoc declaration and record its |
+| information.                                                    |
+`----------------------------------------------------------------*/
 
 static void
 
 static void
-parse_assoc_decl (int assoc)
+parse_assoc_decl (associativity assoc)
 {
 {
-  int k;
   char *name = NULL;
   int prev = 0;
 
   char *name = NULL;
   int prev = 0;
 
@@ -570,7 +639,7 @@ parse_assoc_decl (int assoc)
 
   for (;;)
     {
 
   for (;;)
     {
-      int t;
+      token_t t;
       int tmp_char = ungetc (skip_white_space (), finput);
 
       if (tmp_char == '%')
       int tmp_char = ungetc (skip_white_space (), finput);
 
       if (tmp_char == '%')
@@ -582,24 +651,21 @@ parse_assoc_decl (int assoc)
 
       switch (t)
        {
 
       switch (t)
        {
-
-       case TYPENAME:
-         k = strlen (token_buffer);
-         name = XCALLOC (char, k + 1);
-         strcpy (name, token_buffer);
+       case tok_typename:
+         name = xstrdup (token_buffer);
          break;
 
          break;
 
-       case COMMA:
+       case tok_comma:
          break;
 
          break;
 
-       case IDENTIFIER:
+       case tok_identifier:
          if (symval->prec != 0)
            complain (_("redefining precedence of %s"), symval->tag);
          symval->prec = lastprec;
          symval->assoc = assoc;
          if (symval->prec != 0)
            complain (_("redefining precedence of %s"), symval->tag);
          symval->prec = lastprec;
          symval->assoc = assoc;
-         if (symval->class == SNTERM)
+         if (symval->class == nterm_sym)
            complain (_("symbol %s redefined"), symval->tag);
            complain (_("symbol %s redefined"), symval->tag);
-         symval->class = STOKEN;
+         symval->class = token_sym;
          if (name)
            {                   /* record the type, if one is specified */
              if (symval->type_name == NULL)
          if (name)
            {                   /* record the type, if one is specified */
              if (symval->type_name == NULL)
@@ -609,8 +675,8 @@ parse_assoc_decl (int assoc)
            }
          break;
 
            }
          break;
 
-       case NUMBER:
-         if (prev == IDENTIFIER)
+       case tok_number:
+         if (prev == tok_identifier)
            {
              symval->user_token_number = numval;
              translations = 1;
            {
              symval->user_token_number = numval;
              translations = 1;
@@ -624,7 +690,7 @@ token_buffer);
            }
          break;
 
            }
          break;
 
-       case SEMICOLON:
+       case tok_semicolon:
          return;
 
        default:
          return;
 
        default:
@@ -639,9 +705,11 @@ token_buffer);
 
 
 
 
 
 
-/* copy the union declaration into fattrs (and fdefines),
-   where it is made into the
-   definition of YYSTYPE, the type of elements of the parser value stack.  */
+/*--------------------------------------------------------------.
+| Copy the union declaration into ATTRS_OBSTACK (and fdefines), |
+| where it is made into the definition of YYSTYPE, the type of  |
+| elements of the parser value stack.                           |
+`--------------------------------------------------------------*/
 
 static void
 parse_union_decl (void)
 
 static void
 parse_union_decl (void)
@@ -654,22 +722,23 @@ parse_union_decl (void)
 
   typed = 1;
 
 
   typed = 1;
 
-  if (!nolinesflag)
-    fprintf (fattrs, "\n#line %d \"%s\"\n", lineno, infile);
+  if (!no_lines_flag)
+    obstack_fgrow2 (&attrs_obstack, "\n#line %d %s\n",
+                   lineno, quotearg_style (c_quoting_style, infile));
   else
   else
-    fprintf (fattrs, "\n");
+    obstack_1grow (&attrs_obstack, '\n');
 
 
-  fprintf (fattrs, "typedef union");
-  if (fdefines)
-    fprintf (fdefines, "typedef union");
+  obstack_sgrow (&attrs_obstack, "typedef union");
+  if (defines_flag)
+    obstack_sgrow (&defines_obstack, "typedef union");
 
   c = getc (finput);
 
   while (c != EOF)
     {
 
   c = getc (finput);
 
   while (c != EOF)
     {
-      putc (c, fattrs);
-      if (fdefines)
-       putc (c, fdefines);
+      obstack_1grow (&attrs_obstack, c);
+      if (defines_flag)
+       obstack_1grow (&defines_obstack, c);
 
       switch (c)
        {
 
       switch (c)
        {
@@ -678,13 +747,9 @@ parse_union_decl (void)
          break;
 
        case '/':
          break;
 
        case '/':
-         c = getc (finput);
-         if (c != '*' && c != '/')
-           continue;
-         copy_comment2 (finput, fattrs, fdefines, c);
+         copy_comment2 (finput, &defines_obstack, &attrs_obstack);
          break;
 
          break;
 
-
        case '{':
          count++;
          break;
        case '{':
          count++;
          break;
@@ -695,9 +760,9 @@ parse_union_decl (void)
          count--;
          if (count <= 0)
            {
          count--;
          if (count <= 0)
            {
-             fprintf (fattrs, " YYSTYPE;\n");
-             if (fdefines)
-               fprintf (fdefines, " YYSTYPE;\n");
+             obstack_sgrow (&attrs_obstack, " YYSTYPE;\n");
+             if (defines_flag)
+               obstack_sgrow (&defines_obstack, " YYSTYPE;\n");
              /* JF don't choke on trailing semi */
              c = skip_white_space ();
              if (c != ';')
              /* JF don't choke on trailing semi */
              c = skip_white_space ();
              if (c != ';')
@@ -710,34 +775,22 @@ parse_union_decl (void)
     }
 }
 
     }
 }
 
-/* parse the declaration %expect N which says to expect N
-   shift-reduce conflicts.  */
+
+/*-------------------------------------------------------.
+| Parse the declaration %expect N which says to expect N |
+| shift-reduce conflicts.                                |
+`-------------------------------------------------------*/
 
 static void
 parse_expect_decl (void)
 {
 
 static void
 parse_expect_decl (void)
 {
-  int c;
-  int count;
-  char buffer[20];
-
-  c = getc (finput);
-  while (c == ' ' || c == '\t')
-    c = getc (finput);
-
-  count = 0;
-  while (c >= '0' && c <= '9')
-    {
-      if (count < 20)
-       buffer[count++] = c;
-      c = getc (finput);
-    }
-  buffer[count] = 0;
-
+  int c = skip_white_space ();
   ungetc (c, finput);
 
   ungetc (c, finput);
 
-  if (count <= 0 || count > 10)
-    complain ("%s", _("argument of %expect is not an integer"));
-  expected_conflicts = atoi (buffer);
+  if (!isdigit (c))
+    complain (_("argument of %%expect is not an integer"));
+  else
+    expected_conflicts = read_signed_integer (finput);
 }
 
 
 }
 
 
@@ -764,39 +817,37 @@ parse_expect_decl (void)
 static void
 parse_thong_decl (void)
 {
 static void
 parse_thong_decl (void)
 {
-  int token;
+  token_t token;
   struct bucket *symbol;
   char *typename = 0;
   struct bucket *symbol;
   char *typename = 0;
-  int k, usrtoknum;
+  int usrtoknum;
 
   translations = 1;
   token = lex ();              /* fetch typename or first token */
 
   translations = 1;
   token = lex ();              /* fetch typename or first token */
-  if (token == TYPENAME)
+  if (token == tok_typename)
     {
     {
-      k = strlen (token_buffer);
-      typename = XCALLOC (char, k + 1);
-      strcpy (typename, token_buffer);
+      typename = xstrdup (token_buffer);
       value_components_used = 1;
       token = lex ();          /* fetch first token */
     }
 
   /* process first token */
 
       value_components_used = 1;
       token = lex ();          /* fetch first token */
     }
 
   /* process first token */
 
-  if (token != IDENTIFIER)
+  if (token != tok_identifier)
     {
       complain (_("unrecognized item %s, expected an identifier"),
                token_buffer);
       skip_to_char ('%');
       return;
     }
     {
       complain (_("unrecognized item %s, expected an identifier"),
                token_buffer);
       skip_to_char ('%');
       return;
     }
-  symval->class = STOKEN;
+  symval->class = token_sym;
   symval->type_name = typename;
   symval->user_token_number = SALIAS;
   symbol = symval;
 
   token = lex ();              /* get number or literal string */
 
   symval->type_name = typename;
   symval->user_token_number = SALIAS;
   symbol = symval;
 
   token = lex ();              /* get number or literal string */
 
-  if (token == NUMBER)
+  if (token == tok_number)
     {
       usrtoknum = numval;
       token = lex ();          /* okay, did number, now get literal */
     {
       usrtoknum = numval;
       token = lex ();          /* okay, did number, now get literal */
@@ -806,26 +857,57 @@ parse_thong_decl (void)
 
   /* process literal string token */
 
 
   /* process literal string token */
 
-  if (token != IDENTIFIER || *symval->tag != '\"')
+  if (token != tok_identifier || *symval->tag != '\"')
     {
       complain (_("expected string constant instead of %s"), token_buffer);
       skip_to_char ('%');
       return;
     }
     {
       complain (_("expected string constant instead of %s"), token_buffer);
       skip_to_char ('%');
       return;
     }
-  symval->class = STOKEN;
+  symval->class = token_sym;
   symval->type_name = typename;
   symval->user_token_number = usrtoknum;
 
   symval->alias = symbol;
   symbol->alias = symval;
 
   symval->type_name = typename;
   symval->user_token_number = usrtoknum;
 
   symval->alias = symbol;
   symbol->alias = symval;
 
-  nsyms--;                     /* symbol and symval combined are only one symbol */
+  /* symbol and symval combined are only one symbol.  */
+  nsyms--;
+}
+
+/*------------------------------------------.
+| Parse what comes after %header_extension. |
+`------------------------------------------*/
+
+static void
+parse_header_extension_decl (void)
+{
+  char buff[32];
+
+  if (header_extension)
+    complain (_("multiple %%header_extension declarations"));
+  fscanf (finput, "%s", buff);
+  header_extension = xstrdup (buff);
+}
+
+/*------------------------------------------.
+| Parse what comes after %source_extension. |
+`------------------------------------------*/
+
+static void
+parse_source_extension_decl (void)
+{
+  char buff[32];
+
+  if (src_extension)
+    complain (_("multiple %%source_extension declarations"));
+  fscanf (finput, "%s", buff);
+  src_extension = xstrdup (buff);
 }
 
 /*----------------------------------------------------------------.
 | Read from finput until `%%' is seen.  Discard the `%%'.  Handle |
 | any `%' declarations, and copy the contents of any `%{ ... %}'  |
 }
 
 /*----------------------------------------------------------------.
 | Read from finput until `%%' is seen.  Discard the `%%'.  Handle |
 | any `%' declarations, and copy the contents of any `%{ ... %}'  |
-| groups to fattrs.                                               |
+| groups to ATTRS_OBSTACK.                                        |
 `----------------------------------------------------------------*/
 
 static void
 `----------------------------------------------------------------*/
 
 static void
@@ -844,64 +926,62 @@ read_declarations (void)
 
          switch (tok)
            {
 
          switch (tok)
            {
-           case TWO_PERCENTS:
+           case tok_two_percents:
              return;
 
              return;
 
-           case PERCENT_LEFT_CURLY:
+           case tok_percent_left_curly:
              copy_definition ();
              break;
 
              copy_definition ();
              break;
 
-           case TOKEN:
-             parse_token_decl (STOKEN, SNTERM);
+           case tok_token:
+             parse_token_decl (token_sym, nterm_sym);
              break;
 
              break;
 
-           case NTERM:
-             parse_token_decl (SNTERM, STOKEN);
+           case tok_nterm:
+             parse_token_decl (nterm_sym, token_sym);
              break;
 
              break;
 
-           case TYPE:
+           case tok_type:
              parse_type_decl ();
              break;
 
              parse_type_decl ();
              break;
 
-           case START:
+           case tok_start:
              parse_start_decl ();
              break;
 
              parse_start_decl ();
              break;
 
-           case UNION:
+           case tok_union:
              parse_union_decl ();
              break;
 
              parse_union_decl ();
              break;
 
-           case EXPECT:
+           case tok_expect:
              parse_expect_decl ();
              break;
              parse_expect_decl ();
              break;
-           case THONG:
+
+           case tok_thong:
              parse_thong_decl ();
              break;
              parse_thong_decl ();
              break;
-           case LEFT:
-             parse_assoc_decl (LEFT_ASSOC);
+
+           case tok_left:
+             parse_assoc_decl (left_assoc);
              break;
 
              break;
 
-           case RIGHT:
-             parse_assoc_decl (RIGHT_ASSOC);
+           case tok_right:
+             parse_assoc_decl (right_assoc);
              break;
 
              break;
 
-           case NONASSOC:
-             parse_assoc_decl (NON_ASSOC);
+           case tok_nonassoc:
+             parse_assoc_decl (non_assoc);
              break;
 
              break;
 
-           case SEMANTIC_PARSER:
-             if (semantic_parser == 0)
-               {
-                 semantic_parser = 1;
-                 open_extra_files ();
-               }
+           case tok_hdrext:
+             parse_header_extension_decl ();
              break;
 
              break;
 
-           case PURE_PARSER:
-             pure_parser = 1;
+           case tok_srcext:
+             parse_source_extension_decl ();
              break;
 
              break;
 
-           case NOOP:
+           case tok_noop:
              break;
 
            default:
              break;
 
            default:
@@ -913,7 +993,9 @@ read_declarations (void)
        fatal (_("no input grammar"));
       else
        {
        fatal (_("no input grammar"));
       else
        {
-         complain (_("unknown character: %s"), printable_version (c));
+         char buf[] = "c";
+         buf[0] = c;
+         complain (_("unknown character: %s"), quote (buf));
          skip_to_char ('%');
        }
     }
          skip_to_char ('%');
        }
     }
@@ -927,21 +1009,26 @@ read_declarations (void)
 `-------------------------------------------------------------------*/
 
 static void
 `-------------------------------------------------------------------*/
 
 static void
-copy_action (symbol_list * rule, int stack_offset)
+copy_action (symbol_list *rule, int stack_offset)
 {
   int c;
 {
   int c;
-  int n;
   int count;
   int count;
-  char *type_name;
+  char buf[4096];
 
   /* offset is always 0 if parser has already popped the stack pointer */
   if (semantic_parser)
     stack_offset = 0;
 
 
   /* offset is always 0 if parser has already popped the stack pointer */
   if (semantic_parser)
     stack_offset = 0;
 
-  fprintf (faction, "\ncase %d:\n", nrules);
-  if (!nolinesflag)
-    fprintf (faction, "#line %d \"%s\"\n", lineno, infile);
-  putc ('{', faction);
+  sprintf (buf, "\ncase %d:\n", nrules);
+  obstack_grow (&action_obstack, buf, strlen (buf));
+
+  if (!no_lines_flag)
+    {
+      sprintf (buf, "#line %d %s\n",
+              lineno, quotearg_style (c_quoting_style, infile));
+      obstack_grow (&action_obstack, buf, strlen (buf));
+    }
+  obstack_1grow (&action_obstack, '{');
 
   count = 1;
   c = getc (finput);
 
   count = 1;
   c = getc (finput);
@@ -953,91 +1040,39 @@ copy_action (symbol_list * rule, int stack_offset)
          switch (c)
            {
            case '\n':
          switch (c)
            {
            case '\n':
-             putc (c, faction);
+             obstack_1grow (&action_obstack, c);
              lineno++;
              break;
 
            case '{':
              lineno++;
              break;
 
            case '{':
-             putc (c, faction);
+             obstack_1grow (&action_obstack, c);
              count++;
              break;
 
            case '\'':
            case '"':
              count++;
              break;
 
            case '\'':
            case '"':
-             copy_string (finput, faction, c);
+             copy_string (finput, &action_obstack, c);
              break;
 
            case '/':
              break;
 
            case '/':
-             putc (c, faction);
-             c = getc (finput);
-             if (c != '*' && c != '/')
-               continue;
-             copy_comment (finput, faction, c);
+             copy_comment (finput, &action_obstack);
              break;
 
            case '$':
              break;
 
            case '$':
-             c = getc (finput);
-             type_name = NULL;
-
-             if (c == '<')
-               {
-                 char *cp = token_buffer;
-
-                 while ((c = getc (finput)) != '>' && c > 0)
-                   {
-                     if (cp == token_buffer + maxtoken)
-                       cp = grow_token_buffer (cp);
-
-                     *cp++ = c;
-                   }
-                 *cp = 0;
-                 type_name = token_buffer;
-                 value_components_used = 1;
-
-                 c = getc (finput);
-               }
-             if (c == '$')
-               {
-                 fprintf (faction, "yyval");
-                 if (!type_name)
-                   type_name = get_type_name (0, rule);
-                 if (type_name)
-                   fprintf (faction, ".%s", type_name);
-                 if (!type_name && typed)
-                   complain (_("$$ of `%s' has no declared type"),
-                             rule->sym->tag);
-               }
-             else if (isdigit (c) || c == '-')
-               {
-                 ungetc (c, finput);
-                 n = read_signed_integer (finput);
-                 c = getc (finput);
-
-                 if (!type_name && n > 0)
-                   type_name = get_type_name (n, rule);
-
-                 fprintf (faction, "yyvsp[%d]", n - stack_offset);
-                 if (type_name)
-                   fprintf (faction, ".%s", type_name);
-                 if (!type_name && typed)
-                   complain (_("$%d of `%s' has no declared type"),
-                             n, rule->sym->tag);
-                 continue;
-               }
-             else
-               complain (_("$%s is invalid"), printable_version (c));
-
+             copy_dollar (finput, &action_obstack,
+                          rule, stack_offset);
              break;
 
            case '@':
              break;
 
            case '@':
-             copy_at (finput, faction, stack_offset);
+             copy_at (finput, &action_obstack,
+                      stack_offset);
              break;
 
            case EOF:
              fatal (_("unmatched %s"), "`{'");
 
            default:
              break;
 
            case EOF:
              fatal (_("unmatched %s"), "`{'");
 
            default:
-             putc (c, faction);
+             obstack_1grow (&action_obstack, c);
            }
 
          c = getc (finput);
            }
 
          c = getc (finput);
@@ -1047,12 +1082,12 @@ copy_action (symbol_list * rule, int stack_offset)
 
       if (--count)
        {
 
       if (--count)
        {
-         putc (c, faction);
+         obstack_1grow (&action_obstack, c);
          c = getc (finput);
        }
     }
 
          c = getc (finput);
        }
     }
 
-  fprintf (faction, ";\n    break;}");
+  obstack_sgrow (&action_obstack, ";\n    break;}");
 }
 \f
 /*-------------------------------------------------------------------.
 }
 \f
 /*-------------------------------------------------------------------.
@@ -1065,22 +1100,21 @@ copy_action (symbol_list * rule, int stack_offset)
 `-------------------------------------------------------------------*/
 
 static void
 `-------------------------------------------------------------------*/
 
 static void
-copy_guard (symbol_list * rule, int stack_offset)
+copy_guard (symbol_list *rule, int stack_offset)
 {
   int c;
 {
   int c;
-  int n;
   int count;
   int count;
-  char *type_name;
   int brace_flag = 0;
 
   /* offset is always 0 if parser has already popped the stack pointer */
   if (semantic_parser)
     stack_offset = 0;
 
   int brace_flag = 0;
 
   /* offset is always 0 if parser has already popped the stack pointer */
   if (semantic_parser)
     stack_offset = 0;
 
-  fprintf (fguard, "\ncase %d:\n", nrules);
-  if (!nolinesflag)
-    fprintf (fguard, "#line %d \"%s\"\n", lineno, infile);
-  putc ('{', fguard);
+  obstack_fgrow1 (&guard_obstack, "\ncase %d:\n", nrules);
+  if (!no_lines_flag)
+    obstack_fgrow2 (&guard_obstack, "#line %d %s\n",
+                   lineno, quotearg_style (c_quoting_style, infile));
+  obstack_1grow (&guard_obstack, '{');
 
   count = 0;
   c = getc (finput);
 
   count = 0;
   c = getc (finput);
@@ -1090,18 +1124,18 @@ copy_guard (symbol_list * rule, int stack_offset)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         putc (c, fguard);
+         obstack_1grow (&guard_obstack, c);
          lineno++;
          break;
 
        case '{':
          lineno++;
          break;
 
        case '{':
-         putc (c, fguard);
+         obstack_1grow (&guard_obstack, c);
          brace_flag = 1;
          count++;
          break;
 
        case '}':
          brace_flag = 1;
          count++;
          break;
 
        case '}':
-         putc (c, fguard);
+         obstack_1grow (&guard_obstack, c);
          if (count > 0)
            count--;
          else
          if (count > 0)
            count--;
          else
@@ -1113,79 +1147,26 @@ copy_guard (symbol_list * rule, int stack_offset)
 
        case '\'':
        case '"':
 
        case '\'':
        case '"':
-         copy_string (finput, fguard, c);
+         copy_string (finput, &guard_obstack, c);
          break;
 
        case '/':
          break;
 
        case '/':
-         putc (c, fguard);
-         c = getc (finput);
-         if (c != '*' && c != '/')
-           continue;
-         copy_comment (finput, fguard, c);
+         copy_comment (finput, &guard_obstack);
          break;
 
        case '$':
          break;
 
        case '$':
-         c = getc (finput);
-         type_name = NULL;
-
-         if (c == '<')
-           {
-             char *cp = token_buffer;
-
-             while ((c = getc (finput)) != '>' && c > 0)
-               {
-                 if (cp == token_buffer + maxtoken)
-                   cp = grow_token_buffer (cp);
-
-                 *cp++ = c;
-               }
-             *cp = 0;
-             type_name = token_buffer;
-
-             c = getc (finput);
-           }
-
-         if (c == '$')
-           {
-             fprintf (fguard, "yyval");
-             if (!type_name)
-               type_name = rule->sym->type_name;
-             if (type_name)
-               fprintf (fguard, ".%s", type_name);
-             if (!type_name && typed)
-               complain (_("$$ of `%s' has no declared type"),
-                         rule->sym->tag);
-           }
-         else if (isdigit (c) || c == '-')
-           {
-             ungetc (c, finput);
-             n = read_signed_integer (finput);
-             c = getc (finput);
-
-             if (!type_name && n > 0)
-               type_name = get_type_name (n, rule);
-
-             fprintf (fguard, "yyvsp[%d]", n - stack_offset);
-             if (type_name)
-               fprintf (fguard, ".%s", type_name);
-             if (!type_name && typed)
-               complain (_("$%d of `%s' has no declared type"),
-                         n, rule->sym->tag);
-             continue;
-           }
-         else
-           complain (_("$%s is invalid"), printable_version (c));
+         copy_dollar (finput, &guard_obstack, rule, stack_offset);
          break;
 
        case '@':
          break;
 
        case '@':
-         copy_at (finput, fguard, stack_offset);
+         copy_at (finput, &guard_obstack, stack_offset);
          break;
 
        case EOF:
          fatal ("%s", _("unterminated %guard clause"));
 
        default:
          break;
 
        case EOF:
          fatal ("%s", _("unterminated %guard clause"));
 
        default:
-         putc (c, fguard);
+         obstack_1grow (&guard_obstack, c);
        }
 
       if (c != '}' || count != 0)
        }
 
       if (c != '}' || count != 0)
@@ -1194,7 +1175,7 @@ copy_guard (symbol_list * rule, int stack_offset)
 
   c = skip_white_space ();
 
 
   c = skip_white_space ();
 
-  fprintf (fguard, ";\n    break;}");
+  obstack_sgrow (&guard_obstack, ";\n    break;}");
   if (c == '{')
     copy_action (rule, stack_offset);
   else if (c == '=')
   if (c == '{')
     copy_action (rule, stack_offset);
   else if (c == '=')
@@ -1230,11 +1211,16 @@ record_rule_line (void)
 static bucket *
 gensym (void)
 {
 static bucket *
 gensym (void)
 {
+  /* Incremented for each generated symbol */
+  static int gensym_count = 0;
+  static char buf[256];
+
   bucket *sym;
 
   bucket *sym;
 
-  sprintf (token_buffer, "@%d", ++gensym_count);
+  sprintf (buf, "@%d", ++gensym_count);
+  token_buffer = buf;
   sym = getsym (token_buffer);
   sym = getsym (token_buffer);
-  sym->class = SNTERM;
+  sym->class = nterm_sym;
   sym->value = nvars++;
   return sym;
 }
   sym->value = nvars++;
   return sym;
 }
@@ -1250,34 +1236,32 @@ static int
 get_type (void)
 {
   int k;
 get_type (void)
 {
   int k;
-  int t;
+  token_t token;
   char *name;
 
   char *name;
 
-  t = lex ();
+  token = lex ();
 
 
-  if (t != TYPENAME)
+  if (token != tok_typename)
     {
       complain (_("invalid %s declaration"), "%type");
       return t;
     }
 
     {
       complain (_("invalid %s declaration"), "%type");
       return t;
     }
 
-  k = strlen (token_buffer);
-  name = XCALLOC (char, k + 1);
-  strcpy (name, token_buffer);
+  name = xstrdup (token_buffer);
 
   for (;;)
     {
 
   for (;;)
     {
-      t = lex ();
+      token = lex ();
 
 
-      switch (t)
+      switch (token)
        {
        {
-       case SEMICOLON:
+       case tok_semicolon:
          return lex ();
 
          return lex ();
 
-       case COMMA:
+       case tok_comma:
          break;
 
          break;
 
-       case IDENTIFIER:
+       case tok_identifier:
          if (symval->type_name == NULL)
            symval->type_name = name;
          else if (strcmp (name, symval->type_name) != 0)
          if (symval->type_name == NULL)
            symval->type_name = name;
          else if (strcmp (name, symval->type_name) != 0)
@@ -1286,7 +1270,7 @@ get_type (void)
          break;
 
        default:
          break;
 
        default:
-         return t;
+         return token;
        }
     }
 }
        }
     }
 }
@@ -1307,30 +1291,33 @@ get_type (void)
 static void
 readgram (void)
 {
 static void
 readgram (void)
 {
-  int t;
+  token_t t;
   bucket *lhs = NULL;
   symbol_list *p;
   symbol_list *p1;
   bucket *bp;
 
   bucket *lhs = NULL;
   symbol_list *p;
   symbol_list *p1;
   bucket *bp;
 
-  symbol_list *crule;          /* points to first symbol_list of current rule.  */
-  /* its symbol is the lhs of the rule.   */
-  symbol_list *crule1;         /* points to the symbol_list preceding crule.  */
+  /* Points to first symbol_list of current rule. its symbol is the
+     lhs of the rule.  */
+  symbol_list *crule;
+  /* Points to the symbol_list preceding crule.  */
+  symbol_list *crule1;
 
   p1 = NULL;
 
   t = lex ();
 
 
   p1 = NULL;
 
   t = lex ();
 
-  while (t != TWO_PERCENTS && t != ENDFILE)
+  while (t != tok_two_percents && t != tok_eof)
     {
     {
-      if (t == IDENTIFIER || t == BAR)
+      if (t == tok_identifier || t == tok_bar)
        {
        {
-         int actionflag = 0;
-         int rulelength = 0;   /* number of symbols in rhs of this rule so far  */
+         int action_flag = 0;
+         /* Number of symbols in rhs of this rule so far */
+         int rulelength = 0;
          int xactions = 0;     /* JF for error checking */
          bucket *first_rhs = 0;
 
          int xactions = 0;     /* JF for error checking */
          bucket *first_rhs = 0;
 
-         if (t == IDENTIFIER)
+         if (t == tok_identifier)
            {
              lhs = symval;
 
            {
              lhs = symval;
 
@@ -1341,14 +1328,14 @@ readgram (void)
                }
 
              t = lex ();
                }
 
              t = lex ();
-             if (t != COLON)
+             if (t != tok_colon)
                {
                  complain (_("ill-formed rule: initial symbol not followed by colon"));
                  unlex (t);
                }
            }
 
                {
                  complain (_("ill-formed rule: initial symbol not followed by colon"));
                  unlex (t);
                }
            }
 
-         if (nrules == 0 && t == BAR)
+         if (nrules == 0 && t == tok_bar)
            {
              complain (_("grammar starts with vertical bar"));
              lhs = symval;     /* BOGUS: use a random symval */
            {
              complain (_("grammar starts with vertical bar"));
              lhs = symval;     /* BOGUS: use a random symval */
@@ -1374,13 +1361,13 @@ readgram (void)
 
          /* mark the rule's lhs as a nonterminal if not already so.  */
 
 
          /* mark the rule's lhs as a nonterminal if not already so.  */
 
-         if (lhs->class == SUNKNOWN)
+         if (lhs->class == unknown_sym)
            {
            {
-             lhs->class = SNTERM;
+             lhs->class = nterm_sym;
              lhs->value = nvars;
              nvars++;
            }
              lhs->value = nvars;
              nvars++;
            }
-         else if (lhs->class == STOKEN)
+         else if (lhs->class == token_sym)
            complain (_("rule given for %s, which is a token"), lhs->tag);
 
          /* read the rhs of the rule.  */
            complain (_("rule given for %s, which is a token"), lhs->tag);
 
          /* read the rhs of the rule.  */
@@ -1388,28 +1375,28 @@ readgram (void)
          for (;;)
            {
              t = lex ();
          for (;;)
            {
              t = lex ();
-             if (t == PREC)
+             if (t == tok_prec)
                {
                  t = lex ();
                  crule->ruleprec = symval;
                  t = lex ();
                }
 
                {
                  t = lex ();
                  crule->ruleprec = symval;
                  t = lex ();
                }
 
-             if (!(t == IDENTIFIER || t == LEFT_CURLY))
+             if (!(t == tok_identifier || t == tok_left_curly))
                break;
 
              /* If next token is an identifier, see if a colon follows it.
                 If one does, exit this rule now.  */
                break;
 
              /* If next token is an identifier, see if a colon follows it.
                 If one does, exit this rule now.  */
-             if (t == IDENTIFIER)
+             if (t == tok_identifier)
                {
                  bucket *ssave;
                {
                  bucket *ssave;
-                 int t1;
+                 token_t t1;
 
                  ssave = symval;
                  t1 = lex ();
                  unlex (t1);
                  symval = ssave;
 
                  ssave = symval;
                  t1 = lex ();
                  unlex (t1);
                  symval = ssave;
-                 if (t1 == COLON)
+                 if (t1 == tok_colon)
                    break;
 
                  if (!first_rhs)       /* JF */
                    break;
 
                  if (!first_rhs)       /* JF */
@@ -1421,13 +1408,13 @@ readgram (void)
              /* If we just passed an action, that action was in the middle
                 of a rule, so make a dummy rule to reduce it to a
                 non-terminal.  */
              /* If we just passed an action, that action was in the middle
                 of a rule, so make a dummy rule to reduce it to a
                 non-terminal.  */
-             if (actionflag)
+             if (action_flag)
                {
                  bucket *sdummy;
 
                {
                  bucket *sdummy;
 
-                 /* Since the action was written out with this rule's */
-                 /* number, we must give the new rule this number */
-                 /* by inserting the new rule before it.  */
+                 /* Since the action was written out with this rule's
+                    number, we must give the new rule this number by
+                    inserting the new rule before it.  */
 
                  /* Make a dummy nonterminal, a gensym.  */
                  sdummy = gensym ();
 
                  /* Make a dummy nonterminal, a gensym.  */
                  sdummy = gensym ();
@@ -1448,17 +1435,18 @@ readgram (void)
                  p->next = crule1;
                  crule1->next = crule;
 
                  p->next = crule1;
                  crule1->next = crule;
 
-                 /* insert the dummy generated by that rule into this rule.  */
+                 /* Insert the dummy generated by that rule into this
+                    rule.  */
                  nitems++;
                  p = XCALLOC (symbol_list, 1);
                  p->sym = sdummy;
                  p1->next = p;
                  p1 = p;
 
                  nitems++;
                  p = XCALLOC (symbol_list, 1);
                  p->sym = sdummy;
                  p1->next = p;
                  p1 = p;
 
-                 actionflag = 0;
+                 action_flag = 0;
                }
 
                }
 
-             if (t == IDENTIFIER)
+             if (t == tok_identifier)
                {
                  nitems++;
                  p = XCALLOC (symbol_list, 1);
                {
                  nitems++;
                  p = XCALLOC (symbol_list, 1);
@@ -1469,7 +1457,7 @@ readgram (void)
              else              /* handle an action.  */
                {
                  copy_action (crule, rulelength);
              else              /* handle an action.  */
                {
                  copy_action (crule, rulelength);
-                 actionflag = 1;
+                 action_flag = 1;
                  xactions++;   /* JF */
                }
              rulelength++;
                  xactions++;   /* JF */
                }
              rulelength++;
@@ -1480,30 +1468,28 @@ readgram (void)
          p1->next = p;
          p1 = p;
 
          p1->next = p;
          p1 = p;
 
-         if (t == PREC)
+         if (t == tok_prec)
            {
              complain (_("two @prec's in a row"));
              t = lex ();
              crule->ruleprec = symval;
              t = lex ();
            }
            {
              complain (_("two @prec's in a row"));
              t = lex ();
              crule->ruleprec = symval;
              t = lex ();
            }
-         if (t == GUARD)
+         if (t == tok_guard)
            {
              if (!semantic_parser)
            {
              if (!semantic_parser)
-               complain ("%s",
-                         _
-                         ("%guard present but %semantic_parser not specified"));
+               complain (_("%%guard present but %%semantic_parser not specified"));
 
              copy_guard (crule, rulelength);
              t = lex ();
            }
 
              copy_guard (crule, rulelength);
              t = lex ();
            }
-         else if (t == LEFT_CURLY)
+         else if (t == tok_left_curly)
            {
              /* This case never occurs -wjh */
            {
              /* This case never occurs -wjh */
-             if (actionflag)
+             if (action_flag)
                complain (_("two actions at end of one rule"));
              copy_action (crule, rulelength);
                complain (_("two actions at end of one rule"));
              copy_action (crule, rulelength);
-             actionflag = 1;
+             action_flag = 1;
              xactions++;       /* -wjh */
              t = lex ();
            }
              xactions++;       /* -wjh */
              t = lex ();
            }
@@ -1522,7 +1508,7 @@ readgram (void)
          /* Warn if there is no default for $$ but we need one.  */
          else if (!xactions && !first_rhs && lhs->type_name != 0)
            complain (_("empty rule for typed nonterminal, and no action"));
          /* Warn if there is no default for $$ but we need one.  */
          else if (!xactions && !first_rhs && lhs->type_name != 0)
            complain (_("empty rule for typed nonterminal, and no action"));
-         if (t == SEMICOLON)
+         if (t == tok_semicolon)
            t = lex ();
        }
 #if 0
            t = lex ();
        }
 #if 0
@@ -1532,31 +1518,31 @@ readgram (void)
        b) most of them scan forward until finding a next %
                thus they may swallow lots of intervening rules
 */
        b) most of them scan forward until finding a next %
                thus they may swallow lots of intervening rules
 */
-      else if (t == TOKEN)
+      else if (t == tok_token)
        {
        {
-         parse_token_decl (STOKEN, SNTERM);
+         parse_token_decl (token_sym, nterm_sym);
          t = lex ();
        }
          t = lex ();
        }
-      else if (t == NTERM)
+      else if (t == tok_nterm)
        {
        {
-         parse_token_decl (SNTERM, STOKEN);
+         parse_token_decl (nterm_sym, token_sym);
          t = lex ();
        }
          t = lex ();
        }
-      else if (t == TYPE)
+      else if (t == tok_type)
        {
          t = get_type ();
        }
        {
          t = get_type ();
        }
-      else if (t == UNION)
+      else if (t == tok_union)
        {
          parse_union_decl ();
          t = lex ();
        }
        {
          parse_union_decl ();
          t = lex ();
        }
-      else if (t == EXPECT)
+      else if (t == tok_expect)
        {
          parse_expect_decl ();
          t = lex ();
        }
        {
          parse_expect_decl ();
          t = lex ();
        }
-      else if (t == START)
+      else if (t == tok_start)
        {
          parse_start_decl ();
          t = lex ();
        {
          parse_start_decl ();
          t = lex ();
@@ -1565,7 +1551,7 @@ readgram (void)
 
       else
        {
 
       else
        {
-         complain (_("invalid input: %s"), token_buffer);
+         complain (_("invalid input: %s"), quote (token_buffer));
          t = lex ();
        }
     }
          t = lex ();
        }
     }
@@ -1578,26 +1564,31 @@ readgram (void)
   if (nrules == 0)
     fatal (_("no rules in the input grammar"));
 
   if (nrules == 0)
     fatal (_("no rules in the input grammar"));
 
-  if (typed == 0               /* JF put out same default YYSTYPE as YACC does */
+  /* JF put out same default YYSTYPE as YACC does */
+  if (typed == 0
       && !value_components_used)
     {
       /* We used to use `unsigned long' as YYSTYPE on MSDOS,
          but it seems better to be consistent.
          Most programs should declare their own type anyway.  */
       && !value_components_used)
     {
       /* We used to use `unsigned long' as YYSTYPE on MSDOS,
          but it seems better to be consistent.
          Most programs should declare their own type anyway.  */
-      fprintf (fattrs, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
-      if (fdefines)
-       fprintf (fdefines, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
+      obstack_sgrow (&attrs_obstack,
+                          "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
+      if (defines_flag)
+       obstack_sgrow (&defines_obstack, "\
+# ifndef YYSTYPE\n\
+#  define YYSTYPE int\n\
+# endif\n");
     }
 
   /* Report any undefined symbols and consider them nonterminals.  */
 
   for (bp = firstsymbol; bp; bp = bp->next)
     }
 
   /* Report any undefined symbols and consider them nonterminals.  */
 
   for (bp = firstsymbol; bp; bp = bp->next)
-    if (bp->class == SUNKNOWN)
+    if (bp->class == unknown_sym)
       {
        complain (_
                  ("symbol %s is used, but is not defined as a token and has no rules"),
       {
        complain (_
                  ("symbol %s is used, but is not defined as a token and has no rules"),
-bp->tag);
-       bp->class = SNTERM;
+                 bp->tag);
+       bp->class = nterm_sym;
        bp->value = nvars++;
       }
 
        bp->value = nvars++;
       }
 
@@ -1610,7 +1601,7 @@ bp->tag);
 `--------------------------------------------------------------*/
 
 static void
 `--------------------------------------------------------------*/
 
 static void
-output_token_defines (FILE *file)
+output_token_defines (struct obstack *oout)
 {
   bucket *bp;
   char *cp, *symbol;
 {
   bucket *bp;
   char *cp, *symbol;
@@ -1643,14 +1634,14 @@ output_token_defines (FILE *file)
       if (c != '\0')
        continue;
 
       if (c != '\0')
        continue;
 
-      fprintf (file, "#define\t%s\t%d\n", symbol,
-              ((translations && !rawtoknumflag)
-               ? bp->user_token_number : bp->value));
+      obstack_fgrow2 (oout, "# define\t%s\t%d\n",
+                     symbol,
+                     (translations ? bp->user_token_number : bp->value));
       if (semantic_parser)
       if (semantic_parser)
-       fprintf (file, "#define\tT%s\t%d\n", symbol, bp->value);
+       obstack_fgrow2 (oout, "# define\tT%s\t%d\n", symbol, bp->value);
     }
 
     }
 
-  putc ('\n', file);
+  obstack_1grow (oout, '\n');
 }
 
 
 }
 
 
@@ -1684,7 +1675,7 @@ packsymbols (void)
 
   for (bp = firstsymbol; bp; bp = bp->next)
     {
 
   for (bp = firstsymbol; bp; bp = bp->next)
     {
-      if (bp->class == SNTERM)
+      if (bp->class == nterm_sym)
        {
          bp->value += ntokens;
        }
        {
          bp->value += ntokens;
        }
@@ -1724,12 +1715,12 @@ packsymbols (void)
            continue;           /* do not do processing below for SALIASs */
 
        }
            continue;           /* do not do processing below for SALIASs */
 
        }
-      else                     /* bp->class == STOKEN */
+      else                     /* bp->class == token_sym */
        {
          bp->value = tokno++;
        }
 
        {
          bp->value = tokno++;
        }
 
-      if (bp->class == STOKEN)
+      if (bp->class == token_sym)
        {
          if (translations && !(bp->user_token_number))
            bp->user_token_number = ++last_user_token_number;
        {
          if (translations && !(bp->user_token_number))
            bp->user_token_number = ++last_user_token_number;
@@ -1772,27 +1763,28 @@ packsymbols (void)
 
   error_token_number = errtoken->value;
 
 
   error_token_number = errtoken->value;
 
-  if (!noparserflag)
-    output_token_defines (ftable);
+  if (!no_parser_flag)
+    output_token_defines (&table_obstack);
 
 
-  if (startval->class == SUNKNOWN)
+  if (startval->class == unknown_sym)
     fatal (_("the start symbol %s is undefined"), startval->tag);
     fatal (_("the start symbol %s is undefined"), startval->tag);
-  else if (startval->class == STOKEN)
+  else if (startval->class == token_sym)
     fatal (_("the start symbol %s is a token"), startval->tag);
 
   start_symbol = startval->value;
 
     fatal (_("the start symbol %s is a token"), startval->tag);
 
   start_symbol = startval->value;
 
-  if (definesflag)
+  if (defines_flag)
     {
     {
-      output_token_defines (fdefines);
+      output_token_defines (&defines_obstack);
 
       if (!pure_parser)
        {
          if (spec_name_prefix)
 
       if (!pure_parser)
        {
          if (spec_name_prefix)
-           fprintf (fdefines, "\nextern YYSTYPE %slval;\n",
-                    spec_name_prefix);
+           obstack_fgrow1 (&defines_obstack, "\nextern YYSTYPE %slval;\n",
+                           spec_name_prefix);
          else
          else
-           fprintf (fdefines, "\nextern YYSTYPE yylval;\n");
+           obstack_sgrow (&defines_obstack,
+                                "\nextern YYSTYPE yylval;\n");
        }
 
       if (semantic_parser)
        }
 
       if (semantic_parser)
@@ -1800,7 +1792,8 @@ packsymbols (void)
          {
            /* don't make these for dummy nonterminals made by gensym.  */
            if (*tags[i] != '@')
          {
            /* don't make these for dummy nonterminals made by gensym.  */
            if (*tags[i] != '@')
-             fprintf (fdefines, "#define\tNT%s\t%d\n", tags[i], i);
+              obstack_fgrow2 (&defines_obstack,
+                              "# define\tNT%s\t%d\n", tags[i], i);
          }
 #if 0
       /* `fdefines' is now a temporary file, so we need to copy its
          }
 #if 0
       /* `fdefines' is now a temporary file, so we need to copy its
@@ -1849,7 +1842,7 @@ packgram (void)
          ritem[itemno++] = p->sym->value;
          /* A rule gets by default the precedence and associativity
             of the last token in it.  */
          ritem[itemno++] = p->sym->value;
          /* A rule gets by default the precedence and associativity
             of the last token in it.  */
-         if (p->sym->class == STOKEN)
+         if (p->sym->class == token_sym)
            {
              rprec[ruleno] = p->sym->prec;
              rassoc[ruleno] = p->sym->assoc;
            {
              rprec[ruleno] = p->sym->prec;
              rassoc[ruleno] = p->sym->assoc;
@@ -1879,10 +1872,10 @@ packgram (void)
 \f
 /*-------------------------------------------------------------------.
 | Read in the grammar specification and record it in the format      |
 \f
 /*-------------------------------------------------------------------.
 | Read in the grammar specification and record it in the format      |
-| described in gram.h.  All guards are copied into the FGUARD file   |
-| and all actions into FACTION, in each case forming the body of a C |
-| function (YYGUARD or YYACTION) which contains a switch statement   |
-| to decide which guard or action to execute.                        |
+| described in gram.h.  All guards are copied into the GUARD_OBSTACK |
+| and all actions into ACTION_OBSTACK, in each case forming the body |
+| of a C function (YYGUARD or YYACTION) which contains a switch      |
+| statement to decide which guard or action to execute.              |
 `-------------------------------------------------------------------*/
 
 void
 `-------------------------------------------------------------------*/
 
 void
@@ -1910,11 +1903,8 @@ reader (void)
   typed = 0;
   lastprec = 0;
 
   typed = 0;
   lastprec = 0;
 
-  gensym_count = 0;
-
   semantic_parser = 0;
   pure_parser = 0;
   semantic_parser = 0;
   pure_parser = 0;
-  yylsp_needed = 0;
 
   grammar = NULL;
 
 
   grammar = NULL;
 
@@ -1925,24 +1915,27 @@ reader (void)
   tabinit ();
   /* Construct the error token */
   errtoken = getsym ("error");
   tabinit ();
   /* Construct the error token */
   errtoken = getsym ("error");
-  errtoken->class = STOKEN;
+  errtoken->class = token_sym;
   errtoken->user_token_number = 256;   /* Value specified by POSIX.  */
   /* Construct a token that represents all undefined literal tokens.
      It is always token number 2.  */
   undeftoken = getsym ("$undefined.");
   errtoken->user_token_number = 256;   /* Value specified by POSIX.  */
   /* Construct a token that represents all undefined literal tokens.
      It is always token number 2.  */
   undeftoken = getsym ("$undefined.");
-  undeftoken->class = STOKEN;
+  undeftoken->class = token_sym;
   undeftoken->user_token_number = 2;
 
   undeftoken->user_token_number = 2;
 
-  /* Read the declaration section.  Copy %{ ... %} groups to FTABLE
-     and FDEFINES file.  Also notice any %token, %left, etc. found
-     there.  */
-  putc ('\n', ftable);
-  fprintf (ftable, "\
+  /* Read the declaration section.  Copy %{ ... %} groups to
+     TABLE_OBSTACK and FDEFINES file.  Also notice any %token, %left,
+     etc. found there.  */
+  obstack_1grow (&table_obstack, '\n');
+  obstack_fgrow3 (&table_obstack, "\
 /* %s, made from %s\n\
    by GNU bison %s.  */\n\
 /* %s, made from %s\n\
    by GNU bison %s.  */\n\
-\n", noparserflag ? "Bison-generated parse tables" : "A Bison parser", infile, VERSION);
+\n",
+                 no_parser_flag ? "Bison-generated parse tables" : "A Bison parser",
+                 infile, VERSION);
 
 
-  fputs ("#define YYBISON 1  /* Identify Bison output.  */\n\n", ftable);
+  obstack_sgrow (&table_obstack,
+                      "#define YYBISON 1  /* Identify Bison output.  */\n\n");
   read_declarations ();
   /* Start writing the guard and action files, if they are needed.  */
   output_headers ();
   read_declarations ();
   /* Start writing the guard and action files, if they are needed.  */
   output_headers ();
@@ -1951,12 +1944,12 @@ reader (void)
   readgram ();
   /* Now we know whether we need the line-number stack.  If we do,
      write its type into the .tab.h file.  */
   readgram ();
   /* Now we know whether we need the line-number stack.  If we do,
      write its type into the .tab.h file.  */
-  if (fdefines)
-    reader_output_yylsp (fdefines);
+  if (defines_flag)
+    reader_output_yylsp (&defines_obstack);
   /* Write closing delimiters for actions and guards.  */
   output_trailers ();
   /* Write closing delimiters for actions and guards.  */
   output_trailers ();
-  if (yylsp_needed)
-    fputs ("#define YYLSP_NEEDED\n\n", ftable);
+  if (locations_flag)
+    obstack_sgrow (&table_obstack, "#define YYLSP_NEEDED 1\n\n");
   /* Assign the symbols their symbol numbers.  Write #defines for the
      token symbols into FDEFINES if requested.  */
   packsymbols ();
   /* Assign the symbols their symbol numbers.  Write #defines for the
      token symbols into FDEFINES if requested.  */
   packsymbols ();
@@ -1967,9 +1960,29 @@ reader (void)
   free_symtab ();
 }
 
   free_symtab ();
 }
 
+
+/*------------------------------------------------------------------.
+| Define YYLTYPE.  Cannot be in the skeleton since we might have to |
+| output it in the headers if --defines is used.                    |
+`------------------------------------------------------------------*/
+
 void
 void
-reader_output_yylsp (FILE *f)
+reader_output_yylsp (struct obstack *oout)
 {
 {
-  if (yylsp_needed)
-    fprintf (f, LTYPESTR);
+  if (locations_flag)
+    obstack_sgrow (oout, "\
+\n\
+#ifndef YYLTYPE\n\
+typedef struct yyltype\n\
+{\n\
+  int first_line;\n\
+  int first_column;\n\
+\n\
+  int last_line;\n\
+  int last_column;\n\
+} yyltype;\n\
+\n\
+# define YYLTYPE yyltype\n\
+#endif\n\
+\n");
 }
 }