]> git.saurik.com Git - bison.git/blobdiff - src/reader.c
Point to an official beta.
[bison.git] / src / reader.c
index bd13e044e70baf9c8bee222c1a64760932edbd1a..6a99cfffa79e0b57ceaeb46c3562a6c28710b639 100644 (file)
@@ -1,5 +1,5 @@
 /* Input parser for bison
 /* Input parser for bison
-   Copyright (C) 1984, 1986, 1989, 1992, 1998, 2000
+   Copyright (C) 1984, 1986, 1989, 1992, 1998, 2000, 2001, 2002
    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.
 
 
 #include "system.h"
 
 
 #include "system.h"
+#include "quotearg.h"
+#include "quote.h"
 #include "getargs.h"
 #include "files.h"
 #include "getargs.h"
 #include "files.h"
-#include "xalloc.h"
 #include "symtab.h"
 #include "symtab.h"
+#include "options.h"
 #include "lex.h"
 #include "gram.h"
 #include "complain.h"
 #include "output.h"
 #include "reader.h"
 #include "conflicts.h"
 #include "lex.h"
 #include "gram.h"
 #include "complain.h"
 #include "output.h"
 #include "reader.h"
 #include "conflicts.h"
-
-extern char *printable_version PARAMS ((int));
-
-/* Number of slots allocated (but not necessarily used yet) in `rline'  */
-static int rline_allocated;
+#include "muscle_tab.h"
 
 typedef struct symbol_list
 {
   struct symbol_list *next;
 
 typedef struct symbol_list
 {
   struct symbol_list *next;
-  bucket *sym;
-  bucket *ruleprec;
-}
-symbol_list;
+  symbol_t *sym;
+  int line;
+
+  /* The action is attached to the LHS of a rule. */
+  const char *action;
+  int action_line;
+
+  /* The guard is attached to the LHS of a rule. */
+  const char *guard;
+  int guard_line;
+  symbol_t *ruleprec;
+} symbol_list;
 
 int lineno;
 
 int lineno;
-char **tags;
-short *user_toknums;
-static symbol_list *grammar;
-static int start_flag;
-static bucket *startval;
+static symbol_list *grammar = NULL;
+static int start_flag = 0;
+static symbol_t *startval = NULL;
 
 /* Nonzero if components of semantic values are used, implying
    they must be unions.  */
 static int value_components_used;
 
 /* Nonzero if %union has been seen.  */
 
 /* Nonzero if components of semantic values are used, implying
    they must be unions.  */
 static int value_components_used;
 
 /* Nonzero if %union has been seen.  */
-static int typed;
+static int typed = 0;
 
 /* Incremented for each %left, %right or %nonassoc seen */
 
 /* Incremented for each %left, %right or %nonassoc seen */
-static int lastprec;
+static int lastprec = 0;
+
+symbol_t *errtoken = NULL;
+symbol_t *undeftoken = NULL;
+symbol_t *eoftoken = NULL;
+symbol_t *axiom = NULL;
+
+static symbol_list *
+symbol_list_new (symbol_t *sym)
+{
+  symbol_list *res = XMALLOC (symbol_list, 1);
+  res->next = NULL;
+  res->sym = sym;
+  res->line = lineno;
+  res->action = NULL;
+  res->action_line = 0;
+  res->guard = NULL;
+  res->guard_line = 0;
+  res->ruleprec = NULL;
+  return res;
+}
+
+/*------------------------.
+| Operations on symbols.  |
+`------------------------*/
+
+
+/*-----------------------------------------------------------.
+| If THIS is not defined, report an error, and consider it a |
+| nonterminal.                                               |
+`-----------------------------------------------------------*/
+
+static bool
+symbol_check_defined (symbol_t *this)
+{
+  if (this->class == unknown_sym)
+    {
+      complain
+       (_("symbol %s is used, but is not defined as a token and has no rules"),
+        this->tag);
+      this->class = nterm_sym;
+      this->number = nvars++;
+    }
+
+  return TRUE;
+}
+
+
+/*-------------------------------------------------------------------.
+| Assign a symbol number, and write the definition of the token name |
+| into FDEFINES.  Put in SYMBOLS.                                    |
+`-------------------------------------------------------------------*/
+
+static bool
+symbol_make_alias (symbol_t *symbol, char *typename)
+{
+  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--;
+      ntokens--;
+      assert (ntokens == symbol->number || ntokens == symval->number);
+      symbol->number = symval->number =
+       (symval->number < symbol->number) ? symval->number : symbol->number;
+    }
+
+  return TRUE;
+}
+
+/*---------------------------------------------------------.
+| Check that THIS, and its alias, have same precedence and |
+| associativity.                                           |
+`---------------------------------------------------------*/
+
+static bool
+symbol_check_alias_consistence (symbol_t *this)
+{
+  /* Check only those who _are_ the aliases. */
+  if (this->alias && this->user_token_number == SALIAS)
+    {
+      if (this->prec != this->alias->prec)
+       {
+         if (this->prec != 0 && this->alias->prec != 0)
+           complain (_("conflicting precedences for %s and %s"),
+                     this->tag, this->alias->tag);
+         if (this->prec != 0)
+           this->alias->prec = this->prec;
+         else
+           this->prec = this->alias->prec;
+       }
+
+      if (this->assoc != this->alias->assoc)
+       {
+         if (this->assoc != 0 && this->alias->assoc != 0)
+           complain (_("conflicting assoc values for %s and %s"),
+                     this->tag, this->alias->tag);
+         if (this->assoc != 0)
+           this->alias->assoc = this->assoc;
+         else
+           this->assoc = this->alias->assoc;
+       }
+    }
+  return TRUE;
+}
+
+
+/*-------------------------------------------------------------------.
+| Assign a symbol number, and write the definition of the token name |
+| into FDEFINES.  Put in SYMBOLS.                                    |
+`-------------------------------------------------------------------*/
+
+static bool
+symbol_pack (symbol_t *this)
+{
+  if (this->class == nterm_sym)
+    {
+      this->number += ntokens;
+    }
+  else if (this->alias)
+    {
+      /* This symbol and its alias are a single token defn.
+        Allocate a tokno, and assign to both check agreement of
+        prec and assoc fields and make both the same */
+      if (this->number == NUMBER_UNDEFINED)
+       {
+         if (this == eoftoken || this->alias == eoftoken)
+           this->number = this->alias->number = 0;
+         else
+           {
+             assert (this->alias->number != NUMBER_UNDEFINED);
+             this->number = this->alias->number;
+           }
+       }
+      /* Do not do processing below for SALIASs.  */
+      if (this->user_token_number == SALIAS)
+       return TRUE;
+    }
+  else /* this->class == token_sym */
+    {
+      assert (this->number != NUMBER_UNDEFINED);
+    }
+
+  symbols[this->number] = this;
+  return TRUE;
+}
+
+
+
 
 
-/* Incremented for each generated symbol */
-static int gensym_count;
+/*--------------------------------------------------.
+| Put THIS in TOKEN_TRANSLATIONS if it is a token.  |
+`--------------------------------------------------*/
 
 
-static bucket *errtoken;
-static bucket *undeftoken;
+static bool
+symbol_translation (symbol_t *this)
+{
+  /* Non-terminal? */
+  if (this->class == token_sym
+      && this->user_token_number != SALIAS)
+    {
+      /* A token which translation has already been set? */
+      if (token_translations[this->user_token_number] != undeftoken->number)
+       complain (_("tokens %s and %s both assigned number %d"),
+                 symbols[token_translations[this->user_token_number]]->tag,
+                 this->tag, this->user_token_number);
+
+      token_translations[this->user_token_number] = this->number;
+    }
 
 
-/* Nonzero if any action or guard uses the @n construct.  */
-static int yylsp_needed;
+  return TRUE;
+}
 \f
 
 /*===================\
 \f
 
 /*===================\
@@ -121,17 +298,53 @@ 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_string2 (FILE *fin, struct obstack *oout, int match, int store)
 {
   int c;
 
 {
   int c;
 
-  putc (match, fout);
+  if (store)
+    obstack_1grow (oout, match);
+
   c = getc (fin);
 
   while (c != match)
   c = getc (fin);
 
   while (c != match)
@@ -146,42 +359,79 @@ 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')
          if (c == '\n')
-           lineno++;
+           ++lineno;
        }
 
       c = getc (fin);
     }
 
        }
 
       c = getc (fin);
     }
 
-  putc (c, fout);
+  if (store)
+    obstack_1grow (oout, c);
 }
 
 }
 
+/* FIXME. */
 
 
-/*---------------------------------------------------------------.
-| Dump the comment from IN to OUT1 and OUT2.  C is either `*' or |
-| `/', depending upon the type of comments used.  OUT2 might be  |
-| NULL.                                                          |
-`---------------------------------------------------------------*/
+static inline void
+copy_string (FILE *fin, struct obstack *oout, int match)
+{
+  copy_string2 (fin, oout, match, 1);
+}
+
+/* FIXME. */
+
+static inline void
+copy_identifier (FILE *fin, struct obstack *oout)
+{
+  int c;
+
+  while (isalnum (c = getc (fin)) || c == '_')
+    obstack_1grow (oout, c);
+
+  ungetc (c, fin);
+}
+
+
+/*------------------------------------------------------------------.
+| Dump the wannabee comment from IN to OOUT.  In fact we just saw a |
+| `/', which might or might not be a comment.  In any case, copy    |
+| what we saw.                                                      |
+`------------------------------------------------------------------*/
 
 static inline void
 
 static inline void
-copy_comment2 (FILE *in, FILE *out1, FILE *out2, int c)
+copy_comment (FILE *fin, struct obstack *oout)
 {
   int cplus_comment;
   int ended;
 {
   int cplus_comment;
   int ended;
+  int c;
 
 
-  cplus_comment = (c == '/');
-  putc (c, out1);
-  if (out2)
-    putc (c, out2);
-  c = getc (in);
+  /* We read a `/', output it. */
+  obstack_1grow (oout, '/');
+
+  switch ((c = getc (fin)))
+    {
+    case '/':
+      cplus_comment = 1;
+      break;
+    case '*':
+      cplus_comment = 0;
+      break;
+    default:
+      ungetc (c, fin);
+      return;
+    }
+
+  obstack_1grow (oout, c);
+  c = getc (fin);
 
   ended = 0;
   while (!ended)
 
   ended = 0;
   while (!ended)
@@ -190,86 +440,149 @@ 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 (oout, c);
+             c = getc (fin);
            }
 
          if (c == '/')
            {
            }
 
          if (c == '/')
            {
-             putc (c, out1);
-             if (out2)
-               putc (c, out2);
+             obstack_1grow (oout, c);
              ended = 1;
            }
        }
       else if (c == '\n')
        {
              ended = 1;
            }
        }
       else if (c == '\n')
        {
-         lineno++;
-         putc (c, out1);
-         if (out2)
-           putc (c, out2);
+         ++lineno;
+         obstack_1grow (oout, 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 (oout, c);
+         c = getc (fin);
        }
     }
 }
 
 
        }
     }
 }
 
 
-/*------------------------------------------------------------.
-| Dump the comment from FIN to FOUT.  C is either `*' or `/', |
-| depending upon the type of comments used.                   |
-`------------------------------------------------------------*/
-
-static inline void
-copy_comment (FILE *fin, FILE *fout, int c)
-{
-  copy_comment2 (fin, fout, NULL, c);
-}
-
-
 /*-----------------------------------------------------------------.
 /*-----------------------------------------------------------------.
-| 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 == '-')
     {
       int n;
 
     }
   else if (isdigit (c) || c == '-')
     {
       int n;
 
+      ungetc (c, fin);
+      n = read_signed_integer (fin);
+      if (n > stack_offset)
+       complain (_("invalid value: %s%d"), "@", n);
+      else
+       {
+         /* Offset is always 0 if parser has already popped the stack
+            pointer.  */
+         obstack_fgrow1 (oout, "yylsp[%d]",
+                         n - (semantic_parser ? 0 : stack_offset));
+         locations_flag = 1;
+       }
+    }
+  else
+    {
+      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);
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
-      fprintf (fout, "yylsp[%d]", n - stack_offset);
-      yylsp_needed = 1;
+      if (n > stack_offset)
+       complain (_("invalid value: %s%d"), "$", n);
+      else
+       {
+         if (!type_name && n > 0)
+           type_name = get_type_name (n, rule);
+
+         /* Offset is always 0 if parser has already popped the stack
+            pointer.  */
+         obstack_fgrow1 (oout, "yyvsp[%d]",
+                         n - (semantic_parser ? 0 : 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
     }
   else
-    complain (_("@%s is invalid"), printable_version (c));
+    {
+      char buf[] = "$c";
+      buf[1] = c;
+      complain (_("%s is invalid"), quote (buf));
+    }
 }
 \f
 /*-------------------------------------------------------------------.
 }
 \f
 /*-------------------------------------------------------------------.
@@ -284,8 +597,12 @@ 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, muscle_find ("linef"),
+                     lineno, quotearg_style (c_quoting_style,
+                                             muscle_find ("filename")));
+    }
 
   after_percent = 0;
 
 
   after_percent = 0;
 
@@ -296,8 +613,8 @@ copy_definition (void)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         putc (c, fattrs);
-         lineno++;
+         obstack_1grow (&attrs_obstack, c);
+         ++lineno;
          break;
 
        case '%':
          break;
 
        case '%':
@@ -306,22 +623,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);
@@ -330,12 +643,10 @@ copy_definition (void)
        {
          if (c == '}')
            return;
        {
          if (c == '}')
            return;
-         putc ('%', fattrs);
+         obstack_1grow (&attrs_obstack, '%');
        }
       after_percent = 0;
        }
       after_percent = 0;
-
     }
     }
-
 }
 
 
 }
 
 
@@ -348,49 +659,43 @@ copy_definition (void)
 static void
 parse_token_decl (symbol_class what_is, symbol_class what_is_not)
 {
 static void
 parse_token_decl (symbol_class what_is, symbol_class what_is_not)
 {
-  int token = 0;
-  char *typename = 0;
-  struct bucket *symbol = NULL;        /* pts to symbol being defined */
-  int k;
+  token_t token = tok_undef;
+  char *typename = NULL;
+
+  /* The symbol being defined.  */
+  symbol_t *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)
        {
        {
-         translations = 1;
-         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 = NULL;
-
-         nsyms--;              /* symbol and symval combined are only one symbol */
+         symbol_make_alias (symbol, typename);
+         symbol = NULL;
        }
        }
-      else if (token == IDENTIFIER)
+      else if (token == tok_identifier)
        {
          int oldclass = symval->class;
          symbol = symval;
        {
          int oldclass = symval->class;
          symbol = symval;
@@ -399,7 +704,9 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
            complain (_("symbol %s redefined"), symbol->tag);
          symbol->class = what_is;
          if (what_is == nterm_sym && oldclass != nterm_sym)
            complain (_("symbol %s redefined"), symbol->tag);
          symbol->class = what_is;
          if (what_is == nterm_sym && oldclass != nterm_sym)
-           symbol->value = nvars++;
+           symbol->number = nvars++;
+         if (what_is == token_sym && symbol->number == NUMBER_UNDEFINED)
+           symbol->number = ntokens++;
 
          if (typename)
            {
 
          if (typename)
            {
@@ -409,15 +716,24 @@ parse_token_decl (symbol_class what_is, symbol_class 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;
        {
          symbol->user_token_number = numval;
-         translations = 1;
+         /* User defined EOF token? */
+         if (numval == 0)
+           {
+             eoftoken = symbol;
+             eoftoken->number = 0;
+             /* It is always mapped to 0, so it was already counted in
+                NTOKENS.  */
+             --ntokens;
+           }
        }
       else
        {
          complain (_("`%s' is invalid in %s"),
        }
       else
        {
          complain (_("`%s' is invalid in %s"),
-                   token_buffer, (what_is == token_sym) ? "%token" : "%nterm");
+                   token_buffer,
+                   (what_is == token_sym) ? "%token" : "%nterm");
          skip_to_char ('%');
        }
     }
          skip_to_char ('%');
        }
     }
@@ -434,7 +750,7 @@ parse_start_decl (void)
 {
   if (start_flag)
     complain (_("multiple %s declarations"), "%start");
 {
   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
     {
@@ -443,43 +759,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                                    |
@@ -488,23 +767,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 == '%')
@@ -517,11 +793,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)
@@ -547,15 +823,15 @@ parse_type_decl (void)
 static void
 parse_assoc_decl (associativity assoc)
 {
 static void
 parse_assoc_decl (associativity assoc)
 {
-  int k;
   char *name = NULL;
   int prev = 0;
 
   char *name = NULL;
   int prev = 0;
 
-  lastprec++;                  /* Assign a new precedence level, never 0.  */
+  /* Assign a new precedence level, never 0.  */
+  ++lastprec;
 
   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 == '%')
@@ -567,24 +843,25 @@ parse_assoc_decl (associativity 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->class == nterm_sym)
            complain (_("symbol %s redefined"), symval->tag);
          if (symval->prec != 0)
            complain (_("redefining precedence of %s"), symval->tag);
          symval->prec = lastprec;
          symval->assoc = assoc;
          if (symval->class == nterm_sym)
            complain (_("symbol %s redefined"), symval->tag);
-         symval->class = token_sym;
+         if (symval->number == NUMBER_UNDEFINED)
+           {
+             symval->number = ntokens++;
+             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)
@@ -594,22 +871,21 @@ parse_assoc_decl (associativity assoc)
            }
          break;
 
            }
          break;
 
-       case NUMBER:
-         if (prev == IDENTIFIER)
+       case tok_number:
+         if (prev == tok_identifier)
            {
              symval->user_token_number = numval;
            {
              symval->user_token_number = numval;
-             translations = 1;
            }
          else
            {
            }
          else
            {
-             complain (_
-                       ("invalid text (%s) - number should be after identifier"),
-token_buffer);
+             complain
+               (_("invalid text (%s) - number should be after identifier"),
+                token_buffer);
              skip_to_char ('%');
            }
          break;
 
              skip_to_char ('%');
            }
          break;
 
-       case SEMICOLON:
+       case tok_semicolon:
          return;
 
        default:
          return;
 
        default:
@@ -618,83 +894,72 @@ token_buffer);
        }
 
       prev = t;
        }
 
       prev = t;
-
     }
 }
 
 
 
     }
 }
 
 
 
-/*-------------------------------------------------------------------.
-| 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 the stype muscle             |
+| (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)
 {
   int c;
   int count = 0;
 
 static void
 parse_union_decl (void)
 {
   int c;
   int count = 0;
-
+  bool done = FALSE;
+  struct obstack union_obstack;
   if (typed)
     complain (_("multiple %s declarations"), "%union");
 
   typed = 1;
 
   if (typed)
     complain (_("multiple %s declarations"), "%union");
 
   typed = 1;
 
-  if (!nolinesflag)
-    fprintf (fattrs, "\n#line %d \"%s\"\n", lineno, infile);
-  else
-    fprintf (fattrs, "\n");
-
-  fprintf (fattrs, "typedef union");
-  if (fdefines)
-    fprintf (fdefines, "typedef union");
-
-  c = getc (finput);
+  MUSCLE_INSERT_INT ("stype_line", lineno);
+  obstack_init (&union_obstack);
+  obstack_sgrow (&union_obstack, "union");
 
 
-  while (c != EOF)
+  while (!done)
     {
     {
-      putc (c, fattrs);
-      if (fdefines)
-       putc (c, fdefines);
+      c = xgetc (finput);
+
+      /* If C contains '/', it is output by copy_comment ().  */
+      if (c != '/')
+       obstack_1grow (&union_obstack, c);
 
       switch (c)
        {
        case '\n':
 
       switch (c)
        {
        case '\n':
-         lineno++;
+         ++lineno;
          break;
 
        case '/':
          break;
 
        case '/':
-         c = getc (finput);
-         if (c != '*' && c != '/')
-           continue;
-         copy_comment2 (finput, fattrs, fdefines, c);
+         copy_comment (finput, &union_obstack);
          break;
 
          break;
 
-
        case '{':
        case '{':
-         count++;
+         ++count;
          break;
 
        case '}':
          break;
 
        case '}':
+         /* FIXME: Errr.  How could this happen???. --akim */
          if (count == 0)
            complain (_("unmatched %s"), "`}'");
          count--;
          if (count == 0)
            complain (_("unmatched %s"), "`}'");
          count--;
-         if (count <= 0)
-           {
-             fprintf (fattrs, " YYSTYPE;\n");
-             if (fdefines)
-               fprintf (fdefines, " YYSTYPE;\n");
-             /* JF don't choke on trailing semi */
-             c = skip_white_space ();
-             if (c != ';')
-               ungetc (c, finput);
-             return;
-           }
+         if (!count)
+           done = TRUE;
+         break;
        }
        }
-
-      c = getc (finput);
     }
     }
+
+  /* JF don't choke on trailing semi */
+  c = skip_white_space ();
+  if (c != ';')
+    ungetc (c, finput);
+  obstack_1grow (&union_obstack, 0);
+  muscle_insert ("stype", obstack_finish (&union_obstack));
 }
 
 
 }
 
 
@@ -706,29 +971,14 @@ parse_union_decl (void)
 static void
 parse_expect_decl (void)
 {
 static void
 parse_expect_decl (void)
 {
-  int c;
-  int count;
-  char buffer[20];
+  int c = skip_white_space ();
+  ungetc (c, finput);
 
 
-  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;
-
-  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);
+}
 
 
 /*-------------------------------------------------------------------.
 
 
 /*-------------------------------------------------------------------.
@@ -754,25 +1004,22 @@ parse_expect_decl (void)
 static void
 parse_thong_decl (void)
 {
 static void
 parse_thong_decl (void)
 {
-  int token;
-  struct bucket *symbol;
+  token_t token;
+  symbol_t *symbol;
   char *typename = 0;
   char *typename = 0;
-  int k, usrtoknum;
+  int usrtoknum = SUNDEF;
 
 
-  translations = 1;
   token = lex ();              /* fetch typename or first token */
   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);
     {
       complain (_("unrecognized item %s, expected an identifier"),
                token_buffer);
@@ -786,17 +1033,15 @@ parse_thong_decl (void)
 
   token = lex ();              /* get number or literal string */
 
 
   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 */
     }
-  else
-    usrtoknum = 0;
 
   /* 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 ('%');
     {
       complain (_("expected string constant instead of %s"), token_buffer);
       skip_to_char ('%');
@@ -809,93 +1054,187 @@ parse_thong_decl (void)
   symval->alias = symbol;
   symbol->alias = symval;
 
   symval->alias = symbol;
   symbol->alias = symval;
 
-  nsyms--;                     /* symbol and symval combined are only one symbol */
+  /* symbol and symval combined are only one symbol.  */
+  nsyms--;
 }
 
 
 }
 
 
+static void
+parse_muscle_decl (void)
+{
+  int ch = ungetc (skip_white_space (), finput);
+  char *muscle_key;
+  char *muscle_value;
+
+  /* Read key. */
+  if (!isalpha (ch) && ch != '_')
+    {
+      complain (_("invalid %s declaration"), "%define");
+      skip_to_char ('%');
+      return;
+    }
+  copy_identifier (finput, &muscle_obstack);
+  obstack_1grow (&muscle_obstack, 0);
+  muscle_key = obstack_finish (&muscle_obstack);
+
+  /* Read value. */
+  ch = skip_white_space ();
+  if (ch != '"')
+    {
+      ungetc (ch, finput);
+      if (ch != EOF)
+       {
+         complain (_("invalid %s declaration"), "%define");
+         skip_to_char ('%');
+         return;
+       }
+      else
+       fatal (_("Premature EOF after %s"), "\"");
+    }
+  copy_string2 (finput, &muscle_obstack, '"', 0);
+  obstack_1grow (&muscle_obstack, 0);
+  muscle_value = obstack_finish (&muscle_obstack);
+
+  /* Store the (key, value) pair in the environment. */
+  muscle_insert (muscle_key, muscle_value);
+}
+
+
+
+/*---------------------------------.
+| Parse a double quoted parameter. |
+`---------------------------------*/
+
+static const char *
+parse_dquoted_param (const char *from)
+{
+  struct obstack param_obstack;
+  const char *param = NULL;
+  int c;
+
+  obstack_init (&param_obstack);
+  c = skip_white_space ();
+
+  if (c != '"')
+    {
+      complain (_("invalid %s declaration"), from);
+      ungetc (c, finput);
+      skip_to_char ('%');
+      return NULL;
+    }
+
+  while ((c = literalchar ()) != '"')
+    obstack_1grow (&param_obstack, c);
+
+  obstack_1grow (&param_obstack, '\0');
+  param = obstack_finish (&param_obstack);
+
+  if (c != '"' || strlen (param) == 0)
+    {
+      complain (_("invalid %s declaration"), from);
+      if (c != '"')
+       ungetc (c, finput);
+      skip_to_char ('%');
+      return NULL;
+    }
+
+  return param;
+}
+
+/*----------------------------------.
+| Parse what comes after %skeleton. |
+`----------------------------------*/
+
+static void
+parse_skel_decl (void)
+{
+  skeleton = parse_dquoted_param ("%skeleton");
+}
+
 /*----------------------------------------------------------------.
 | 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
 read_declarations (void)
 {
 `----------------------------------------------------------------*/
 
 static void
 read_declarations (void)
 {
-  int c;
-  int tok;
-
   for (;;)
     {
   for (;;)
     {
-      c = skip_white_space ();
+      int c = skip_white_space ();
 
       if (c == '%')
        {
 
       if (c == '%')
        {
-         tok = parse_percent_token ();
+         token_t tok = parse_percent_token ();
 
          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:
+           case tok_token:
              parse_token_decl (token_sym, nterm_sym);
              break;
 
              parse_token_decl (token_sym, nterm_sym);
              break;
 
-           case NTERM:
+           case tok_nterm:
              parse_token_decl (nterm_sym, token_sym);
              break;
 
              parse_token_decl (nterm_sym, token_sym);
              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:
+           case tok_left:
              parse_assoc_decl (left_assoc);
              break;
 
              parse_assoc_decl (left_assoc);
              break;
 
-           case RIGHT:
+           case tok_right:
              parse_assoc_decl (right_assoc);
              break;
 
              parse_assoc_decl (right_assoc);
              break;
 
-           case NONASSOC:
+           case tok_nonassoc:
              parse_assoc_decl (non_assoc);
              break;
 
              parse_assoc_decl (non_assoc);
              break;
 
-           case SEMANTIC_PARSER:
-             if (semantic_parser == 0)
-               {
-                 semantic_parser = 1;
-                 open_extra_files ();
-               }
+           case tok_define:
+             parse_muscle_decl ();
+             break;
+
+           case tok_skel:
+             parse_skel_decl ();
              break;
 
              break;
 
-           case PURE_PARSER:
-             pure_parser = 1;
+           case tok_noop:
              break;
 
              break;
 
-           case NOOP:
+           case tok_stropt:
+           case tok_intopt:
+           case tok_obsolete:
+             assert (0);
              break;
 
              break;
 
+           case tok_illegal:
            default:
              complain (_("unrecognized: %s"), token_buffer);
              skip_to_char ('%');
            default:
              complain (_("unrecognized: %s"), token_buffer);
              skip_to_char ('%');
@@ -905,7 +1244,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 ('%');
        }
     }
@@ -916,897 +1257,500 @@ read_declarations (void)
 | matching `}' into the actions file.  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.                              |
 | matching `}' into the actions file.  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.                              |
+|                                                                    |
+| This routine is used both for actions and guards.  Only            |
+| ACTION_OBSTACK is used, but this is fine, since we use only        |
+| pointers to relevant portions inside this obstack.                 |
 `-------------------------------------------------------------------*/
 
 static void
 `-------------------------------------------------------------------*/
 
 static void
-copy_action (symbol_list * rule, int stack_offset)
+parse_braces (symbol_list *rule, int stack_offset)
 {
   int c;
 {
   int c;
-  int n;
   int count;
   int count;
-  char *type_name;
-
-  /* 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);
 
   count = 1;
 
   count = 1;
-  c = getc (finput);
-
   while (count > 0)
     {
   while (count > 0)
     {
-      while (c != '}')
-       {
-         switch (c)
-           {
-           case '\n':
-             putc (c, faction);
-             lineno++;
-             break;
-
-           case '{':
-             putc (c, faction);
-             count++;
-             break;
-
-           case '\'':
-           case '"':
-             copy_string (finput, faction, c);
-             break;
-
-           case '/':
-             putc (c, faction);
-             c = getc (finput);
-             if (c != '*' && c != '/')
-               continue;
-             copy_comment (finput, faction, c);
-             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));
-
-             break;
-
-           case '@':
-             copy_at (finput, faction, stack_offset);
-             break;
-
-           case EOF:
-             fatal (_("unmatched %s"), "`{'");
-
-           default:
-             putc (c, faction);
-           }
-
-         c = getc (finput);
-       }
-
-      /* above loop exits when c is '}' */
+      while ((c = getc (finput)) != '}')
+       switch (c)
+         {
+         case '\n':
+           obstack_1grow (&action_obstack, c);
+           ++lineno;
+           break;
+
+         case '{':
+           obstack_1grow (&action_obstack, c);
+           ++count;
+           break;
+
+         case '\'':
+         case '"':
+           copy_string (finput, &action_obstack, c);
+           break;
+
+         case '/':
+           copy_comment (finput, &action_obstack);
+           break;
+
+         case '$':
+           copy_dollar (finput, &action_obstack,
+                        rule, stack_offset);
+           break;
+
+         case '@':
+           copy_at (finput, &action_obstack,
+                    stack_offset);
+           break;
+
+         case EOF:
+           fatal (_("unmatched %s"), "`{'");
+
+         default:
+           obstack_1grow (&action_obstack, c);
+         }
 
 
+      /* Above loop exits when C is '}'.  */
       if (--count)
       if (--count)
-       {
-         putc (c, faction);
-         c = getc (finput);
-       }
+       obstack_1grow (&action_obstack, c);
     }
 
     }
 
-  fprintf (faction, ";\n    break;}");
+  obstack_1grow (&action_obstack, '\0');
 }
 }
-\f
-/*-------------------------------------------------------------------.
-| After `%guard' is seen in the input file, copy the actual guard    |
-| into the guards file.  If the guard is followed by an action, copy |
-| that into the actions file.  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, for the simple parser in which    |
-| the stack is not popped until after the guard is run.              |
-`-------------------------------------------------------------------*/
+
 
 static void
 
 static void
-copy_guard (symbol_list * rule, int stack_offset)
+parse_action (symbol_list *rule, int stack_offset)
 {
 {
-  int c;
-  int n;
-  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;
-
-  fprintf (fguard, "\ncase %d:\n", nrules);
-  if (!nolinesflag)
-    fprintf (fguard, "#line %d \"%s\"\n", lineno, infile);
-  putc ('{', fguard);
-
-  count = 0;
-  c = getc (finput);
-
-  while (brace_flag ? (count > 0) : (c != ';'))
-    {
-      switch (c)
-       {
-       case '\n':
-         putc (c, fguard);
-         lineno++;
-         break;
-
-       case '{':
-         putc (c, fguard);
-         brace_flag = 1;
-         count++;
-         break;
-
-       case '}':
-         putc (c, fguard);
-         if (count > 0)
-           count--;
-         else
-           {
-             complain (_("unmatched %s"), "`}'");
-             c = getc (finput);        /* skip it */
-           }
-         break;
-
-       case '\'':
-       case '"':
-         copy_string (finput, fguard, c);
-         break;
-
-       case '/':
-         putc (c, fguard);
-         c = getc (finput);
-         if (c != '*' && c != '/')
-           continue;
-         copy_comment (finput, fguard, c);
-         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));
-         break;
-
-       case '@':
-         copy_at (finput, fguard, stack_offset);
-         break;
-
-       case EOF:
-         fatal ("%s", _("unterminated %guard clause"));
-
-       default:
-         putc (c, fguard);
-       }
-
-      if (c != '}' || count != 0)
-       c = getc (finput);
-    }
-
-  c = skip_white_space ();
-
-  fprintf (fguard, ";\n    break;}");
-  if (c == '{')
-    copy_action (rule, stack_offset);
-  else if (c == '=')
-    {
-      c = getc (finput);       /* why not skip_white_space -wjh */
-      if (c == '{')
-       copy_action (rule, stack_offset);
-    }
-  else
-    ungetc (c, finput);
+  rule->action_line = lineno;
+  parse_braces (rule, stack_offset);
+  rule->action = obstack_finish (&action_obstack);
 }
 }
-\f
+
 
 static void
 
 static void
-record_rule_line (void)
+parse_guard (symbol_list *rule, int stack_offset)
 {
 {
-  /* Record each rule's source line number in rline table.  */
-
-  if (nrules >= rline_allocated)
-    {
-      rline_allocated = nrules * 2;
-      rline = XREALLOC (rline, short, rline_allocated);
-    }
-  rline[nrules] = lineno;
+  token_t t = lex ();
+  if (t != tok_left_curly)
+    complain (_("invalid %s declaration"), "%guard");
+  rule->guard_line = lineno;
+  parse_braces (rule, stack_offset);
+  rule->guard = obstack_finish (&action_obstack);
 }
 
 }
 
+\f
 
 /*-------------------------------------------------------------------.
 | Generate a dummy symbol, a nonterminal, whose name cannot conflict |
 | with the user's names.                                             |
 `-------------------------------------------------------------------*/
 
 
 /*-------------------------------------------------------------------.
 | Generate a dummy symbol, a nonterminal, whose name cannot conflict |
 | with the user's names.                                             |
 `-------------------------------------------------------------------*/
 
-static bucket *
+static symbol_t *
 gensym (void)
 {
 gensym (void)
 {
-  bucket *sym;
+  /* Incremented for each generated symbol */
+  static int gensym_count = 0;
+  static char buf[256];
+
+  symbol_t *sym;
 
 
-  sprintf (token_buffer, "@%d", ++gensym_count);
+  sprintf (buf, "@%d", ++gensym_count);
+  token_buffer = buf;
   sym = getsym (token_buffer);
   sym->class = nterm_sym;
   sym = getsym (token_buffer);
   sym->class = nterm_sym;
-  sym->value = nvars++;
+  sym->number = nvars++;
   return sym;
 }
   return sym;
 }
-
-#if 0
-/*------------------------------------------------------------------.
-| read in a %type declaration and record its information for        |
-| get_type_name to access.  This is unused.  It is only called from |
-| the #if 0 part of readgram                                        |
-`------------------------------------------------------------------*/
-
-static int
-get_type (void)
-{
-  int k;
-  int t;
-  char *name;
-
-  t = lex ();
-
-  if (t != TYPENAME)
-    {
-      complain (_("invalid %s declaration"), "%type");
-      return t;
-    }
-
-  k = strlen (token_buffer);
-  name = XCALLOC (char, k + 1);
-  strcpy (name, token_buffer);
-
-  for (;;)
-    {
-      t = lex ();
-
-      switch (t)
-       {
-       case SEMICOLON:
-         return lex ();
-
-       case COMMA:
-         break;
-
-       case IDENTIFIER:
-         if (symval->type_name == NULL)
-           symval->type_name = name;
-         else if (strcmp (name, symval->type_name) != 0)
-           complain (_("type redeclaration for %s"), symval->tag);
-
-         break;
-
-       default:
-         return t;
-       }
-    }
-}
-
-#endif
 \f
 \f
-/*------------------------------------------------------------------.
-| Parse the input grammar into a one symbol_list structure.  Each   |
-| rule is represented by a sequence of symbols: the left hand side  |
-| followed by the contents of the right hand side, followed by a    |
-| null pointer instead of a symbol to terminate the rule.  The next |
-| symbol is the lhs of the following rule.                          |
-|                                                                   |
-| All guards and actions are copied out to the appropriate files,   |
-| labelled by the rule number they apply to.                        |
-`------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Parse the input grammar into a one symbol_list structure.  Each    |
+| rule is represented by a sequence of symbols: the left hand side   |
+| followed by the contents of the right hand side, followed by a     |
+| null pointer instead of a symbol to terminate the rule.  The next  |
+| symbol is the lhs of the following rule.                           |
+|                                                                    |
+| All guards and actions are copied out to the appropriate files,    |
+| labelled by the rule number they apply to.                         |
+|                                                                    |
+| Bison used to allow some %directives in the rules sections, but    |
+| this is no longer consider appropriate: (i) the documented grammar |
+| doesn't claim it, (ii), it would promote bad style, (iii), error   |
+| recovery for %directives consists in skipping the junk until a `%' |
+| is seen and helrp synchronizing.  This scheme is definitely wrong  |
+| in the rules section.                                              |
+`-------------------------------------------------------------------*/
 
 static void
 readgram (void)
 {
 
 static void
 readgram (void)
 {
-  int t;
-  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.  */
+  token_t t;
+  symbol_t *lhs = NULL;
+  symbol_list *p = NULL;
+  symbol_list *p1 = NULL;
 
 
-  p1 = NULL;
+  /* Points to first symbol_list of current rule. its symbol is the
+     lhs of the rule.  */
+  symbol_list *crule = NULL;
+  /* Points to the symbol_list preceding crule.  */
+  symbol_list *crule1 = NULL;
 
   t = lex ();
 
 
   t = lex ();
 
-  while (t != TWO_PERCENTS && t != ENDFILE)
-    {
-      if (t == IDENTIFIER || t == BAR)
-       {
-         int actionflag = 0;
-         int rulelength = 0;   /* number of symbols in rhs of this rule so far  */
-         int xactions = 0;     /* JF for error checking */
-         bucket *first_rhs = 0;
+  while (t != tok_two_percents && t != tok_eof)
+    if (t == tok_identifier || t == tok_bar)
+      {
+       int action_flag = 0;
+       /* Number of symbols in rhs of this rule so far */
+       int rulelength = 0;
+       int xactions = 0;       /* JF for error checking */
+       symbol_t *first_rhs = 0;
 
 
-         if (t == IDENTIFIER)
-           {
-             lhs = symval;
-
-             if (!start_flag)
-               {
-                 startval = lhs;
-                 start_flag = 1;
-               }
-
-             t = lex ();
-             if (t != COLON)
-               {
-                 complain (_("ill-formed rule: initial symbol not followed by colon"));
-                 unlex (t);
-               }
-           }
+       if (t == tok_identifier)
+         {
+           lhs = symval;
 
 
-         if (nrules == 0 && t == BAR)
-           {
-             complain (_("grammar starts with vertical bar"));
-             lhs = symval;     /* BOGUS: use a random symval */
-           }
-         /* start a new rule and record its lhs.  */
+           if (!start_flag)
+             {
+               startval = lhs;
+               start_flag = 1;
+             }
 
 
-         nrules++;
-         nitems++;
+           t = lex ();
+           if (t != tok_colon)
+             {
+               complain (_("ill-formed rule: initial symbol not followed by colon"));
+               unlex (t);
+             }
+         }
 
 
-         record_rule_line ();
+       if (nrules == 0 && t == tok_bar)
+         {
+           complain (_("grammar starts with vertical bar"));
+           lhs = symval;       /* BOGUS: use a random symval */
+         }
+       /* start a new rule and record its lhs.  */
 
 
-         p = XCALLOC (symbol_list, 1);
-         p->sym = lhs;
+       ++nrules;
+       ++nritems;
 
 
-         crule1 = p1;
-         if (p1)
-           p1->next = p;
-         else
-           grammar = p;
+       p = symbol_list_new (lhs);
 
 
-         p1 = p;
-         crule = p;
+       crule1 = p1;
+       if (p1)
+         p1->next = p;
+       else
+         grammar = p;
 
 
-         /* mark the rule's lhs as a nonterminal if not already so.  */
+       p1 = p;
+       crule = p;
 
 
-         if (lhs->class == unknown_sym)
-           {
-             lhs->class = nterm_sym;
-             lhs->value = nvars;
-             nvars++;
-           }
-         else if (lhs->class == token_sym)
-           complain (_("rule given for %s, which is a token"), lhs->tag);
+       /* mark the rule's lhs as a nonterminal if not already so.  */
 
 
-         /* read the rhs of the rule.  */
+       if (lhs->class == unknown_sym)
+         {
+           lhs->class = nterm_sym;
+           lhs->number = nvars;
+           ++nvars;
+         }
+       else if (lhs->class == token_sym)
+         complain (_("rule given for %s, which is a token"), lhs->tag);
 
 
-         for (;;)
-           {
-             t = lex ();
-             if (t == PREC)
-               {
-                 t = lex ();
-                 crule->ruleprec = symval;
-                 t = lex ();
-               }
-
-             if (!(t == IDENTIFIER || t == LEFT_CURLY))
-               break;
-
-             /* If next token is an identifier, see if a colon follows it.
-                If one does, exit this rule now.  */
-             if (t == IDENTIFIER)
-               {
-                 bucket *ssave;
-                 int t1;
-
-                 ssave = symval;
-                 t1 = lex ();
-                 unlex (t1);
-                 symval = ssave;
-                 if (t1 == COLON)
-                   break;
+       /* read the rhs of the rule.  */
 
 
-                 if (!first_rhs)       /* JF */
-                   first_rhs = symval;
-                 /* Not followed by colon =>
-                    process as part of this rule's rhs.  */
-               }
-
-             /* 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)
-               {
-                 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.  */
-
-                 /* Make a dummy nonterminal, a gensym.  */
-                 sdummy = gensym ();
-
-                 /* Make a new rule, whose body is empty,
-                    before the current one, so that the action
-                    just read can belong to it.  */
-                 nrules++;
-                 nitems++;
-                 record_rule_line ();
-                 p = XCALLOC (symbol_list, 1);
-                 if (crule1)
-                   crule1->next = p;
-                 else
-                   grammar = p;
-                 p->sym = sdummy;
-                 crule1 = XCALLOC (symbol_list, 1);
-                 p->next = crule1;
-                 crule1->next = crule;
-
-                 /* insert the dummy generated by that rule into this rule.  */
-                 nitems++;
-                 p = XCALLOC (symbol_list, 1);
-                 p->sym = sdummy;
-                 p1->next = p;
-                 p1 = p;
-
-                 actionflag = 0;
-               }
-
-             if (t == IDENTIFIER)
-               {
-                 nitems++;
-                 p = XCALLOC (symbol_list, 1);
-                 p->sym = symval;
-                 p1->next = p;
-                 p1 = p;
-               }
-             else              /* handle an action.  */
-               {
-                 copy_action (crule, rulelength);
-                 actionflag = 1;
-                 xactions++;   /* JF */
-               }
-             rulelength++;
-           }                   /* end of  read rhs of rule */
-
-         /* Put an empty link in the list to mark the end of this rule  */
-         p = XCALLOC (symbol_list, 1);
-         p1->next = p;
-         p1 = p;
+       for (;;)
+         {
+           t = lex ();
+           if (t == tok_prec)
+             {
+               t = lex ();
+               crule->ruleprec = symval;
+               t = lex ();
+             }
+
+           if (!(t == tok_identifier || t == tok_left_curly))
+             break;
 
 
-         if (t == PREC)
-           {
-             complain (_("two @prec's in a row"));
-             t = lex ();
-             crule->ruleprec = symval;
-             t = lex ();
-           }
-         if (t == GUARD)
-           {
-             if (!semantic_parser)
-               complain ("%s",
-                         _
-                         ("%guard present but %semantic_parser not specified"));
+           /* If next token is an identifier, see if a colon follows it.
+              If one does, exit this rule now.  */
+           if (t == tok_identifier)
+             {
+               symbol_t *ssave;
+               token_t t1;
+
+               ssave = symval;
+               t1 = lex ();
+               unlex (t1);
+               symval = ssave;
+               if (t1 == tok_colon)
+                 {
+                   warn (_("previous rule lacks an ending `;'"));
+                   break;
+                 }
+
+               if (!first_rhs) /* JF */
+                 first_rhs = symval;
+               /* Not followed by colon =>
+                  process as part of this rule's rhs.  */
+             }
+
+           /* 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 (action_flag)
+             {
+               /* 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.  */
+               symbol_t *sdummy = gensym ();
+
+               /* Make a new rule, whose body is empty, before the
+                  current one, so that the action just read can
+                  belong to it.  */
+               ++nrules;
+               ++nritems;
+               p = symbol_list_new (sdummy);
+               /* Attach its lineno to that of the host rule. */
+               p->line = crule->line;
+               /* Move the action from the host rule to this one. */
+               p->action = crule->action;
+               p->action_line = crule->action_line;
+               crule->action = NULL;
+
+               if (crule1)
+                 crule1->next = p;
+               else
+                 grammar = p;
+               /* End of the rule. */
+               crule1 = symbol_list_new (NULL);
+               crule1->next = crule;
+
+               p->next = crule1;
+
+               /* Insert the dummy generated by that rule into this
+                  rule.  */
+               ++nritems;
+               p = symbol_list_new (sdummy);
+               p1->next = p;
+               p1 = p;
+
+               action_flag = 0;
+             }
+
+           if (t == tok_identifier)
+             {
+               ++nritems;
+               p = symbol_list_new (symval);
+               p1->next = p;
+               p1 = p;
+             }
+           else                /* handle an action.  */
+             {
+               parse_action (crule, rulelength);
+               action_flag = 1;
+               ++xactions;     /* JF */
+             }
+           ++rulelength;
+         }                     /* end of  read rhs of rule */
+
+       /* Put an empty link in the list to mark the end of this rule  */
+       p = symbol_list_new (NULL);
+       p1->next = p;
+       p1 = p;
+
+       if (t == tok_prec)
+         {
+           complain (_("two @prec's in a row"));
+           t = lex ();
+           crule->ruleprec = symval;
+           t = lex ();
+         }
 
 
-             copy_guard (crule, rulelength);
-             t = lex ();
-           }
-         else if (t == LEFT_CURLY)
-           {
-             /* This case never occurs -wjh */
-             if (actionflag)
-               complain (_("two actions at end of one rule"));
-             copy_action (crule, rulelength);
-             actionflag = 1;
-             xactions++;       /* -wjh */
-             t = lex ();
-           }
-         /* If $$ is being set in default way, report if any type
-            mismatch.  */
-         else if (!xactions
-                  && first_rhs && lhs->type_name != first_rhs->type_name)
-           {
-             if (lhs->type_name == 0
-                 || first_rhs->type_name == 0
-                 || strcmp (lhs->type_name, first_rhs->type_name))
-               complain (_("type clash (`%s' `%s') on default action"),
-                         lhs->type_name ? lhs->type_name : "",
-                         first_rhs->type_name ? first_rhs->type_name : "");
-           }
-         /* 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_guard)
+         {
+           if (!semantic_parser)
+             complain (_("%%guard present but %%semantic_parser not specified"));
+
+           parse_guard (crule, rulelength);
            t = lex ();
            t = lex ();
-       }
-#if 0
-      /* these things can appear as alternatives to rules.  */
-/* NO, they cannot.
-       a) none of the documentation allows them
-       b) most of them scan forward until finding a next %
-               thus they may swallow lots of intervening rules
-*/
-      else if (t == TOKEN)
-       {
-         parse_token_decl (token_sym, nterm_sym);
-         t = lex ();
-       }
-      else if (t == NTERM)
-       {
-         parse_token_decl (nterm_sym, token_sym);
-         t = lex ();
-       }
-      else if (t == TYPE)
-       {
-         t = get_type ();
-       }
-      else if (t == UNION)
-       {
-         parse_union_decl ();
-         t = lex ();
-       }
-      else if (t == EXPECT)
-       {
-         parse_expect_decl ();
-         t = lex ();
-       }
-      else if (t == START)
-       {
-         parse_start_decl ();
-         t = lex ();
-       }
-#endif
+         }
 
 
-      else
-       {
-         complain (_("invalid input: %s"), token_buffer);
+       if (t == tok_left_curly)
+         {
+           /* This case never occurs -wjh */
+           if (action_flag)
+             complain (_("two actions at end of one rule"));
+           parse_action (crule, rulelength);
+           action_flag = 1;
+           ++xactions; /* -wjh */
+           t = lex ();
+         }
+       /* If $$ is being set in default way, report if any type
+          mismatch.  */
+       else if (!xactions
+                && first_rhs && lhs->type_name != first_rhs->type_name)
+         {
+           if (lhs->type_name == 0
+               || first_rhs->type_name == 0
+               || strcmp (lhs->type_name, first_rhs->type_name))
+             complain (_("type clash (`%s' `%s') on default action"),
+                       lhs->type_name ? lhs->type_name : "",
+                       first_rhs->type_name ? first_rhs->type_name : "");
+         }
+       /* 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 == tok_two_percents || t == tok_eof)
+         warn (_("previous rule lacks an ending `;'"));
+       if (t == tok_semicolon)
          t = lex ();
          t = lex ();
-       }
-    }
+      }
+    else
+      {
+       complain (_("invalid input: %s"), quote (token_buffer));
+       t = lex ();
+      }
 
   /* grammar has been read.  Do some checking */
 
 
   /* grammar has been read.  Do some checking */
 
-  if (nsyms > MAXSHORT)
-    fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
-          MAXSHORT);
   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 */
-      && !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");
-    }
-
   /* Report any undefined symbols and consider them nonterminals.  */
   /* Report any undefined symbols and consider them nonterminals.  */
+  symbols_do (symbol_check_defined, NULL);
+
+  /* Insert the initial rule, which line is that of the first rule
+     (not that of the start symbol):
+
+     axiom: %start EOF.  */
+  p = symbol_list_new (axiom);
+  p->line = grammar->line;
+  p->next = symbol_list_new (startval);
+  p->next->next = symbol_list_new (eoftoken);
+  p->next->next->next = symbol_list_new (NULL);
+  p->next->next->next->next = grammar;
+  nrules += 1;
+  nritems += 3;
+  grammar = p;
+  startval = axiom;
+
+  if (nsyms > SHRT_MAX)
+    fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
+          SHRT_MAX);
 
 
-  for (bp = firstsymbol; bp; bp = bp->next)
-    if (bp->class == unknown_sym)
-      {
-       complain (_
-                 ("symbol %s is used, but is not defined as a token and has no rules"),
-bp->tag);
-       bp->class = nterm_sym;
-       bp->value = nvars++;
-      }
-
-  ntokens = nsyms - nvars;
+  assert (nsyms == ntokens + nvars);
 }
 }
-\f
-/*--------------------------------------------------------------.
-| For named tokens, but not literal ones, define the name.  The |
-| value is the user token number.                               |
-`--------------------------------------------------------------*/
 
 
+/* At the end of the grammar file, some C source code must
+   be stored. It is going to be associated to the epilogue
+   directive.  */
 static void
 static void
-output_token_defines (FILE *file)
+read_additionnal_code (void)
 {
 {
-  bucket *bp;
-  char *cp, *symbol;
-  char c;
+  int c;
+  struct obstack el_obstack;
 
 
-  for (bp = firstsymbol; bp; bp = bp->next)
-    {
-      symbol = bp->tag;                /* get symbol */
-
-      if (bp->value >= ntokens)
-       continue;
-      if (bp->user_token_number == SALIAS)
-       continue;
-      if ('\'' == *symbol)
-       continue;               /* skip literal character */
-      if (bp == errtoken)
-       continue;               /* skip error token */
-      if ('\"' == *symbol)
-       {
-         /* use literal string only if given a symbol with an alias */
-         if (bp->alias)
-           symbol = bp->alias->tag;
-         else
-           continue;
-       }
+  obstack_init (&el_obstack);
 
 
-      /* Don't #define nonliteral tokens whose names contain periods.  */
-      cp = symbol;
-      while ((c = *cp++) && c != '.');
-      if (c != '\0')
-       continue;
-
-      fprintf (file, "#define\t%s\t%d\n", symbol,
-              ((translations && !rawtoknumflag)
-               ? bp->user_token_number : bp->value));
-      if (semantic_parser)
-       fprintf (file, "#define\tT%s\t%d\n", symbol, bp->value);
+  if (!no_lines_flag)
+    {
+      obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
+                     lineno, quotearg_style (c_quoting_style,
+                                             muscle_find ("filename")));
     }
 
     }
 
-  putc ('\n', file);
-}
+  while ((c = getc (finput)) != EOF)
+    obstack_1grow (&el_obstack, c);
 
 
+  obstack_1grow (&el_obstack, 0);
+  muscle_insert ("epilogue", obstack_finish (&el_obstack));
+}
 
 
+\f
 /*------------------------------------------------------------------.
 /*------------------------------------------------------------------.
-| Assign symbol numbers, and write definition of token names into   |
-| FDEFINES.  Set up vectors TAGS and SPREC of names and precedences |
-| of symbols.                                                       |
+| Set TOKEN_TRANSLATIONS.  Check that no two symbols share the same |
+| number.                                                           |
 `------------------------------------------------------------------*/
 
 static void
 `------------------------------------------------------------------*/
 
 static void
-packsymbols (void)
+token_translations_init (void)
 {
 {
-  bucket *bp;
-  int tokno = 1;
+  int num_256_available_p = TRUE;
   int i;
   int i;
-  int last_user_token_number;
-  static char DOLLAR[] = "$";
-
-  /* int lossage = 0; JF set but not used */
 
 
-  tags = XCALLOC (char *, nsyms + 1);
-  tags[0] = DOLLAR;
-  user_toknums = XCALLOC (short, nsyms + 1);
-  user_toknums[0] = 0;
-
-  sprec = XCALLOC (short, nsyms);
-  sassoc = XCALLOC (short, nsyms);
-
-  max_user_token_number = 256;
-  last_user_token_number = 256;
-
-  for (bp = firstsymbol; bp; bp = bp->next)
+  /* Find the highest user token number, and whether 256, the POSIX
+     preferred user token number for the error token, is used.  */
+  max_user_token_number = 0;
+  for (i = 0; i < ntokens; ++i)
     {
     {
-      if (bp->class == nterm_sym)
-       {
-         bp->value += ntokens;
-       }
-      else if (bp->alias)
-       {
-         /* this symbol and its alias are a single token defn.
-            allocate a tokno, and assign to both check agreement of
-            ->prec and ->assoc fields and make both the same */
-         if (bp->value == 0)
-           bp->value = bp->alias->value = tokno++;
-
-         if (bp->prec != bp->alias->prec)
-           {
-             if (bp->prec != 0 && bp->alias->prec != 0
-                 && bp->user_token_number == SALIAS)
-               complain (_("conflicting precedences for %s and %s"),
-                         bp->tag, bp->alias->tag);
-             if (bp->prec != 0)
-               bp->alias->prec = bp->prec;
-             else
-               bp->prec = bp->alias->prec;
-           }
-
-         if (bp->assoc != bp->alias->assoc)
-           {
-             if (bp->assoc != 0 && bp->alias->assoc != 0
-                 && bp->user_token_number == SALIAS)
-               complain (_("conflicting assoc values for %s and %s"),
-                         bp->tag, bp->alias->tag);
-             if (bp->assoc != 0)
-               bp->alias->assoc = bp->assoc;
-             else
-               bp->assoc = bp->alias->assoc;
-           }
-
-         if (bp->user_token_number == SALIAS)
-           continue;           /* do not do processing below for SALIASs */
-
-       }
-      else                     /* bp->class == token_sym */
+      symbol_t *this = symbols[i];
+      if (this->user_token_number != SUNDEF)
        {
        {
-         bp->value = tokno++;
+         if (this->user_token_number > max_user_token_number)
+           max_user_token_number = this->user_token_number;
+         if (this->user_token_number == 256)
+           num_256_available_p = FALSE;
        }
        }
+    }
 
 
-      if (bp->class == token_sym)
-       {
-         if (translations && !(bp->user_token_number))
-           bp->user_token_number = ++last_user_token_number;
-         if (bp->user_token_number > max_user_token_number)
-           max_user_token_number = bp->user_token_number;
-       }
+  /* If 256 is not used, assign it to error, to follow POSIX.  */
+  if (num_256_available_p && errtoken->user_token_number == SUNDEF)
+    errtoken->user_token_number = 256;
 
 
-      tags[bp->value] = bp->tag;
-      user_toknums[bp->value] = bp->user_token_number;
-      sprec[bp->value] = bp->prec;
-      sassoc[bp->value] = bp->assoc;
+  /* Set the missing user numbers. */
+  if (max_user_token_number < 256)
+    max_user_token_number = 256;
 
 
+  for (i = 0; i < ntokens; ++i)
+    {
+      symbol_t *this = symbols[i];
+      if (this->user_token_number == SUNDEF)
+       this->user_token_number = ++max_user_token_number;
+      if (this->user_token_number > max_user_token_number)
+       max_user_token_number = this->user_token_number;
     }
 
     }
 
-  if (translations)
-    {
-      int j;
+  token_translations = XCALLOC (token_number_t, max_user_token_number + 1);
 
 
-      token_translations = XCALLOC (short, max_user_token_number + 1);
+  /* Initialize all entries for literal tokens to 2, the internal
+     token number for $undefined., which represents all invalid
+     inputs.  */
+  for (i = 0; i < max_user_token_number + 1; i++)
+    token_translations[i] = undeftoken->number;
+  symbols_do (symbol_translation, NULL);
+}
 
 
-      /* initialize all entries for literal tokens to 2, the internal
-         token number for $undefined., which represents all invalid
-         inputs.  */
-      for (j = 0; j <= max_user_token_number; j++)
-       token_translations[j] = 2;
 
 
-      for (bp = firstsymbol; bp; bp = bp->next)
-       {
-         if (bp->value >= ntokens)
-           continue;           /* non-terminal */
-         if (bp->user_token_number == SALIAS)
-           continue;
-         if (token_translations[bp->user_token_number] != 2)
-           complain (_("tokens %s and %s both assigned number %d"),
-                     tags[token_translations[bp->user_token_number]],
-                     bp->tag, bp->user_token_number);
-         token_translations[bp->user_token_number] = bp->value;
-       }
-    }
+/*----------------------------------------------------------------.
+| Assign symbol numbers, and write definition of token names into |
+| FDEFINES.  Set up vectors SYMBOL_TABLE, TAGS of symbols.        |
+`----------------------------------------------------------------*/
 
 
-  error_token_number = errtoken->value;
+static void
+packsymbols (void)
+{
+  symbols = XCALLOC (symbol_t *, nsyms);
+
+  symbols_do (symbol_check_alias_consistence, NULL);
+  symbols_do (symbol_pack, NULL);
 
 
-  if (!noparserflag)
-    output_token_defines (ftable);
+  token_translations_init ();
 
   if (startval->class == unknown_sym)
     fatal (_("the start symbol %s is undefined"), startval->tag);
   else if (startval->class == token_sym)
     fatal (_("the start symbol %s is a token"), startval->tag);
 
 
   if (startval->class == unknown_sym)
     fatal (_("the start symbol %s is undefined"), startval->tag);
   else if (startval->class == token_sym)
     fatal (_("the start symbol %s is a token"), startval->tag);
 
-  start_symbol = startval->value;
-
-  if (definesflag)
-    {
-      output_token_defines (fdefines);
-
-      if (!pure_parser)
-       {
-         if (spec_name_prefix)
-           fprintf (fdefines, "\nextern YYSTYPE %slval;\n",
-                    spec_name_prefix);
-         else
-           fprintf (fdefines, "\nextern YYSTYPE yylval;\n");
-       }
-
-      if (semantic_parser)
-       for (i = ntokens; i < nsyms; 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);
-         }
-#if 0
-      /* `fdefines' is now a temporary file, so we need to copy its
-         contents in `done', so we can't close it here.  */
-      fclose (fdefines);
-      fdefines = NULL;
-#endif
-    }
+  start_symbol = startval->number;
 }
 
 
 /*---------------------------------------------------------------.
 | Convert the rules into the representation using RRHS, RLHS and |
 }
 
 
 /*---------------------------------------------------------------.
 | Convert the rules into the representation using RRHS, RLHS and |
-| RITEMS.                                                        |
+| RITEM                                                        |
 `---------------------------------------------------------------*/
 
 static void
 `---------------------------------------------------------------*/
 
 static void
@@ -1816,14 +1760,8 @@ packgram (void)
   int ruleno;
   symbol_list *p;
 
   int ruleno;
   symbol_list *p;
 
-  bucket *ruleprec;
-
-  ritem = XCALLOC (short, nitems + 1);
-  rlhs = XCALLOC (short, nrules) - 1;
-  rrhs = XCALLOC (short, nrules) - 1;
-  rprec = XCALLOC (short, nrules) - 1;
-  rprecsym = XCALLOC (short, nrules) - 1;
-  rassoc = XCALLOC (short, nrules) - 1;
+  ritem = XCALLOC (item_number_t, nritems + 1);
+  rules = XCALLOC (rule_t, nrules) - 1;
 
   itemno = 0;
   ruleno = 1;
 
   itemno = 0;
   ruleno = 1;
@@ -1831,21 +1769,28 @@ packgram (void)
   p = grammar;
   while (p)
     {
   p = grammar;
   while (p)
     {
-      rlhs[ruleno] = p->sym->value;
-      rrhs[ruleno] = itemno;
-      ruleprec = p->ruleprec;
+      symbol_t *ruleprec = p->ruleprec;
+      rules[ruleno].user_number = ruleno;
+      rules[ruleno].number = ruleno;
+      rules[ruleno].lhs = p->sym;
+      rules[ruleno].rhs = ritem + itemno;
+      rules[ruleno].line = p->line;
+      rules[ruleno].useful = TRUE;
+      rules[ruleno].action = p->action;
+      rules[ruleno].action_line = p->action_line;
+      rules[ruleno].guard = p->guard;
+      rules[ruleno].guard_line = p->guard_line;
 
       p = p->next;
       while (p && p->sym)
        {
 
       p = p->next;
       while (p && p->sym)
        {
-         ritem[itemno++] = p->sym->value;
+         /* item_number_t = token_number_t.
+            But the former needs to contain more: negative rule numbers. */
+         ritem[itemno++] = token_number_as_item_number (p->sym->number);
          /* A rule gets by default the precedence and associativity
             of the last token in it.  */
          if (p->sym->class == token_sym)
          /* A rule gets by default the precedence and associativity
             of the last token in it.  */
          if (p->sym->class == token_sym)
-           {
-             rprec[ruleno] = p->sym->prec;
-             rassoc[ruleno] = p->sym->assoc;
-           }
+           rules[ruleno].prec = p->sym;
          if (p)
            p = p->next;
        }
          if (p)
            p = p->next;
        }
@@ -1854,136 +1799,106 @@ packgram (void)
          the specified symbol's precedence replaces the default.  */
       if (ruleprec)
        {
          the specified symbol's precedence replaces the default.  */
       if (ruleprec)
        {
-         rprec[ruleno] = ruleprec->prec;
-         rassoc[ruleno] = ruleprec->assoc;
-         rprecsym[ruleno] = ruleprec->value;
+         rules[ruleno].precsym = ruleprec;
+         rules[ruleno].prec = ruleprec;
        }
        }
-
       ritem[itemno++] = -ruleno;
       ritem[itemno++] = -ruleno;
-      ruleno++;
+      ++ruleno;
 
       if (p)
        p = p->next;
     }
 
   ritem[itemno] = 0;
 
       if (p)
        p = p->next;
     }
 
   ritem[itemno] = 0;
+  assert (itemno == nritems);
+
+  if (trace_flag)
+    ritem_print (stderr);
 }
 \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
 reader (void)
 {
 `-------------------------------------------------------------------*/
 
 void
 reader (void)
 {
-  start_flag = 0;
-  startval = NULL;             /* start symbol not specified yet. */
-
-#if 0
-  /* initially assume token number translation not needed.  */
-  translations = 0;
-#endif
-  /* Nowadays translations is always set to 1, since we give `error' a
-     user-token-number to satisfy the Posix demand for YYERRCODE==256.
-   */
-  translations = 1;
-
-  nsyms = 1;
-  nvars = 0;
-  nrules = 0;
-  nitems = 0;
-  rline_allocated = 10;
-  rline = XCALLOC (short, rline_allocated);
-
-  typed = 0;
-  lastprec = 0;
-
-  gensym_count = 0;
+  lex_init ();
+  lineno = 1;
 
 
-  semantic_parser = 0;
-  pure_parser = 0;
-  yylsp_needed = 0;
+  /* Initialize the muscle obstack.  */
+  obstack_init (&muscle_obstack);
 
 
-  grammar = NULL;
+  /* Initialize the symbol table.  */
+  symbols_new ();
 
 
-  init_lex ();
-  lineno = 1;
+  /* Construct the axiom symbol. */
+  axiom = getsym ("$axiom");
+  axiom->class = nterm_sym;
+  axiom->number = nvars++;
 
 
-  /* Initialize the symbol table.  */
-  tabinit ();
   /* Construct the error token */
   errtoken = getsym ("error");
   errtoken->class = token_sym;
   /* Construct the error token */
   errtoken = getsym ("error");
   errtoken->class = token_sym;
-  errtoken->user_token_number = 256;   /* Value specified by POSIX.  */
+  errtoken->number = ntokens++;
+
   /* Construct a token that represents all undefined literal tokens.
      It is always token number 2.  */
   undeftoken = getsym ("$undefined.");
   undeftoken->class = token_sym;
   /* Construct a token that represents all undefined literal tokens.
      It is always token number 2.  */
   undeftoken = getsym ("$undefined.");
   undeftoken->class = token_sym;
-  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, "\
-/* %s, made from %s\n\
-   by GNU bison %s.  */\n\
-\n", noparserflag ? "Bison-generated parse tables" : "A Bison parser", infile, VERSION);
-
-  fputs ("#define YYBISON 1  /* Identify Bison output.  */\n\n", ftable);
+  undeftoken->number = ntokens++;
+
+  /* Initialize the obstacks. */
+  obstack_init (&action_obstack);
+  obstack_init (&attrs_obstack);
+  obstack_init (&output_obstack);
+
+  finput = xfopen (infile, "r");
+
+  /* Read the declaration section.  Copy %{ ... %} groups to
+     TABLE_OBSTACK and FDEFINES file.  Also notice any %token, %left,
+     etc. found there.  */
   read_declarations ();
   read_declarations ();
-  /* Start writing the guard and action files, if they are needed.  */
-  output_headers ();
+
+  /* If the user did not define her EOFTOKEN, do it now. */
+  if (!eoftoken)
+    {
+      eoftoken = getsym ("$");
+      eoftoken->class = token_sym;
+      eoftoken->number = 0;
+      /* Value specified by POSIX.  */
+      eoftoken->user_token_number = 0;
+    }
+
   /* Read in the grammar, build grammar in list form.  Write out
      guards and actions.  */
   readgram ();
   /* Read in the grammar, build grammar in list form.  Write out
      guards and actions.  */
   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);
-  /* Write closing delimiters for actions and guards.  */
-  output_trailers ();
-  if (yylsp_needed)
-    fputs ("#define YYLSP_NEEDED\n\n", ftable);
+  /* Some C code is given at the end of the grammar file. */
+  read_additionnal_code ();
+
+  lex_free ();
+  xfclose (finput);
+
   /* 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 ();
+
   /* Convert the grammar into the format described in gram.h.  */
   packgram ();
   /* Convert the grammar into the format described in gram.h.  */
   packgram ();
-  /* Free the symbol table data structure since symbols are now all
-     referred to by symbol number.  */
-  free_symtab ();
-}
 
 
+  /* The grammar as a symbol_list is no longer needed. */
+  LIST_FREE (symbol_list, grammar);
+}
 
 void
 
 void
-reader_output_yylsp (FILE *f)
+grammar_free (void)
 {
 {
-  if (yylsp_needed)
-    fputs ("\
-\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",
-          f);
+  XFREE (ritem);
+  free (rules + 1);
+  /* Free the symbol table data structure.  */
+  symbols_free ();
 }
 }