]> git.saurik.com Git - bison.git/blobdiff - src/reader.c
Warnings.
[bison.git] / src / reader.c
index bebbc1539b494ff3ab31b817aa1a9b3d36c029c8..da97aa415ff179fa6c0e87487a06f4691f72cb9d 100644 (file)
@@ -1,5 +1,5 @@
 /* Input parser for bison
 /* Input parser for bison
-   Copyright 1984, 1986, 1989, 1992, 1998, 2000, 2001
+   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.
 typedef struct symbol_list
 {
   struct symbol_list *next;
 typedef struct symbol_list
 {
   struct symbol_list *next;
-  bucket *sym;
+  symbol_t *sym;
   int line;
 
   /* The action is attached to the LHS of a rule. */
   const char *action;
   int action_line;
 
   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;
-  bucket *ruleprec;
+  symbol_t *ruleprec;
 } symbol_list;
 
 int lineno;
 } symbol_list;
 
 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;
 
 
-static bucket *errtoken = NULL;
-static bucket *undeftoken = NULL;
-static bucket *eoftoken = NULL;
-static bucket *axiom = NULL;
+symbol_t *errtoken = NULL;
+symbol_t *undeftoken = NULL;
+symbol_t *eoftoken = NULL;
+symbol_t *axiom = NULL;
 
 static symbol_list *
 
 static symbol_list *
-symbol_list_new (bucket *sym)
+symbol_list_new (symbol_t *sym)
 {
   symbol_list *res = XMALLOC (symbol_list, 1);
   res->next = NULL;
 {
   symbol_list *res = XMALLOC (symbol_list, 1);
   res->next = NULL;
@@ -82,12 +77,171 @@ symbol_list_new (bucket *sym)
   res->line = lineno;
   res->action = NULL;
   res->action_line = 0;
   res->line = lineno;
   res->action = NULL;
   res->action_line = 0;
-  res->guard = NULL;
-  res->guard_line = 0;
   res->ruleprec = NULL;
   return res;
 }
 
   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;
+}
+
+
+
+
+/*--------------------------------------------------.
+| Put THIS in TOKEN_TRANSLATIONS if it is a token.  |
+`--------------------------------------------------*/
+
+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;
+    }
+
+  return TRUE;
+}
 \f
 
 /*===================\
 \f
 
 /*===================\
@@ -167,12 +321,34 @@ get_type_name (int n, symbol_list *rule)
          complain (_("invalid $ value"));
          return NULL;
        }
          complain (_("invalid $ value"));
          return NULL;
        }
-      i++;
+      ++i;
     }
 
   return rp->sym->type_name;
 }
 \f
     }
 
   return rp->sym->type_name;
 }
 \f
+/*------------------------------------------------------------------.
+| Copy the character C to OOUT, and insert quadigraphs when needed. |
+`------------------------------------------------------------------*/
+
+static inline void
+copy_character (struct obstack *oout, int c)
+{
+  switch (c)
+    {
+    case '[':
+      obstack_sgrow (oout, "@<:@");
+      break;
+
+    case ']':
+      obstack_sgrow (oout, "@:>@");
+      break;
+
+    default:
+      obstack_1grow (oout, c);
+    }
+}
+
 /*------------------------------------------------------------.
 | Dump the string from FIN to OOUT if non null.  MATCH is the |
 | delimiter of the string (either ' or ").                    |
 /*------------------------------------------------------------.
 | Dump the string from FIN to OOUT if non null.  MATCH is the |
 | delimiter of the string (either ' or ").                    |
@@ -200,17 +376,17 @@ copy_string2 (FILE *fin, struct obstack *oout, int match, int store)
          continue;
        }
 
          continue;
        }
 
-      obstack_1grow (oout, c);
+      copy_character (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"));
-         obstack_1grow (oout, c);
+         copy_character (oout, c);
 
          if (c == '\n')
 
          if (c == '\n')
-           lineno++;
+           ++lineno;
        }
 
       c = getc (fin);
        }
 
       c = getc (fin);
@@ -293,7 +469,7 @@ copy_comment (FILE *fin, struct obstack *oout)
        }
       else if (c == '\n')
        {
        }
       else if (c == '\n')
        {
-         lineno++;
+         ++lineno;
          obstack_1grow (oout, c);
          if (cplus_comment)
            ended = 1;
          obstack_1grow (oout, c);
          if (cplus_comment)
            ended = 1;
@@ -304,30 +480,29 @@ copy_comment (FILE *fin, struct obstack *oout)
        fatal (_("unterminated comment"));
       else
        {
        fatal (_("unterminated comment"));
       else
        {
-         obstack_1grow (oout, c);
+         copy_character (oout, c);
          c = getc (fin);
        }
     }
 }
 
 
          c = getc (fin);
        }
     }
 }
 
 
-/*-----------------------------------------------------------------.
-| 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.                                 |
-`-----------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| FIN is pointing to a location (i.e., a `@').  Output to OOUT a     |
+| reference to this location. RULE_LENGTH 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
 
 static inline void
-copy_at (FILE *fin, struct obstack *oout, int stack_offset)
+copy_at (FILE *fin, struct obstack *oout, int rule_length)
 {
 {
-  int c;
+  int c = getc (fin);
+  locations_flag = 1;
 
 
-  c = getc (fin);
   if (c == '$')
     {
   if (c == '$')
     {
-      obstack_sgrow (oout, "yyloc");
-      locations_flag = 1;
+      obstack_sgrow (oout, "]b4_lhs_location[");
     }
   else if (isdigit (c) || c == '-')
     {
     }
   else if (isdigit (c) || c == '-')
     {
@@ -335,16 +510,11 @@ copy_at (FILE *fin, struct obstack *oout, int stack_offset)
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
-      if (n > stack_offset)
+      if (n > rule_length)
        complain (_("invalid value: %s%d"), "@", n);
       else
        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;
-       }
+       obstack_fgrow2 (oout, "]b4_rhs_location([%d], [%d])[",
+                       rule_length, n);
     }
   else
     {
     }
   else
     {
@@ -355,19 +525,19 @@ copy_at (FILE *fin, struct obstack *oout, int stack_offset)
 }
 
 
 }
 
 
-/*-------------------------------------------------------------------.
-| 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.                 |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| FIN is pointing to a wannabee semantic value (i.e., a `$').       |
+|                                                                   |
+| Possible inputs: $[<TYPENAME>]($|integer)                         |
+|                                                                   |
+| Output to OOUT a reference to this semantic value. RULE_LENGTH 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,
 
 static inline void
 copy_dollar (FILE *fin, struct obstack *oout,
-            symbol_list *rule, int stack_offset)
+            symbol_list *rule, int rule_length)
 {
   int c = getc (fin);
   const char *type_name = NULL;
 {
   int c = getc (fin);
   const char *type_name = NULL;
@@ -383,15 +553,15 @@ copy_dollar (FILE *fin, struct obstack *oout,
 
   if (c == '$')
     {
 
   if (c == '$')
     {
-      obstack_sgrow (oout, "yyval");
-
       if (!type_name)
        type_name = get_type_name (0, rule);
       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);
       if (!type_name && typed)
        complain (_("$$ of `%s' has no declared type"),
                  rule->sym->tag);
+      if (!type_name)
+       type_name = "";
+      obstack_fgrow1 (oout,
+                     "]b4_lhs_value([%s])[", type_name);
     }
   else if (isdigit (c) || c == '-')
     {
     }
   else if (isdigit (c) || c == '-')
     {
@@ -399,23 +569,19 @@ copy_dollar (FILE *fin, struct obstack *oout,
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
-      if (n > stack_offset)
+      if (n > rule_length)
        complain (_("invalid value: %s%d"), "$", n);
       else
        {
          if (!type_name && n > 0)
            type_name = get_type_name (n, rule);
        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);
          if (!type_name && typed)
            complain (_("$%d of `%s' has no declared type"),
                      n, rule->sym->tag);
+         if (!type_name)
+           type_name = "";
+         obstack_fgrow3 (oout, "]b4_rhs_value([%d], [%d], [%s])[",
+                         rule_length, n, type_name);
        }
     }
   else
        }
     }
   else
@@ -432,7 +598,7 @@ copy_dollar (FILE *fin, struct obstack *oout,
 `-------------------------------------------------------------------*/
 
 static void
 `-------------------------------------------------------------------*/
 
 static void
-copy_definition (void)
+copy_definition (struct obstack *oout)
 {
   int c;
   /* -1 while reading a character if prev char was %. */
 {
   int c;
   /* -1 while reading a character if prev char was %. */
@@ -440,7 +606,7 @@ copy_definition (void)
 
   if (!no_lines_flag)
     {
 
   if (!no_lines_flag)
     {
-      obstack_fgrow2 (&attrs_obstack, muscle_find ("linef"),
+      obstack_fgrow2 (oout, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
                                              muscle_find ("filename")));
     }
                      lineno, quotearg_style (c_quoting_style,
                                              muscle_find ("filename")));
     }
@@ -454,8 +620,8 @@ copy_definition (void)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         obstack_1grow (&attrs_obstack, c);
-         lineno++;
+         obstack_1grow (oout, c);
+         ++lineno;
          break;
 
        case '%':
          break;
 
        case '%':
@@ -464,18 +630,18 @@ copy_definition (void)
 
        case '\'':
        case '"':
 
        case '\'':
        case '"':
-         copy_string (finput, &attrs_obstack, c);
+         copy_string (finput, oout, c);
          break;
 
        case '/':
          break;
 
        case '/':
-         copy_comment (finput, &attrs_obstack);
+         copy_comment (finput, oout);
          break;
 
        case EOF:
          fatal ("%s", _("unterminated `%{' definition"));
 
        default:
          break;
 
        case EOF:
          fatal ("%s", _("unterminated `%{' definition"));
 
        default:
-         obstack_1grow (&attrs_obstack, c);
+         copy_character (oout, c);
        }
 
       c = getc (finput);
        }
 
       c = getc (finput);
@@ -484,7 +650,7 @@ copy_definition (void)
        {
          if (c == '}')
            return;
        {
          if (c == '}')
            return;
-         obstack_1grow (&attrs_obstack, '%');
+         obstack_1grow (oout, '%');
        }
       after_percent = 0;
     }
        }
       after_percent = 0;
     }
@@ -504,7 +670,7 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
   char *typename = NULL;
 
   /* The symbol being defined.  */
   char *typename = NULL;
 
   /* The symbol being defined.  */
-  struct bucket *symbol = NULL;
+  symbol_t *symbol = NULL;
 
   /* After `%token' and `%nterm', any number of symbols maybe be
      defined.  */
 
   /* After `%token' and `%nterm', any number of symbols maybe be
      defined.  */
@@ -533,23 +699,7 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
        }
       else if (token == tok_identifier && *symval->tag == '\"' && symbol)
        {
        }
       else if (token == tok_identifier && *symval->tag == '\"' && symbol)
        {
-         if (symval->alias)
-           warn (_("symbol `%s' used more than once as a literal string"),
-                 symval->tag);
-         else if (symbol->alias)
-           warn (_("symbol `%s' given more than one literal string"),
-                 symbol->tag);
-         else
-           {
-             symval->class = token_sym;
-             symval->type_name = typename;
-             symval->user_token_number = symbol->user_token_number;
-             symbol->user_token_number = SALIAS;
-             symval->alias = symbol;
-             symbol->alias = symval;
-             /* symbol and symval combined are only one symbol */
-             nsyms--;
-           }
+         symbol_make_alias (symbol, typename);
          symbol = NULL;
        }
       else if (token == tok_identifier)
          symbol = NULL;
        }
       else if (token == tok_identifier)
@@ -561,7 +711,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)
            {
@@ -576,7 +728,13 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
          symbol->user_token_number = numval;
          /* User defined EOF token? */
          if (numval == 0)
          symbol->user_token_number = numval;
          /* User defined EOF token? */
          if (numval == 0)
-           eoftoken = symbol;
+           {
+             eoftoken = symbol;
+             eoftoken->number = 0;
+             /* It is always mapped to 0, so it was already counted in
+                NTOKENS.  */
+             --ntokens;
+           }
        }
       else
        {
        }
       else
        {
@@ -675,7 +833,8 @@ parse_assoc_decl (associativity assoc)
   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 (;;)
     {
@@ -705,7 +864,11 @@ parse_assoc_decl (associativity assoc)
          symval->assoc = assoc;
          if (symval->class == nterm_sym)
            complain (_("symbol %s redefined"), symval->tag);
          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)
@@ -722,9 +885,9 @@ parse_assoc_decl (associativity assoc)
            }
          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;
@@ -761,6 +924,7 @@ parse_union_decl (void)
 
   typed = 1;
 
 
   typed = 1;
 
+  MUSCLE_INSERT_INT ("stype_line", lineno);
   obstack_init (&union_obstack);
   obstack_sgrow (&union_obstack, "union");
 
   obstack_init (&union_obstack);
   obstack_sgrow (&union_obstack, "union");
 
@@ -775,7 +939,7 @@ parse_union_decl (void)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         lineno++;
+         ++lineno;
          break;
 
        case '/':
          break;
 
        case '/':
@@ -783,7 +947,7 @@ parse_union_decl (void)
          break;
 
        case '{':
          break;
 
        case '{':
-         count++;
+         ++count;
          break;
 
        case '}':
          break;
 
        case '}':
@@ -848,7 +1012,7 @@ static void
 parse_thong_decl (void)
 {
   token_t token;
 parse_thong_decl (void)
 {
   token_t token;
-  struct bucket *symbol;
+  symbol_t *symbol;
   char *typename = 0;
   int usrtoknum = SUNDEF;
 
   char *typename = 0;
   int usrtoknum = SUNDEF;
 
@@ -997,7 +1161,7 @@ parse_skel_decl (void)
 /*----------------------------------------------------------------.
 | 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 ATTRS_OBSTACK.                                        |
+| groups to PRE_PROLOGUE_OBSTACK or POST_PROLOGUE_OBSTACK.        |
 `----------------------------------------------------------------*/
 
 static void
 `----------------------------------------------------------------*/
 
 static void
@@ -1017,7 +1181,10 @@ read_declarations (void)
              return;
 
            case tok_percent_left_curly:
              return;
 
            case tok_percent_left_curly:
-             copy_definition ();
+              if (!typed)
+               copy_definition (&pre_prologue_obstack);
+             else
+               copy_definition (&post_prologue_obstack);
              break;
 
            case tok_token:
              break;
 
            case tok_token:
@@ -1074,7 +1241,7 @@ read_declarations (void)
            case tok_stropt:
            case tok_intopt:
            case tok_obsolete:
            case tok_stropt:
            case tok_intopt:
            case tok_obsolete:
-             abort ();
+             assert (0);
              break;
 
            case tok_illegal:
              break;
 
            case tok_illegal:
@@ -1095,37 +1262,37 @@ read_declarations (void)
     }
 }
 \f
     }
 }
 \f
-/*-------------------------------------------------------------------.
-| Assuming that a `{' has just been seen, copy everything up to the  |
-| 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.                 |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Assuming that a `{' has just been seen, copy everything up to the |
+| matching `}' into ACTION_OBSTACK.                                 |
+|                                                                   |
+| RULE_LENGTH 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.  It is not the same as the rule->length in the case of mid |
+| rule actions.                                                     |
+|                                                                   |
+| This routine is used for actions.                                 |
+`------------------------------------------------------------------*/
 
 static void
 
 static void
-parse_braces (symbol_list *rule, int stack_offset)
+parse_action (symbol_list *rule, int rule_length)
 {
 {
-  int c;
-  int count;
-
-  count = 1;
+  int count = 1;
+  rule->action_line = lineno;
   while (count > 0)
     {
   while (count > 0)
     {
+      int c;
       while ((c = getc (finput)) != '}')
        switch (c)
          {
          case '\n':
            obstack_1grow (&action_obstack, c);
       while ((c = getc (finput)) != '}')
        switch (c)
          {
          case '\n':
            obstack_1grow (&action_obstack, c);
-           lineno++;
+           ++lineno;
            break;
 
          case '{':
            obstack_1grow (&action_obstack, c);
            break;
 
          case '{':
            obstack_1grow (&action_obstack, c);
-           count++;
+           ++count;
            break;
 
          case '\'':
            break;
 
          case '\'':
@@ -1138,13 +1305,11 @@ parse_braces (symbol_list *rule, int stack_offset)
            break;
 
          case '$':
            break;
 
          case '$':
-           copy_dollar (finput, &action_obstack,
-                        rule, stack_offset);
+           copy_dollar (finput, &action_obstack, rule, rule_length);
            break;
 
          case '@':
            break;
 
          case '@':
-           copy_at (finput, &action_obstack,
-                    stack_offset);
+           copy_at (finput, &action_obstack, rule_length);
            break;
 
          case EOF:
            break;
 
          case EOF:
@@ -1156,36 +1321,13 @@ parse_braces (symbol_list *rule, int stack_offset)
 
       /* Above loop exits when C is '}'.  */
       if (--count)
 
       /* Above loop exits when C is '}'.  */
       if (--count)
-       {
-         obstack_1grow (&action_obstack, c);
-         c = getc (finput);
-       }
+       obstack_1grow (&action_obstack, c);
     }
 
   obstack_1grow (&action_obstack, '\0');
     }
 
   obstack_1grow (&action_obstack, '\0');
-}
-
-
-static void
-parse_action (symbol_list *rule, int stack_offset)
-{
-  rule->action_line = lineno;
-  parse_braces (rule, stack_offset);
   rule->action = obstack_finish (&action_obstack);
 }
 
   rule->action = obstack_finish (&action_obstack);
 }
 
-
-static void
-parse_guard (symbol_list *rule, int stack_offset)
-{
-  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
 
 /*-------------------------------------------------------------------.
 \f
 
 /*-------------------------------------------------------------------.
@@ -1193,20 +1335,20 @@ parse_guard (symbol_list *rule, int stack_offset)
 | with the user's names.                                             |
 `-------------------------------------------------------------------*/
 
 | with the user's names.                                             |
 `-------------------------------------------------------------------*/
 
-static bucket *
+static symbol_t *
 gensym (void)
 {
   /* Incremented for each generated symbol */
   static int gensym_count = 0;
   static char buf[256];
 
 gensym (void)
 {
   /* Incremented for each generated symbol */
   static int gensym_count = 0;
   static char buf[256];
 
-  bucket *sym;
+  symbol_t *sym;
 
   sprintf (buf, "@%d", ++gensym_count);
   token_buffer = buf;
   sym = getsym (token_buffer);
   sym->class = nterm_sym;
 
   sprintf (buf, "@%d", ++gensym_count);
   token_buffer = buf;
   sym = getsym (token_buffer);
   sym->class = nterm_sym;
-  sym->value = nvars++;
+  sym->number = nvars++;
   return sym;
 }
 \f
   return sym;
 }
 \f
@@ -1217,8 +1359,8 @@ gensym (void)
 | null pointer instead of a symbol to terminate the rule.  The next  |
 | symbol is the lhs of the following rule.                           |
 |                                                                    |
 | 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.                         |
+| All actions are copied out, 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 |
 |                                                                    |
 | Bison used to allow some %directives in the rules sections, but    |
 | this is no longer consider appropriate: (i) the documented grammar |
@@ -1232,10 +1374,9 @@ static void
 readgram (void)
 {
   token_t t;
 readgram (void)
 {
   token_t t;
-  bucket *lhs = NULL;
+  symbol_t *lhs = NULL;
   symbol_list *p = NULL;
   symbol_list *p1 = NULL;
   symbol_list *p = NULL;
   symbol_list *p1 = NULL;
-  bucket *bp;
 
   /* Points to first symbol_list of current rule. its symbol is the
      lhs of the rule.  */
 
   /* Points to first symbol_list of current rule. its symbol is the
      lhs of the rule.  */
@@ -1252,7 +1393,7 @@ readgram (void)
        /* Number of symbols in rhs of this rule so far */
        int rulelength = 0;
        int xactions = 0;       /* JF for error checking */
        /* Number of symbols in rhs of this rule so far */
        int rulelength = 0;
        int xactions = 0;       /* JF for error checking */
-       bucket *first_rhs = 0;
+       symbol_t *first_rhs = 0;
 
        if (t == tok_identifier)
          {
 
        if (t == tok_identifier)
          {
@@ -1279,8 +1420,8 @@ readgram (void)
          }
        /* start a new rule and record its lhs.  */
 
          }
        /* start a new rule and record its lhs.  */
 
-       nrules++;
-       nitems++;
+       ++nrules;
+       ++nritems;
 
        p = symbol_list_new (lhs);
 
 
        p = symbol_list_new (lhs);
 
@@ -1298,8 +1439,8 @@ readgram (void)
        if (lhs->class == unknown_sym)
          {
            lhs->class = nterm_sym;
        if (lhs->class == unknown_sym)
          {
            lhs->class = nterm_sym;
-           lhs->value = nvars;
-           nvars++;
+           lhs->number = nvars;
+           ++nvars;
          }
        else if (lhs->class == token_sym)
          complain (_("rule given for %s, which is a token"), lhs->tag);
          }
        else if (lhs->class == token_sym)
          complain (_("rule given for %s, which is a token"), lhs->tag);
@@ -1323,7 +1464,7 @@ readgram (void)
               If one does, exit this rule now.  */
            if (t == tok_identifier)
              {
               If one does, exit this rule now.  */
            if (t == tok_identifier)
              {
-               bucket *ssave;
+               symbol_t *ssave;
                token_t t1;
 
                ssave = symval;
                token_t t1;
 
                ssave = symval;
@@ -1331,7 +1472,10 @@ readgram (void)
                unlex (t1);
                symval = ssave;
                if (t1 == tok_colon)
                unlex (t1);
                symval = ssave;
                if (t1 == tok_colon)
-                 break;
+                 {
+                   warn (_("previous rule lacks an ending `;'"));
+                   break;
+                 }
 
                if (!first_rhs) /* JF */
                  first_rhs = symval;
 
                if (!first_rhs) /* JF */
                  first_rhs = symval;
@@ -1349,16 +1493,21 @@ readgram (void)
                   inserting the new rule before it.  */
 
                /* Make a dummy nonterminal, a gensym.  */
                   inserting the new rule before it.  */
 
                /* Make a dummy nonterminal, a gensym.  */
-               bucket *sdummy = 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.  */
 
                /* Make a new rule, whose body is empty, before the
                   current one, so that the action just read can
                   belong to it.  */
-               nrules++;
-               nitems++;
+               ++nrules;
+               ++nritems;
                p = symbol_list_new (sdummy);
                /* Attach its lineno to that of the host rule. */
                p->line = crule->line;
                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
                if (crule1)
                  crule1->next = p;
                else
@@ -1371,7 +1520,7 @@ readgram (void)
 
                /* Insert the dummy generated by that rule into this
                   rule.  */
 
                /* Insert the dummy generated by that rule into this
                   rule.  */
-               nitems++;
+               ++nritems;
                p = symbol_list_new (sdummy);
                p1->next = p;
                p1 = p;
                p = symbol_list_new (sdummy);
                p1->next = p;
                p1 = p;
@@ -1381,7 +1530,7 @@ readgram (void)
 
            if (t == tok_identifier)
              {
 
            if (t == tok_identifier)
              {
-               nitems++;
+               ++nritems;
                p = symbol_list_new (symval);
                p1->next = p;
                p1 = p;
                p = symbol_list_new (symval);
                p1->next = p;
                p1 = p;
@@ -1390,9 +1539,9 @@ readgram (void)
              {
                parse_action (crule, rulelength);
                action_flag = 1;
              {
                parse_action (crule, rulelength);
                action_flag = 1;
-               xactions++;     /* JF */
+               ++xactions;     /* JF */
              }
              }
-           rulelength++;
+           ++rulelength;
          }                     /* end of  read rhs of rule */
 
        /* Put an empty link in the list to mark the end of this rule  */
          }                     /* end of  read rhs of rule */
 
        /* Put an empty link in the list to mark the end of this rule  */
@@ -1408,15 +1557,6 @@ readgram (void)
            t = lex ();
          }
 
            t = lex ();
          }
 
-       if (t == tok_guard)
-         {
-           if (!semantic_parser)
-             complain (_("%%guard present but %%semantic_parser not specified"));
-
-           parse_guard (crule, rulelength);
-           t = lex ();
-         }
-
        if (t == tok_left_curly)
          {
            /* This case never occurs -wjh */
        if (t == tok_left_curly)
          {
            /* This case never occurs -wjh */
@@ -1424,7 +1564,7 @@ readgram (void)
              complain (_("two actions at end of one rule"));
            parse_action (crule, rulelength);
            action_flag = 1;
              complain (_("two actions at end of one rule"));
            parse_action (crule, rulelength);
            action_flag = 1;
-           xactions++; /* -wjh */
+           ++xactions; /* -wjh */
            t = lex ();
          }
        /* If $$ is being set in default way, report if any type
            t = lex ();
          }
        /* If $$ is being set in default way, report if any type
@@ -1442,6 +1582,8 @@ readgram (void)
        /* Warn if there is no default for $$ but we need one.  */
        else if (!xactions && !first_rhs && lhs->type_name != 0)
          complain (_("empty rule for typed nonterminal, and no action"));
        /* Warn if there is no default for $$ but we need one.  */
        else if (!xactions && !first_rhs && lhs->type_name != 0)
          complain (_("empty rule for typed nonterminal, and no action"));
+       if (t == tok_two_percents || t == tok_eof)
+         warn (_("previous rule lacks an ending `;'"));
        if (t == tok_semicolon)
          t = lex ();
       }
        if (t == tok_semicolon)
          t = lex ();
       }
@@ -1457,16 +1599,7 @@ readgram (void)
     fatal (_("no rules in the input grammar"));
 
   /* Report any undefined symbols and consider them nonterminals.  */
     fatal (_("no rules in the input grammar"));
 
   /* Report any undefined symbols and consider them nonterminals.  */
-
-  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++;
-      }
+  symbols_do (symbol_check_defined, NULL);
 
   /* Insert the initial rule, which line is that of the first rule
      (not that of the start symbol):
 
   /* Insert the initial rule, which line is that of the first rule
      (not that of the start symbol):
@@ -1479,15 +1612,15 @@ readgram (void)
   p->next->next->next = symbol_list_new (NULL);
   p->next->next->next->next = grammar;
   nrules += 1;
   p->next->next->next = symbol_list_new (NULL);
   p->next->next->next->next = grammar;
   nrules += 1;
-  nitems += 3;
+  nritems += 3;
   grammar = p;
   startval = axiom;
 
   grammar = p;
   startval = axiom;
 
-  if (nsyms > MAXSHORT)
+  if (nsyms > SHRT_MAX)
     fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
     fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
-          MAXSHORT);
+          SHRT_MAX);
 
 
-  ntokens = nsyms - nvars;
+  assert (nsyms == ntokens + nvars);
 }
 
 /* At the end of the grammar file, some C source code must
 }
 
 /* At the end of the grammar file, some C source code must
@@ -1496,7 +1629,7 @@ readgram (void)
 static void
 read_additionnal_code (void)
 {
 static void
 read_additionnal_code (void)
 {
-  char c;
+  int c;
   struct obstack el_obstack;
 
   obstack_init (&el_obstack);
   struct obstack el_obstack;
 
   obstack_init (&el_obstack);
@@ -1509,7 +1642,7 @@ read_additionnal_code (void)
     }
 
   while ((c = getc (finput)) != EOF)
     }
 
   while ((c = getc (finput)) != EOF)
-    obstack_1grow (&el_obstack, c);
+    copy_character (&el_obstack, c);
 
   obstack_1grow (&el_obstack, 0);
   muscle_insert ("epilogue", obstack_finish (&el_obstack));
 
   obstack_1grow (&el_obstack, 0);
   muscle_insert ("epilogue", obstack_finish (&el_obstack));
@@ -1524,198 +1657,79 @@ read_additionnal_code (void)
 static void
 token_translations_init (void)
 {
 static void
 token_translations_init (void)
 {
-  bucket *bp = NULL;
+  int num_256_available_p = TRUE;
   int i;
 
   int i;
 
-  token_translations = XCALLOC (short, max_user_token_number + 1);
+  /* 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)
+    {
+      symbol_t *this = symbols[i];
+      if (this->user_token_number != SUNDEF)
+       {
+         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;
+       }
+    }
 
 
-  /* 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; i++)
-    token_translations[i] = 2;
+  /* 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;
+
+  /* Set the missing user numbers. */
+  if (max_user_token_number < 256)
+    max_user_token_number = 256;
 
 
-  for (bp = firstsymbol; bp; bp = bp->next)
+  for (i = 0; i < ntokens; ++i)
     {
     {
-      /* Non-terminal? */
-      if (bp->value >= ntokens)
-       continue;
-      /* A token string alias? */
-      if (bp->user_token_number == SALIAS)
-       continue;
+      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;
+    }
 
 
-      assert (bp->user_token_number != SUNDEF);
+  token_translations = XCALLOC (token_number_t, max_user_token_number + 1);
 
 
-      /* A token which translation has already been set? */
-      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;
-    }
+  /* 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);
 }
 
 
 }
 
 
-/*------------------------------------------------------------------.
-| Assign symbol numbers, and write definition of token names into   |
-| FDEFINES.  Set up vectors TAGS and SPREC of names and precedences |
-| of symbols.                                                       |
-`------------------------------------------------------------------*/
+/*----------------------------------------------------------------.
+| Assign symbol numbers, and write definition of token names into |
+| FDEFINES.  Set up vectors SYMBOL_TABLE, TAGS of symbols.        |
+`----------------------------------------------------------------*/
 
 static void
 packsymbols (void)
 {
 
 static void
 packsymbols (void)
 {
-  bucket *bp = NULL;
-  int tokno = 1;
-  int last_user_token_number;
-
-  tags = XCALLOC (char *, nsyms + 1);
-  user_toknums = XCALLOC (short, nsyms + 1);
-
-  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)
-    {
-      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 == -1)
-           {
-             if (bp == eoftoken || bp->alias == eoftoken)
-               bp->value = bp->alias->value = 0;
-             else
-               {
-                 bp->value = bp->alias->value = tokno++;
-               }
-           }
+  symbols = XCALLOC (symbol_t *, nsyms);
 
 
-         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;
-           }
-
-         /* Do not do processing below for SALIASs.  */
-         if (bp->user_token_number == SALIAS)
-           continue;
-
-       }
-      else /* bp->class == token_sym */
-       {
-         if (bp == eoftoken)
-           bp->value = 0;
-         else
-           bp->value = tokno++;
-       }
-
-      if (bp->class == token_sym)
-       {
-         if (bp->user_token_number == SUNDEF)
-           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;
-       }
-
-      tags[bp->value] = bp->tag;
-      user_toknums[bp->value] = bp->user_token_number;
-      sprec[bp->value] = bp->prec;
-      sassoc[bp->value] = bp->assoc;
-    }
+  symbols_do (symbol_check_alias_consistence, NULL);
+  symbols_do (symbol_pack, NULL);
 
   token_translations_init ();
 
 
   token_translations_init ();
 
-  error_token_number = errtoken->value;
-
   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;
-}
-
-
-/*---------------------------------------------------------------.
-| Save the definition of token names in the `TOKENDEFS' muscle.  |
-`---------------------------------------------------------------*/
-
-static void
-symbols_save (void)
-{
-  struct obstack tokendefs;
-  bucket *bp;
-  obstack_init (&tokendefs);
-
-  for (bp = firstsymbol; bp; bp = bp->next)
-    {
-      char *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;
-       }
-
-      /* Don't #define nonliteral tokens whose names contain periods.  */
-      if (strchr (symbol, '.'))
-       continue;
-
-      obstack_fgrow2 (&tokendefs, "# define %s\t%d\n",
-                     symbol, bp->user_token_number);
-      if (semantic_parser)
-       /* FIXME: This is probably wrong, and should be just as
-          above. --akim.  */
-       obstack_fgrow2 (&tokendefs, "# define T%s\t%d\n", symbol, bp->value);
-    }
-
-  obstack_1grow (&tokendefs, 0);
-  muscle_insert ("tokendef", xstrdup (obstack_finish (&tokendefs)));
-  obstack_free (&tokendefs, NULL);
+  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
@@ -1725,12 +1739,8 @@ packgram (void)
   int ruleno;
   symbol_list *p;
 
   int ruleno;
   symbol_list *p;
 
-  /* We use short to index items.  */
-  if (nitems >= MAXSHORT)
-    fatal (_("too many items (max %d)"), MAXSHORT);
-
-  ritem = XCALLOC (short, nitems + 1);
-  rule_table = XCALLOC (rule_t, nrules) - 1;
+  ritem = XCALLOC (item_number_t, nritems + 1);
+  rules = XCALLOC (rule_t, nrules) - 1;
 
   itemno = 0;
   ruleno = 1;
 
   itemno = 0;
   ruleno = 1;
@@ -1738,27 +1748,26 @@ packgram (void)
   p = grammar;
   while (p)
     {
   p = grammar;
   while (p)
     {
-      bucket *ruleprec = p->ruleprec;
-      rule_table[ruleno].lhs = p->sym->value;
-      rule_table[ruleno].rhs = itemno;
-      rule_table[ruleno].line = p->line;
-      rule_table[ruleno].useful = TRUE;
-      rule_table[ruleno].action = p->action;
-      rule_table[ruleno].action_line = p->action_line;
-      rule_table[ruleno].guard = p->guard;
-      rule_table[ruleno].guard_line = p->guard_line;
+      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;
 
       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)
-           {
-             rule_table[ruleno].prec = p->sym->prec;
-             rule_table[ruleno].assoc = p->sym->assoc;
-           }
+           rules[ruleno].prec = p->sym;
          if (p)
            p = p->next;
        }
          if (p)
            p = p->next;
        }
@@ -1767,53 +1776,33 @@ packgram (void)
          the specified symbol's precedence replaces the default.  */
       if (ruleprec)
        {
          the specified symbol's precedence replaces the default.  */
       if (ruleprec)
        {
-         rule_table[ruleno].prec = ruleprec->prec;
-         rule_table[ruleno].assoc = ruleprec->assoc;
-         rule_table[ruleno].precsym = 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;
-  nritems = itemno;
-  assert (nritems == nitems);
+  assert (itemno == nritems);
 
   if (trace_flag)
     ritem_print (stderr);
 }
 \f
 
   if (trace_flag)
     ritem_print (stderr);
 }
 \f
-/*-------------------------------------------------------------------.
-| Read in the grammar specification and record it in the format      |
-| 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.              |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Read in the grammar specification and record it in the format     |
+| described in gram.h.  All actions are copied into ACTION_OBSTACK, |
+| in each case forming the body of a C function (YYACTION) which    |
+| contains a switch statement to decide which action to execute.    |
+`------------------------------------------------------------------*/
 
 void
 reader (void)
 {
 
 void
 reader (void)
 {
-  start_flag = 0;
-  startval = NULL;             /* start symbol not specified yet. */
-
-  nsyms = 0;
-  nvars = 0;
-  nrules = 0;
-  nitems = 0;
-
-  typed = 0;
-  lastprec = 0;
-
-  semantic_parser = 0;
-  pure_parser = 0;
-
-  grammar = NULL;
-
   lex_init ();
   lineno = 1;
 
   lex_init ();
   lineno = 1;
 
@@ -1821,28 +1810,29 @@ reader (void)
   obstack_init (&muscle_obstack);
 
   /* Initialize the symbol table.  */
   obstack_init (&muscle_obstack);
 
   /* Initialize the symbol table.  */
-  tabinit ();
+  symbols_new ();
 
   /* Construct the axiom symbol. */
   axiom = getsym ("$axiom");
   axiom->class = nterm_sym;
 
   /* Construct the axiom symbol. */
   axiom = getsym ("$axiom");
   axiom->class = nterm_sym;
-  axiom->value = nvars++;
+  axiom->number = nvars++;
 
   /* 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;
+  undeftoken->number = ntokens++;
 
   /* Initialize the obstacks. */
   obstack_init (&action_obstack);
 
   /* Initialize the obstacks. */
   obstack_init (&action_obstack);
-  obstack_init (&attrs_obstack);
   obstack_init (&output_obstack);
   obstack_init (&output_obstack);
+  obstack_init (&pre_prologue_obstack);
+  obstack_init (&post_prologue_obstack);
 
   finput = xfopen (infile, "r");
 
 
   finput = xfopen (infile, "r");
 
@@ -1856,12 +1846,13 @@ reader (void)
     {
       eoftoken = getsym ("$");
       eoftoken->class = token_sym;
     {
       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
       /* Value specified by POSIX.  */
       eoftoken->user_token_number = 0;
     }
 
   /* Read in the grammar, build grammar in list form.  Write out
-     guards and actions.  */
+     actions.  */
   readgram ();
   /* Some C code is given at the end of the grammar file. */
   read_additionnal_code ();
   readgram ();
   /* Some C code is given at the end of the grammar file. */
   read_additionnal_code ();
@@ -1872,9 +1863,19 @@ reader (void)
   /* 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 ();
-  /* Save them. */
-  symbols_save ();
 
   /* Convert the grammar into the format described in gram.h.  */
   packgram ();
 
   /* Convert the grammar into the format described in gram.h.  */
   packgram ();
+
+  /* The grammar as a symbol_list is no longer needed. */
+  LIST_FREE (symbol_list, grammar);
+}
+
+void
+grammar_free (void)
+{
+  XFREE (ritem);
+  free (rules + 1);
+  /* Free the symbol table data structure.  */
+  symbols_free ();
 }
 }