entered into RCS

This commit is contained in:
Richard M. Stallman
1991-12-21 00:17:44 +00:00
parent e06f0c3442
commit d0fb370f66
3 changed files with 1258 additions and 0 deletions

351
src/closure.c Normal file
View File

@@ -0,0 +1,351 @@
/* Subroutines for bison
Copyright (C) 1984, 1989 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bison is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bison; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* subroutines of file LR0.c.
Entry points:
closure (items, n)
Given a vector of item numbers items, of length n,
set up ruleset and itemset to indicate what rules could be run
and which items could be accepted when those items are the active ones.
ruleset contains a bit for each rule. closure sets the bits
for all rules which could potentially describe the next input to be read.
itemset is a vector of item numbers; itemsetend points to just beyond the end
of the part of it that is significant.
closure places there the indices of all items which represent units of
input that could arrive next.
initialize_closure (n)
Allocates the itemset and ruleset vectors,
and precomputes useful data so that closure can be called.
n is the number of elements to allocate for itemset.
finalize_closure ()
Frees itemset, ruleset and internal data.
*/
#include <stdio.h>
#include "system.h"
#include "machine.h"
#include "new.h"
#include "gram.h"
extern short **derives;
extern char **tags;
void set_fderives();
void set_firsts();
extern void RTC();
short *itemset;
short *itemsetend;
static unsigned *ruleset;
/* internal data. See comments before set_fderives and set_firsts. */
static unsigned *fderives;
static unsigned *firsts;
/* number of words required to hold a bit for each rule */
static int rulesetsize;
/* number of words required to hold a bit for each variable */
static int varsetsize;
void
initialize_closure(n)
int n;
{
itemset = NEW2(n, short);
rulesetsize = WORDSIZE(nrules + 1);
ruleset = NEW2(rulesetsize, unsigned);
set_fderives();
}
/* set fderives to an nvars by nrules matrix of bits
indicating which rules can help derive the beginning of the data
for each nonterminal. For example, if symbol 5 can be derived as
the sequence of symbols 8 3 20, and one of the rules for deriving
symbol 8 is rule 4, then the [5 - ntokens, 4] bit in fderives is set. */
void
set_fderives()
{
register unsigned *rrow;
register unsigned *vrow;
register int j;
register unsigned cword;
register short *rp;
register int b;
int ruleno;
int i;
fderives = NEW2(nvars * rulesetsize, unsigned) - ntokens * rulesetsize;
set_firsts();
rrow = fderives + ntokens * rulesetsize;
for (i = ntokens; i < nsyms; i++)
{
vrow = firsts + ((i - ntokens) * varsetsize);
cword = *vrow++;
b = 0;
for (j = ntokens; j < nsyms; j++)
{
if (cword & (1 << b))
{
rp = derives[j];
while ((ruleno = *rp++) > 0)
{
SETBIT(rrow, ruleno);
}
}
b++;
if (b >= BITS_PER_WORD && j + 1 < nsyms)
{
cword = *vrow++;
b = 0;
}
}
rrow += rulesetsize;
}
#ifdef DEBUG
print_fderives();
#endif
FREE(firsts);
}
/* set firsts to be an nvars by nvars bit matrix indicating which items
can represent the beginning of the input corresponding to which other items.
For example, if some rule expands symbol 5 into the sequence of symbols 8 3 20,
the symbol 8 can be the beginning of the data for symbol 5,
so the bit [8 - ntokens, 5 - ntokens] in firsts is set. */
void
set_firsts()
{
register unsigned *row;
/* register int done; JF unused */
register int symbol;
register short *sp;
register int rowsize;
int i;
varsetsize = rowsize = WORDSIZE(nvars);
firsts = NEW2(nvars * rowsize, unsigned);
row = firsts;
for (i = ntokens; i < nsyms; i++)
{
sp = derives[i];
while (*sp >= 0)
{
symbol = ritem[rrhs[*sp++]];
if (ISVAR(symbol))
{
symbol -= ntokens;
SETBIT(row, symbol);
}
}
row += rowsize;
}
RTC(firsts, nvars);
#ifdef DEBUG
print_firsts();
#endif
}
void
closure(core, n)
short *core;
int n;
{
register int ruleno;
register unsigned word;
register short *csp;
register unsigned *dsp;
register unsigned *rsp;
short *csend;
unsigned *rsend;
int symbol;
int itemno;
rsp = ruleset;
rsend = ruleset + rulesetsize;
csend = core + n;
if (n == 0)
{
dsp = fderives + start_symbol * rulesetsize;
while (rsp < rsend)
*rsp++ = *dsp++;
}
else
{
while (rsp < rsend)
*rsp++ = 0;
csp = core;
while (csp < csend)
{
symbol = ritem[*csp++];
if (ISVAR(symbol))
{
dsp = fderives + symbol * rulesetsize;
rsp = ruleset;
while (rsp < rsend)
*rsp++ |= *dsp++;
}
}
}
ruleno = 0;
itemsetend = itemset;
csp = core;
rsp = ruleset;
while (rsp < rsend)
{
word = *rsp++;
if (word == 0)
{
ruleno += BITS_PER_WORD;
}
else
{
register int b;
for (b = 0; b < BITS_PER_WORD; b++)
{
if (word & (1 << b))
{
itemno = rrhs[ruleno];
while (csp < csend && *csp < itemno)
*itemsetend++ = *csp++;
*itemsetend++ = itemno;
}
ruleno++;
}
}
}
while (csp < csend)
*itemsetend++ = *csp++;
#ifdef DEBUG
print_closure(n);
#endif
}
void
finalize_closure()
{
FREE(itemset);
FREE(ruleset);
FREE(fderives + ntokens * rulesetsize);
}
#ifdef DEBUG
print_closure(n)
int n;
{
register short *isp;
printf("\n\nn = %d\n\n", n);
for (isp = itemset; isp < itemsetend; isp++)
printf(" %d\n", *isp);
}
print_firsts()
{
register int i;
register int j;
register unsigned *rowp;
printf("\n\n\nFIRSTS\n\n");
for (i = ntokens; i < nsyms; i++)
{
printf("\n\n%s firsts\n\n", tags[i]);
rowp = firsts + ((i - ntokens) * varsetsize);
for (j = 0; j < nvars; j++)
if (BITISSET (rowp, j))
printf(" %s\n", tags[j + ntokens]);
}
}
print_fderives()
{
register int i;
register int j;
register unsigned *rp;
printf("\n\n\nFDERIVES\n");
for (i = ntokens; i < nsyms; i++)
{
printf("\n\n%s derives\n\n", tags[i]);
rp = fderives + i * rulesetsize;
for (j = 0; j <= nrules; j++)
if (BITISSET (rp, j))
printf(" %d\n", j);
}
fflush(stdout);
}
#endif

770
src/lalr.c Normal file
View File

@@ -0,0 +1,770 @@
/* Compute look-ahead criteria for bison,
Copyright (C) 1984, 1986, 1989 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bison is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bison; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Compute how to make the finite state machine deterministic;
find which rules need lookahead in each state, and which lookahead tokens they accept.
lalr(), the entry point, builds these data structures:
goto_map, from_state and to_state
record each shift transition which accepts a variable (a nonterminal).
ngotos is the number of such transitions.
from_state[t] is the state number which a transition leads from
and to_state[t] is the state number it leads to.
All the transitions that accept a particular variable are grouped together and
goto_map[i - ntokens] is the index in from_state and to_state of the first of them.
consistent[s] is nonzero if no lookahead is needed to decide what to do in state s.
LAruleno is a vector which records the rules that need lookahead in various states.
The elements of LAruleno that apply to state s are those from
lookaheads[s] through lookaheads[s+1]-1.
Each element of LAruleno is a rule number.
If lr is the length of LAruleno, then a number from 0 to lr-1
can specify both a rule and a state where the rule might be applied.
LA is a lr by ntokens matrix of bits.
LA[l, i] is 1 if the rule LAruleno[l] is applicable in the appropriate state
when the next token is symbol i.
If LA[l, i] and LA[l, j] are both 1 for i != j, it is a conflict.
*/
#include <stdio.h>
#include "system.h"
#include "machine.h"
#include "types.h"
#include "state.h"
#include "new.h"
#include "gram.h"
extern short **derives;
extern char *nullable;
int tokensetsize;
short *lookaheads;
short *LAruleno;
unsigned *LA;
short *accessing_symbol;
char *consistent;
core **state_table;
shifts **shift_table;
reductions **reduction_table;
short *goto_map;
short *from_state;
short *to_state;
short **transpose();
void set_state_table();
void set_accessing_symbol();
void set_shift_table();
void set_reduction_table();
void set_maxrhs();
void initialize_LA();
void set_goto_map();
void initialize_F();
void build_relations();
void add_lookback_edge();
void compute_FOLLOWS();
void compute_lookaheads();
void digraph();
void traverse();
extern void toomany();
extern void berror();
static int infinity;
static int maxrhs;
static int ngotos;
static unsigned *F;
static short **includes;
static shorts **lookback;
static short **R;
static short *INDEX;
static short *VERTICES;
static int top;
void
lalr()
{
tokensetsize = WORDSIZE(ntokens);
set_state_table();
set_accessing_symbol();
set_shift_table();
set_reduction_table();
set_maxrhs();
initialize_LA();
set_goto_map();
initialize_F();
build_relations();
compute_FOLLOWS();
compute_lookaheads();
}
void
set_state_table()
{
register core *sp;
state_table = NEW2(nstates, core *);
for (sp = first_state; sp; sp = sp->next)
state_table[sp->number] = sp;
}
void
set_accessing_symbol()
{
register core *sp;
accessing_symbol = NEW2(nstates, short);
for (sp = first_state; sp; sp = sp->next)
accessing_symbol[sp->number] = sp->accessing_symbol;
}
void
set_shift_table()
{
register shifts *sp;
shift_table = NEW2(nstates, shifts *);
for (sp = first_shift; sp; sp = sp->next)
shift_table[sp->number] = sp;
}
void
set_reduction_table()
{
register reductions *rp;
reduction_table = NEW2(nstates, reductions *);
for (rp = first_reduction; rp; rp = rp->next)
reduction_table[rp->number] = rp;
}
void
set_maxrhs()
{
register short *itemp;
register int length;
register int max;
length = 0;
max = 0;
for (itemp = ritem; *itemp; itemp++)
{
if (*itemp > 0)
{
length++;
}
else
{
if (length > max) max = length;
length = 0;
}
}
maxrhs = max;
}
void
initialize_LA()
{
register int i;
register int j;
register int count;
register reductions *rp;
register shifts *sp;
register short *np;
consistent = NEW2(nstates, char);
lookaheads = NEW2(nstates + 1, short);
count = 0;
for (i = 0; i < nstates; i++)
{
register int k;
lookaheads[i] = count;
rp = reduction_table[i];
sp = shift_table[i];
if (rp && (rp->nreds > 1
|| (sp && ! ISVAR(accessing_symbol[sp->shifts[0]]))))
count += rp->nreds;
else
consistent[i] = 1;
if (sp)
for (k = 0; k < sp->nshifts; k++)
{
if (accessing_symbol[sp->shifts[k]] == error_token_number)
{
consistent[i] = 0;
break;
}
}
}
lookaheads[nstates] = count;
if (count == 0)
{
LA = NEW2(1 * tokensetsize, unsigned);
LAruleno = NEW2(1, short);
lookback = NEW2(1, shorts *);
}
else
{
LA = NEW2(count * tokensetsize, unsigned);
LAruleno = NEW2(count, short);
lookback = NEW2(count, shorts *);
}
np = LAruleno;
for (i = 0; i < nstates; i++)
{
if (!consistent[i])
{
if (rp = reduction_table[i])
for (j = 0; j < rp->nreds; j++)
*np++ = rp->rules[j];
}
}
}
void
set_goto_map()
{
register shifts *sp;
register int i;
register int symbol;
register int k;
register short *temp_map;
register int state2;
register int state1;
goto_map = NEW2(nvars + 1, short) - ntokens;
temp_map = NEW2(nvars + 1, short) - ntokens;
ngotos = 0;
for (sp = first_shift; sp; sp = sp->next)
{
for (i = sp->nshifts - 1; i >= 0; i--)
{
symbol = accessing_symbol[sp->shifts[i]];
if (ISTOKEN(symbol)) break;
if (ngotos == MAXSHORT)
toomany("gotos");
ngotos++;
goto_map[symbol]++;
}
}
k = 0;
for (i = ntokens; i < nsyms; i++)
{
temp_map[i] = k;
k += goto_map[i];
}
for (i = ntokens; i < nsyms; i++)
goto_map[i] = temp_map[i];
goto_map[nsyms] = ngotos;
temp_map[nsyms] = ngotos;
from_state = NEW2(ngotos, short);
to_state = NEW2(ngotos, short);
for (sp = first_shift; sp; sp = sp->next)
{
state1 = sp->number;
for (i = sp->nshifts - 1; i >= 0; i--)
{
state2 = sp->shifts[i];
symbol = accessing_symbol[state2];
if (ISTOKEN(symbol)) break;
k = temp_map[symbol]++;
from_state[k] = state1;
to_state[k] = state2;
}
}
FREE(temp_map + ntokens);
}
/* Map_goto maps a state/symbol pair into its numeric representation. */
int
map_goto(state, symbol)
int state;
int symbol;
{
register int high;
register int low;
register int middle;
register int s;
low = goto_map[symbol];
high = goto_map[symbol + 1] - 1;
while (low <= high)
{
middle = (low + high) / 2;
s = from_state[middle];
if (s == state)
return (middle);
else if (s < state)
low = middle + 1;
else
high = middle - 1;
}
berror("map_goto");
/* NOTREACHED */
return 0;
}
void
initialize_F()
{
register int i;
register int j;
register int k;
register shifts *sp;
register short *edge;
register unsigned *rowp;
register short *rp;
register short **reads;
register int nedges;
register int stateno;
register int symbol;
register int nwords;
nwords = ngotos * tokensetsize;
F = NEW2(nwords, unsigned);
reads = NEW2(ngotos, short *);
edge = NEW2(ngotos + 1, short);
nedges = 0;
rowp = F;
for (i = 0; i < ngotos; i++)
{
stateno = to_state[i];
sp = shift_table[stateno];
if (sp)
{
k = sp->nshifts;
for (j = 0; j < k; j++)
{
symbol = accessing_symbol[sp->shifts[j]];
if (ISVAR(symbol))
break;
SETBIT(rowp, symbol);
}
for (; j < k; j++)
{
symbol = accessing_symbol[sp->shifts[j]];
if (nullable[symbol])
edge[nedges++] = map_goto(stateno, symbol);
}
if (nedges)
{
reads[i] = rp = NEW2(nedges + 1, short);
for (j = 0; j < nedges; j++)
rp[j] = edge[j];
rp[nedges] = -1;
nedges = 0;
}
}
rowp += tokensetsize;
}
digraph(reads);
for (i = 0; i < ngotos; i++)
{
if (reads[i])
FREE(reads[i]);
}
FREE(reads);
FREE(edge);
}
void
build_relations()
{
register int i;
register int j;
register int k;
register short *rulep;
register short *rp;
register shifts *sp;
register int length;
register int nedges;
register int done;
register int state1;
register int stateno;
register int symbol1;
register int symbol2;
register short *shortp;
register short *edge;
register short *states;
register short **new_includes;
includes = NEW2(ngotos, short *);
edge = NEW2(ngotos + 1, short);
states = NEW2(maxrhs + 1, short);
for (i = 0; i < ngotos; i++)
{
nedges = 0;
state1 = from_state[i];
symbol1 = accessing_symbol[to_state[i]];
for (rulep = derives[symbol1]; *rulep > 0; rulep++)
{
length = 1;
states[0] = state1;
stateno = state1;
for (rp = ritem + rrhs[*rulep]; *rp > 0; rp++)
{
symbol2 = *rp;
sp = shift_table[stateno];
k = sp->nshifts;
for (j = 0; j < k; j++)
{
stateno = sp->shifts[j];
if (accessing_symbol[stateno] == symbol2) break;
}
states[length++] = stateno;
}
if (!consistent[stateno])
add_lookback_edge(stateno, *rulep, i);
length--;
done = 0;
while (!done)
{
done = 1;
rp--;
/* JF added rp>=ritem && I hope to god its right! */
if (rp>=ritem && ISVAR(*rp))
{
stateno = states[--length];
edge[nedges++] = map_goto(stateno, *rp);
if (nullable[*rp]) done = 0;
}
}
}
if (nedges)
{
includes[i] = shortp = NEW2(nedges + 1, short);
for (j = 0; j < nedges; j++)
shortp[j] = edge[j];
shortp[nedges] = -1;
}
}
new_includes = transpose(includes, ngotos);
for (i = 0; i < ngotos; i++)
if (includes[i])
FREE(includes[i]);
FREE(includes);
includes = new_includes;
FREE(edge);
FREE(states);
}
void
add_lookback_edge(stateno, ruleno, gotono)
int stateno;
int ruleno;
int gotono;
{
register int i;
register int k;
register int found;
register shorts *sp;
i = lookaheads[stateno];
k = lookaheads[stateno + 1];
found = 0;
while (!found && i < k)
{
if (LAruleno[i] == ruleno)
found = 1;
else
i++;
}
if (found == 0)
berror("add_lookback_edge");
sp = NEW(shorts);
sp->next = lookback[i];
sp->value = gotono;
lookback[i] = sp;
}
short **
transpose(R_arg, n)
short **R_arg;
int n;
{
register short **new_R;
register short **temp_R;
register short *nedges;
register short *sp;
register int i;
register int k;
nedges = NEW2(n, short);
for (i = 0; i < n; i++)
{
sp = R_arg[i];
if (sp)
{
while (*sp >= 0)
nedges[*sp++]++;
}
}
new_R = NEW2(n, short *);
temp_R = NEW2(n, short *);
for (i = 0; i < n; i++)
{
k = nedges[i];
if (k > 0)
{
sp = NEW2(k + 1, short);
new_R[i] = sp;
temp_R[i] = sp;
sp[k] = -1;
}
}
FREE(nedges);
for (i = 0; i < n; i++)
{
sp = R_arg[i];
if (sp)
{
while (*sp >= 0)
*temp_R[*sp++]++ = i;
}
}
FREE(temp_R);
return (new_R);
}
void
compute_FOLLOWS()
{
register int i;
digraph(includes);
for (i = 0; i < ngotos; i++)
{
if (includes[i]) FREE(includes[i]);
}
FREE(includes);
}
void
compute_lookaheads()
{
register int i;
register int n;
register unsigned *fp1;
register unsigned *fp2;
register unsigned *fp3;
register shorts *sp;
register unsigned *rowp;
/* register short *rulep; JF unused */
/* register int count; JF unused */
register shorts *sptmp;/* JF */
rowp = LA;
n = lookaheads[nstates];
for (i = 0; i < n; i++)
{
fp3 = rowp + tokensetsize;
for (sp = lookback[i]; sp; sp = sp->next)
{
fp1 = rowp;
fp2 = F + tokensetsize * sp->value;
while (fp1 < fp3)
*fp1++ |= *fp2++;
}
rowp = fp3;
}
for (i = 0; i < n; i++)
{/* JF removed ref to freed storage */
for (sp = lookback[i]; sp; sp = sptmp) {
sptmp=sp->next;
FREE(sp);
}
}
FREE(lookback);
FREE(F);
}
void
digraph(relation)
short **relation;
{
register int i;
infinity = ngotos + 2;
INDEX = NEW2(ngotos + 1, short);
VERTICES = NEW2(ngotos + 1, short);
top = 0;
R = relation;
for (i = 0; i < ngotos; i++)
INDEX[i] = 0;
for (i = 0; i < ngotos; i++)
{
if (INDEX[i] == 0 && R[i])
traverse(i);
}
FREE(INDEX);
FREE(VERTICES);
}
void
traverse(i)
register int i;
{
register unsigned *fp1;
register unsigned *fp2;
register unsigned *fp3;
register int j;
register short *rp;
int height;
unsigned *base;
VERTICES[++top] = i;
INDEX[i] = height = top;
base = F + i * tokensetsize;
fp3 = base + tokensetsize;
rp = R[i];
if (rp)
{
while ((j = *rp++) >= 0)
{
if (INDEX[j] == 0)
traverse(j);
if (INDEX[i] > INDEX[j])
INDEX[i] = INDEX[j];
fp1 = base;
fp2 = F + j * tokensetsize;
while (fp1 < fp3)
*fp1++ |= *fp2++;
}
}
if (INDEX[i] == height)
{
for (;;)
{
j = VERTICES[top--];
INDEX[j] = infinity;
if (i == j)
break;
fp1 = base;
fp2 = F + j * tokensetsize;
while (fp1 < fp3)
*fp2++ = *fp1++;
}
}
}

137
src/state.h Normal file
View File

@@ -0,0 +1,137 @@
/* Type definitions for nondeterministic finite state machine for bison,
Copyright (C) 1984, 1989 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bison is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bison; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* These type definitions are used to represent a nondeterministic
finite state machine that parses the specified grammar.
This information is generated by the function generate_states
in the file LR0.
Each state of the machine is described by a set of items --
particular positions in particular rules -- that are the possible
places where parsing could continue when the machine is in this state.
These symbols at these items are the allowable inputs that can follow now.
A core represents one state. States are numbered in the number field.
When generate_states is finished, the starting state is state 0
and nstates is the number of states. (A transition to a state
whose state number is nstates indicates termination.) All the cores
are chained together and first_state points to the first one (state 0).
For each state there is a particular symbol which must have been the
last thing accepted to reach that state. It is the accessing_symbol
of the core.
Each core contains a vector of nitems items which are the indices
in the ritems vector of the items that are selected in this state.
The link field is used for chaining buckets that hash states by
their itemsets. This is for recognizing equivalent states and
combining them when the states are generated.
The two types of transitions are shifts (push the lookahead token
and read another) and reductions (combine the last n things on the
stack via a rule, replace them with the symbol that the rule derives,
and leave the lookahead token alone). When the states are generated,
these transitions are represented in two other lists.
Each shifts structure describes the possible shift transitions out
of one state, the state whose number is in the number field.
The shifts structures are linked through next and first_shift points to them.
Each contains a vector of numbers of the states that shift transitions
can go to. The accessing_symbol fields of those states' cores say what kind
of input leads to them.
A shift to state zero should be ignored. Conflict resolution
deletes shifts by changing them to zero.
Each reductions structure describes the possible reductions at the state
whose number is in the number field. The data is a list of nreds rules,
represented by their rule numbers. first_reduction points to the list
of these structures.
Conflict resolution can decide that certain tokens in certain
states should explicitly be errors (for implementing %nonassoc).
For each state, the tokens that are errors for this reason
are recorded in an errs structure, which has the state number
in its number field. The rest of the errs structure is full
of token numbers.
There is at least one shift transition present in state zero.
It leads to a next-to-final state whose accessing_symbol is
the grammar's start symbol. The next-to-final state has one shift
to the final state, whose accessing_symbol is zero (end of input).
The final state has one shift, which goes to the termination state
(whose number is nstates-1).
The reason for the extra state at the end is to placate the parser's
strategy of making all decisions one token ahead of its actions. */
typedef
struct core
{
struct core *next;
struct core *link;
short number;
short accessing_symbol;
short nitems;
short items[1];
}
core;
typedef
struct shifts
{
struct shifts *next;
short number;
short nshifts;
short shifts[1];
}
shifts;
typedef
struct errs
{
short nerrs;
short errs[1];
}
errs;
typedef
struct reductions
{
struct reductions *next;
short number;
short nreds;
short rules[1];
}
reductions;
extern int nstates;
extern core *first_state;
extern shifts *first_shift;
extern reductions *first_reduction;