]> git.saurik.com Git - bison.git/blobdiff - src/reader.c
Don't `touch' the files gettextize modified.
[bison.git] / src / reader.c
index d19126240f06ea7577194c231a5fa1e08dd8899b..099f32dabc63bf2b27269f0e83de0d73ede3e085 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -38,7 +38,7 @@
 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. */
@@ -48,32 +48,31 @@ typedef struct symbol_list
   /* 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;
-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.  */
-static int typed;
+static int typed = 0;
 
 /* 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 *
-symbol_list_new (bucket *sym)
+symbol_list_new (symbol_t *sym)
 {
   symbol_list *res = XMALLOC (symbol_list, 1);
   res->next = NULL;
@@ -87,6 +86,167 @@ symbol_list_new (bucket *sym)
   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
 
 /*===================\
@@ -166,7 +326,7 @@ get_type_name (int n, symbol_list *rule)
          complain (_("invalid $ value"));
          return NULL;
        }
-      i++;
+      ++i;
     }
 
   return rp->sym->type_name;
@@ -209,7 +369,7 @@ copy_string2 (FILE *fin, struct obstack *oout, int match, int store)
          obstack_1grow (oout, c);
 
          if (c == '\n')
-           lineno++;
+           ++lineno;
        }
 
       c = getc (fin);
@@ -292,7 +452,7 @@ copy_comment (FILE *fin, struct obstack *oout)
        }
       else if (c == '\n')
        {
-         lineno++;
+         ++lineno;
          obstack_1grow (oout, c);
          if (cplus_comment)
            ended = 1;
@@ -334,9 +494,16 @@ copy_at (FILE *fin, struct obstack *oout, int stack_offset)
 
       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
     {
@@ -391,16 +558,24 @@ copy_dollar (FILE *fin, struct obstack *oout,
       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
     {
@@ -416,7 +591,7 @@ copy_dollar (FILE *fin, struct obstack *oout,
 `-------------------------------------------------------------------*/
 
 static void
-copy_definition (void)
+copy_definition (struct obstack *oout)
 {
   int c;
   /* -1 while reading a character if prev char was %. */
@@ -424,9 +599,9 @@ copy_definition (void)
 
   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")));
+                                             muscle_find ("filename")));
     }
 
   after_percent = 0;
@@ -438,8 +613,8 @@ copy_definition (void)
       switch (c)
        {
        case '\n':
-         obstack_1grow (&attrs_obstack, c);
-         lineno++;
+         obstack_1grow (oout, c);
+         ++lineno;
          break;
 
        case '%':
@@ -448,18 +623,18 @@ copy_definition (void)
 
        case '\'':
        case '"':
-         copy_string (finput, &attrs_obstack, c);
+         copy_string (finput, oout, c);
          break;
 
        case '/':
-         copy_comment (finput, &attrs_obstack);
+         copy_comment (finput, oout);
          break;
 
        case EOF:
          fatal ("%s", _("unterminated `%{' definition"));
 
        default:
-         obstack_1grow (&attrs_obstack, c);
+         obstack_1grow (oout, c);
        }
 
       c = getc (finput);
@@ -468,7 +643,7 @@ copy_definition (void)
        {
          if (c == '}')
            return;
-         obstack_1grow (&attrs_obstack, '%');
+         obstack_1grow (oout, '%');
        }
       after_percent = 0;
     }
@@ -488,7 +663,7 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
   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.  */
@@ -517,23 +692,7 @@ parse_token_decl (symbol_class what_is, symbol_class what_is_not)
        }
       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)
@@ -545,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)
-           symbol->value = nvars++;
+           symbol->number = nvars++;
+         if (what_is == token_sym && symbol->number == NUMBER_UNDEFINED)
+           symbol->number = ntokens++;
 
          if (typename)
            {
@@ -558,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;
+         /* 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
        {
@@ -656,7 +826,8 @@ parse_assoc_decl (associativity assoc)
   char *name = NULL;
   int prev = 0;
 
-  lastprec++;                  /* Assign a new precedence level, never 0.  */
+  /* Assign a new precedence level, never 0.  */
+  ++lastprec;
 
   for (;;)
     {
@@ -686,7 +857,11 @@ parse_assoc_decl (associativity assoc)
          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)
@@ -703,9 +878,9 @@ parse_assoc_decl (associativity assoc)
            }
          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;
@@ -742,6 +917,7 @@ parse_union_decl (void)
 
   typed = 1;
 
+  MUSCLE_INSERT_INT ("stype_line", lineno);
   obstack_init (&union_obstack);
   obstack_sgrow (&union_obstack, "union");
 
@@ -756,7 +932,7 @@ parse_union_decl (void)
       switch (c)
        {
        case '\n':
-         lineno++;
+         ++lineno;
          break;
 
        case '/':
@@ -764,7 +940,7 @@ parse_union_decl (void)
          break;
 
        case '{':
-         count++;
+         ++count;
          break;
 
        case '}':
@@ -829,7 +1005,7 @@ static void
 parse_thong_decl (void)
 {
   token_t token;
-  struct bucket *symbol;
+  symbol_t *symbol;
   char *typename = 0;
   int usrtoknum = SUNDEF;
 
@@ -882,12 +1058,13 @@ parse_thong_decl (void)
   nsyms--;
 }
 
+
 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 != '_')
@@ -977,7 +1154,7 @@ parse_skel_decl (void)
 /*----------------------------------------------------------------.
 | 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
@@ -997,7 +1174,10 @@ read_declarations (void)
              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:
@@ -1054,7 +1234,7 @@ read_declarations (void)
            case tok_stropt:
            case tok_intopt:
            case tok_obsolete:
-             abort ();
+             assert (0);
              break;
 
            case tok_illegal:
@@ -1081,8 +1261,8 @@ read_declarations (void)
 | 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 the        |
-| actions_obstack is used, but this is fine, since we use only       |
+| 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.                 |
 `-------------------------------------------------------------------*/
 
@@ -1092,10 +1272,6 @@ parse_braces (symbol_list *rule, int stack_offset)
   int c;
   int count;
 
-  /* offset is always 0 if parser has already popped the stack pointer */
-  if (semantic_parser)
-    stack_offset = 0;
-
   count = 1;
   while (count > 0)
     {
@@ -1104,12 +1280,12 @@ parse_braces (symbol_list *rule, int stack_offset)
          {
          case '\n':
            obstack_1grow (&action_obstack, c);
-           lineno++;
+           ++lineno;
            break;
 
          case '{':
            obstack_1grow (&action_obstack, c);
-           count++;
+           ++count;
            break;
 
          case '\'':
@@ -1140,10 +1316,7 @@ parse_braces (symbol_list *rule, int stack_offset)
 
       /* 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');
@@ -1177,20 +1350,20 @@ parse_guard (symbol_list *rule, int stack_offset)
 | 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];
 
-  bucket *sym;
+  symbol_t *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
@@ -1216,10 +1389,9 @@ static void
 readgram (void)
 {
   token_t t;
-  bucket *lhs = NULL;
+  symbol_t *lhs = 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.  */
@@ -1236,7 +1408,7 @@ readgram (void)
        /* 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)
          {
@@ -1263,8 +1435,8 @@ readgram (void)
          }
        /* start a new rule and record its lhs.  */
 
-       nrules++;
-       nitems++;
+       ++nrules;
+       ++nritems;
 
        p = symbol_list_new (lhs);
 
@@ -1282,8 +1454,8 @@ readgram (void)
        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);
@@ -1307,7 +1479,7 @@ readgram (void)
               If one does, exit this rule now.  */
            if (t == tok_identifier)
              {
-               bucket *ssave;
+               symbol_t *ssave;
                token_t t1;
 
                ssave = symval;
@@ -1315,7 +1487,10 @@ readgram (void)
                unlex (t1);
                symval = ssave;
                if (t1 == tok_colon)
-                 break;
+                 {
+                   warn (_("previous rule lacks an ending `;'"));
+                   break;
+                 }
 
                if (!first_rhs) /* JF */
                  first_rhs = symval;
@@ -1333,16 +1508,21 @@ readgram (void)
                   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.  */
-               nrules++;
-               nitems++;
+               ++nrules;
+               ++nritems;
                p = symbol_list_new (sdummy);
                /* Attach its lineno to that of the host rule. */
                p->line = crule->line;
+               /* Move the action from the host rule to this one. */
+               p->action = crule->action;
+               p->action_line = crule->action_line;
+               crule->action = NULL;
+
                if (crule1)
                  crule1->next = p;
                else
@@ -1355,7 +1535,7 @@ readgram (void)
 
                /* Insert the dummy generated by that rule into this
                   rule.  */
-               nitems++;
+               ++nritems;
                p = symbol_list_new (sdummy);
                p1->next = p;
                p1 = p;
@@ -1365,7 +1545,7 @@ readgram (void)
 
            if (t == tok_identifier)
              {
-               nitems++;
+               ++nritems;
                p = symbol_list_new (symval);
                p1->next = p;
                p1 = p;
@@ -1374,9 +1554,9 @@ readgram (void)
              {
                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  */
@@ -1408,7 +1588,7 @@ readgram (void)
              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
@@ -1426,6 +1606,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"));
+       if (t == tok_two_percents || t == tok_eof)
+         warn (_("previous rule lacks an ending `;'"));
        if (t == tok_semicolon)
          t = lex ();
       }
@@ -1435,28 +1617,34 @@ readgram (void)
        t = lex ();
       }
 
-
   /* 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.  */
+  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
@@ -1465,7 +1653,7 @@ readgram (void)
 static void
 read_additionnal_code (void)
 {
-  char c;
+  int c;
   struct obstack el_obstack;
 
   obstack_init (&el_obstack);
@@ -1474,7 +1662,7 @@ read_additionnal_code (void)
     {
       obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
                      lineno, quotearg_style (c_quoting_style,
-                                             muscle_find("filename")));
+                                             muscle_find ("filename")));
     }
 
   while ((c = getc (finput)) != EOF)
@@ -1493,196 +1681,79 @@ read_additionnal_code (void)
 static void
 token_translations_init (void)
 {
-  bucket *bp = NULL;
+  int num_256_available_p = TRUE;
   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)
 {
-  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);
+  symbols = XCALLOC (symbol_t *, 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;
-           }
-
-         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 ();
 
-  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);
 
-  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 %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 |
-| RITEMS.                                                        |
+| RITEM                                                        |
 `---------------------------------------------------------------*/
 
 static void
@@ -1692,12 +1763,8 @@ packgram (void)
   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;
@@ -1705,27 +1772,28 @@ packgram (void)
   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;
+      rules[ruleno].guard = p->guard;
+      rules[ruleno].guard_line = p->guard_line;
 
       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)
-           {
-             rule_table[ruleno].prec = p->sym->prec;
-             rule_table[ruleno].assoc = p->sym->assoc;
-           }
+           rules[ruleno].prec = p->sym;
          if (p)
            p = p->next;
        }
@@ -1734,19 +1802,18 @@ packgram (void)
          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;
-      ruleno++;
+      ++ruleno;
 
       if (p)
        p = p->next;
     }
 
   ritem[itemno] = 0;
+  assert (itemno == nritems);
 
   if (trace_flag)
     ritem_print (stderr);
@@ -1763,22 +1830,6 @@ packgram (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;
 
@@ -1786,23 +1837,29 @@ reader (void)
   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;
-  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;
-  undeftoken->user_token_number = 2;
+  undeftoken->number = ntokens++;
 
   /* Initialize the obstacks. */
   obstack_init (&action_obstack);
-  obstack_init (&attrs_obstack);
   obstack_init (&output_obstack);
+  obstack_init (&pre_prologue_obstack);
+  obstack_init (&post_prologue_obstack);
 
   finput = xfopen (infile, "r");
 
@@ -1810,6 +1867,17 @@ reader (void)
      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 ();
@@ -1822,9 +1890,19 @@ reader (void)
   /* 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 ();
+
+  /* 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 ();
 }