]> git.saurik.com Git - bison.git/blobdiff - src/reader.c
Point to an official beta.
[bison.git] / src / reader.c
index f1577b486b25d0c712dbbf838883c8829b351dfe..6a99cfffa79e0b57ceaeb46c3562a6c28710b639 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;
   int line;
+
   /* The action is attached to the LHS of a rule. */
   const char *action;
   int action_line;
   /* The action is attached to the LHS of a rule. */
   const char *action;
   int action_line;
-  bucket *ruleprec;
-}
-symbol_list;
+
+  /* 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 bucket *errtoken;
-static bucket *undeftoken;
+static int lastprec = 0;
 
 
+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;
   res->sym = sym;
   res->line = lineno;
 {
   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;
 }
 
   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
 
 /*===================\
@@ -158,7 +326,7 @@ 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;
     }
 
   return rp->sym->type_name;
@@ -201,7 +369,7 @@ copy_string2 (FILE *fin, struct obstack *oout, int match, int store)
          obstack_1grow (oout, c);
 
          if (c == '\n')
          obstack_1grow (oout, c);
 
          if (c == '\n')
-           lineno++;
+           ++lineno;
        }
 
       c = getc (fin);
        }
 
       c = getc (fin);
@@ -284,7 +452,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;
@@ -326,9 +494,16 @@ 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);
-
-      obstack_fgrow1 (oout, "yylsp[%d]", n - stack_offset);
-      locations_flag = 1;
+      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
     {
     }
   else
     {
@@ -383,16 +558,24 @@ copy_dollar (FILE *fin, struct obstack *oout,
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
       ungetc (c, fin);
       n = read_signed_integer (fin);
 
-      if (!type_name && n > 0)
-       type_name = get_type_name (n, rule);
-
-      obstack_fgrow1 (oout, "yyvsp[%d]", n - stack_offset);
-
-      if (type_name)
-       obstack_fgrow1 (oout, ".%s", type_name);
-      if (!type_name && typed)
-       complain (_("$%d of `%s' has no declared type"),
-                 n, rule->sym->tag);
+      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
     {
@@ -418,7 +601,7 @@ copy_definition (void)
     {
       obstack_fgrow2 (&attrs_obstack, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
     {
       obstack_fgrow2 (&attrs_obstack, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
-                                             muscle_find("filename")));
+                                             muscle_find ("filename")));
     }
 
   after_percent = 0;
     }
 
   after_percent = 0;
@@ -431,7 +614,7 @@ copy_definition (void)
        {
        case '\n':
          obstack_1grow (&attrs_obstack, c);
        {
        case '\n':
          obstack_1grow (&attrs_obstack, c);
-         lineno++;
+         ++lineno;
          break;
 
        case '%':
          break;
 
        case '%':
@@ -480,7 +663,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.  */
@@ -509,23 +692,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)
@@ -537,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)
            {
@@ -550,6 +719,15 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
       else if (symbol && token == tok_number)
        {
          symbol->user_token_number = numval;
       else if (symbol && token == tok_number)
        {
          symbol->user_token_number = numval;
+         /* 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
        {
        }
       else
        {
@@ -648,7 +826,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 (;;)
     {
@@ -678,7 +857,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)
@@ -695,9 +878,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;
@@ -734,6 +917,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");
 
@@ -748,7 +932,7 @@ parse_union_decl (void)
       switch (c)
        {
        case '\n':
       switch (c)
        {
        case '\n':
-         lineno++;
+         ++lineno;
          break;
 
        case '/':
          break;
 
        case '/':
@@ -756,7 +940,7 @@ parse_union_decl (void)
          break;
 
        case '{':
          break;
 
        case '{':
-         count++;
+         ++count;
          break;
 
        case '}':
          break;
 
        case '}':
@@ -821,7 +1005,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;
 
@@ -874,12 +1058,13 @@ parse_thong_decl (void)
   nsyms--;
 }
 
   nsyms--;
 }
 
+
 static void
 parse_muscle_decl (void)
 {
   int ch = ungetc (skip_white_space (), finput);
 static void
 parse_muscle_decl (void)
 {
   int ch = ungetc (skip_white_space (), finput);
-  charmuscle_key;
-  charmuscle_value;
+  char *muscle_key;
+  char *muscle_value;
 
   /* Read key. */
   if (!isalpha (ch) && ch != '_')
 
   /* Read key. */
   if (!isalpha (ch) && ch != '_')
@@ -1046,7 +1231,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:
@@ -1072,178 +1257,89 @@ 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 count;
 
 {
   int c;
   int count;
 
-  /* offset is always 0 if parser has already popped the stack pointer */
-  if (semantic_parser)
-    stack_offset = 0;
-
   count = 1;
   count = 1;
-  c = getc (finput);
-
   while (count > 0)
     {
   while (count > 0)
     {
-      while (c != '}')
-       {
-         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);
-           }
-
-         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)
-       {
-         obstack_1grow (&action_obstack, c);
-         c = getc (finput);
-       }
+       obstack_1grow (&action_obstack, c);
     }
 
   obstack_1grow (&action_obstack, '\0');
     }
 
   obstack_1grow (&action_obstack, '\0');
-  rule->action = obstack_finish (&action_obstack);
-  rule->action_line = lineno;
 }
 }
-\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 count;
-  int brace_flag = 0;
-
-  /* offset is always 0 if parser has already popped the stack pointer */
-  if (semantic_parser)
-    stack_offset = 0;
-
-  obstack_fgrow1 (&guard_obstack, "\ncase %d:\n", nrules);
-  if (!no_lines_flag)
-    obstack_fgrow2 (&guard_obstack, muscle_find ("linef"),
-                   lineno, quotearg_style (c_quoting_style,
-                                           muscle_find ("filename")));
-  obstack_1grow (&guard_obstack, '{');
-
-  count = 0;
-  c = getc (finput);
-
-  while (brace_flag ? (count > 0) : (c != ';'))
-    {
-      switch (c)
-       {
-       case '\n':
-         obstack_1grow (&guard_obstack, c);
-         lineno++;
-         break;
-
-       case '{':
-         obstack_1grow (&guard_obstack, c);
-         brace_flag = 1;
-         count++;
-         break;
-
-       case '}':
-         obstack_1grow (&guard_obstack, c);
-         if (count > 0)
-           count--;
-         else
-           {
-             complain (_("unmatched %s"), "`}'");
-             c = getc (finput);        /* skip it */
-           }
-         break;
-
-       case '\'':
-       case '"':
-         copy_string (finput, &guard_obstack, c);
-         break;
-
-       case '/':
-         copy_comment (finput, &guard_obstack);
-         break;
-
-       case '$':
-         copy_dollar (finput, &guard_obstack, rule, stack_offset);
-         break;
-
-       case '@':
-         copy_at (finput, &guard_obstack, stack_offset);
-         break;
-
-       case EOF:
-         fatal ("%s", _("unterminated %guard clause"));
-
-       default:
-         obstack_1grow (&guard_obstack, c);
-       }
-
-      if (c != '}' || count != 0)
-       c = getc (finput);
-    }
+  rule->action_line = lineno;
+  parse_braces (rule, stack_offset);
+  rule->action = obstack_finish (&action_obstack);
+}
 
 
-  c = skip_white_space ();
 
 
-  obstack_sgrow (&guard_obstack, ";\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);
+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
 
 /*-------------------------------------------------------------------.
@@ -1251,20 +1347,20 @@ copy_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
@@ -1290,10 +1386,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.  */
@@ -1310,7 +1405,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)
          {
@@ -1337,8 +1432,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);
 
@@ -1356,8 +1451,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);
@@ -1381,7 +1476,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;
@@ -1389,7 +1484,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;
@@ -1407,16 +1505,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
@@ -1429,7 +1532,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;
@@ -1439,18 +1542,18 @@ readgram (void)
 
            if (t == tok_identifier)
              {
 
            if (t == tok_identifier)
              {
-               nitems++;
+               ++nritems;
                p = symbol_list_new (symval);
                p1->next = p;
                p1 = p;
              }
            else                /* handle an action.  */
              {
                p = symbol_list_new (symval);
                p1->next = p;
                p1 = p;
              }
            else                /* handle an action.  */
              {
-               copy_action (crule, rulelength);
+               parse_action (crule, rulelength);
                action_flag = 1;
                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  */
@@ -1465,22 +1568,24 @@ readgram (void)
            crule->ruleprec = symval;
            t = lex ();
          }
            crule->ruleprec = symval;
            t = lex ();
          }
+
        if (t == tok_guard)
          {
            if (!semantic_parser)
              complain (_("%%guard present but %%semantic_parser not specified"));
 
        if (t == tok_guard)
          {
            if (!semantic_parser)
              complain (_("%%guard present but %%semantic_parser not specified"));
 
-           copy_guard (crule, rulelength);
+           parse_guard (crule, rulelength);
            t = lex ();
          }
            t = lex ();
          }
-       else if (t == tok_left_curly)
+
+       if (t == tok_left_curly)
          {
            /* This case never occurs -wjh */
            if (action_flag)
              complain (_("two actions at end of one rule"));
          {
            /* This case never occurs -wjh */
            if (action_flag)
              complain (_("two actions at end of one rule"));
-           copy_action (crule, rulelength);
+           parse_action (crule, rulelength);
            action_flag = 1;
            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
@@ -1498,6 +1603,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 ();
       }
@@ -1507,28 +1614,34 @@ readgram (void)
        t = lex ();
       }
 
        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"));
 
   /* Report any undefined symbols and consider them nonterminals.  */
   if (nrules == 0)
     fatal (_("no rules in the input grammar"));
 
   /* 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);
 }
 
 /* At the end of the grammar file, some C source code must
 }
 
 /* At the end of the grammar file, some C source code must
@@ -1537,7 +1650,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);
@@ -1546,7 +1659,7 @@ read_additionnal_code (void)
     {
       obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
     {
       obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
-                                             muscle_find("filename")));
+                                             muscle_find ("filename")));
     }
 
   while ((c = getc (finput)) != EOF)
     }
 
   while ((c = getc (finput)) != EOF)
@@ -1565,196 +1678,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;
-  static char DOLLAR[] = "$";
-
-  tags = XCALLOC (char *, nsyms + 1);
-  user_toknums = XCALLOC (short, nsyms + 1);
-
-  sprec = XCALLOC (short, nsyms);
-  sassoc = XCALLOC (short, nsyms);
-
-  /* The EOF token. */
-  tags[0] = DOLLAR;
-  user_toknums[0] = 0;
-
-  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 == 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;
-           }
+  symbols = XCALLOC (symbol_t *, nsyms);
 
 
-         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 */
-       {
-         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;
-  char *cp, *symbol;
-  char c;
-  obstack_init (&tokendefs);
-
-  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;
-       }
-
-      /* Don't #define nonliteral tokens whose names contain periods.  */
-      cp = symbol;
-      while ((c = *cp++) && c != '.');
-      if (c != '\0')
-       continue;
-
-      obstack_fgrow2 (&tokendefs, "# define\t%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\tT%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
@@ -1764,8 +1760,8 @@ packgram (void)
   int ruleno;
   symbol_list *p;
 
   int ruleno;
   symbol_list *p;
 
-  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;
@@ -1773,25 +1769,28 @@ 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;
+      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)
-           {
-             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;
        }
@@ -1800,19 +1799,18 @@ 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;
+  assert (itemno == nritems);
 
   if (trace_flag)
     ritem_print (stderr);
 
   if (trace_flag)
     ritem_print (stderr);
@@ -1829,22 +1827,6 @@ packgram (void)
 void
 reader (void)
 {
 void
 reader (void)
 {
-  start_flag = 0;
-  startval = NULL;             /* start symbol not specified yet. */
-
-  nsyms = 1;
-  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;
 
@@ -1852,35 +1834,71 @@ 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;
+  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);
+  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 the declaration section.  Copy %{ ... %} groups to
      TABLE_OBSTACK and FDEFINES file.  Also notice any %token, %left,
      etc. found there.  */
   read_declarations ();
+
+  /* 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 ();
   /* Some C code is given at the end of the grammar file. */
   read_additionnal_code ();
 
   /* Read in the grammar, build grammar in list form.  Write out
      guards and actions.  */
   readgram ();
   /* 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 ();
-  /* 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 ();
 }
 }