#include <stdio.h>
#include "system.h"
#include "machine.h"
#include "new.h"
#include "gram.h"
#include "state.h"
extern char *nullable;
extern short *itemset;
extern short *itemsetend;
int nstates;
int final_state;
core *first_state;
shifts *first_shift;
reductions *first_reduction;
int get_state();
core *new_state();
void new_itemsets();
void append_states();
void initialize_states();
void save_shifts();
void save_reductions();
void augment_automaton();
void insert_start_shift();
extern void initialize_closure();
extern void closure();
extern void finalize_closure();
extern void toomany();
static core *this_state;
static core *last_state;
static shifts *last_shift;
static reductions *last_reduction;
static int nshifts;
static short *shift_symbol;
static short *redset;
static short *shiftset;
static short **kernel_base;
static short **kernel_end;
static short *kernel_items;
#define STATE_TABLE_SIZE 1009
static core **state_table;
void
allocate_itemsets()
{
register short *itemp;
register int symbol;
register int i;
register int count;
register short *symbol_count;
count = 0;
symbol_count = NEW2(nsyms, short);
itemp = ritem;
symbol = *itemp++;
while (symbol)
{
if (symbol > 0)
{
count++;
symbol_count[symbol]++;
}
symbol = *itemp++;
}
kernel_base = NEW2(nsyms, short *);
kernel_items = NEW2(count, short);
count = 0;
for (i = 0; i < nsyms; i++)
{
kernel_base[i] = kernel_items + count;
count += symbol_count[i];
}
shift_symbol = symbol_count;
kernel_end = NEW2(nsyms, short *);
}
void
allocate_storage()
{
allocate_itemsets();
shiftset = NEW2(nsyms, short);
redset = NEW2(nrules + 1, short);
state_table = NEW2(STATE_TABLE_SIZE, core *);
}
void
free_storage()
{
FREE(shift_symbol);
FREE(redset);
FREE(shiftset);
FREE(kernel_base);
FREE(kernel_end);
FREE(kernel_items);
FREE(state_table);
}
void
generate_states()
{
allocate_storage();
initialize_closure(nitems);
initialize_states();
while (this_state)
{
closure(this_state->items, this_state->nitems);
save_reductions();
new_itemsets();
append_states();
if (nshifts > 0)
save_shifts();
this_state = this_state->next;
}
finalize_closure();
free_storage();
augment_automaton();
}
void
new_itemsets()
{
register int i;
register int shiftcount;
register short *isp;
register short *ksp;
register int symbol;
#ifdef TRACE
fprintf(stderr, "Entering new_itemsets\n");
#endif
for (i = 0; i < nsyms; i++)
kernel_end[i] = NULL;
shiftcount = 0;
isp = itemset;
while (isp < itemsetend)
{
i = *isp++;
symbol = ritem[i];
if (symbol > 0)
{
ksp = kernel_end[symbol];
if (!ksp)
{
shift_symbol[shiftcount++] = symbol;
ksp = kernel_base[symbol];
}
*ksp++ = i + 1;
kernel_end[symbol] = ksp;
}
}
nshifts = shiftcount;
}
void
append_states()
{
register int i;
register int j;
register int symbol;
#ifdef TRACE
fprintf(stderr, "Entering append_states\n");
#endif
for (i = 1; i < nshifts; i++)
{
symbol = shift_symbol[i];
j = i;
while (j > 0 && shift_symbol[j - 1] > symbol)
{
shift_symbol[j] = shift_symbol[j - 1];
j--;
}
shift_symbol[j] = symbol;
}
for (i = 0; i < nshifts; i++)
{
symbol = shift_symbol[i];
shiftset[i] = get_state(symbol);
}
}
int
get_state(symbol)
int symbol;
{
register int key;
register short *isp1;
register short *isp2;
register short *iend;
register core *sp;
register int found;
int n;
#ifdef TRACE
fprintf(stderr, "Entering get_state, symbol = %d\n", symbol);
#endif
isp1 = kernel_base[symbol];
iend = kernel_end[symbol];
n = iend - isp1;
key = 0;
while (isp1 < iend)
key += *isp1++;
key = key % STATE_TABLE_SIZE;
sp = state_table[key];
if (sp)
{
found = 0;
while (!found)
{
if (sp->nitems == n)
{
found = 1;
isp1 = kernel_base[symbol];
isp2 = sp->items;
while (found && isp1 < iend)
{
if (*isp1++ != *isp2++)
found = 0;
}
}
if (!found)
{
if (sp->link)
{
sp = sp->link;
}
else
{
sp = sp->link = new_state(symbol);
found = 1;
}
}
}
}
else
{
state_table[key] = sp = new_state(symbol);
}
return (sp->number);
}
core *
new_state(symbol)
int symbol;
{
register int n;
register core *p;
register short *isp1;
register short *isp2;
register short *iend;
#ifdef TRACE
fprintf(stderr, "Entering new_state, symbol = %d\n", symbol);
#endif
if (nstates >= MAXSHORT)
toomany("states");
isp1 = kernel_base[symbol];
iend = kernel_end[symbol];
n = iend - isp1;
p = (core *) xmalloc((unsigned) (sizeof(core) + (n - 1) * sizeof(short)));
p->accessing_symbol = symbol;
p->number = nstates;
p->nitems = n;
isp2 = p->items;
while (isp1 < iend)
*isp2++ = *isp1++;
last_state->next = p;
last_state = p;
nstates++;
return (p);
}
void
initialize_states()
{
register core *p;
p = (core *) xmalloc((unsigned) (sizeof(core) - sizeof(short)));
first_state = last_state = this_state = p;
nstates = 1;
}
void
save_shifts()
{
register shifts *p;
register short *sp1;
register short *sp2;
register short *send;
p = (shifts *) xmalloc((unsigned) (sizeof(shifts) +
(nshifts - 1) * sizeof(short)));
p->number = this_state->number;
p->nshifts = nshifts;
sp1 = shiftset;
sp2 = p->shifts;
send = shiftset + nshifts;
while (sp1 < send)
*sp2++ = *sp1++;
if (last_shift)
{
last_shift->next = p;
last_shift = p;
}
else
{
first_shift = p;
last_shift = p;
}
}
void
save_reductions()
{
register short *isp;
register short *rp1;
register short *rp2;
register int item;
register int count;
register reductions *p;
short *rend;
count = 0;
for (isp = itemset; isp < itemsetend; isp++)
{
item = ritem[*isp];
if (item < 0)
{
redset[count++] = -item;
}
}
if (count)
{
p = (reductions *) xmalloc((unsigned) (sizeof(reductions) +
(count - 1) * sizeof(short)));
p->number = this_state->number;
p->nreds = count;
rp1 = redset;
rp2 = p->rules;
rend = rp1 + count;
while (rp1 < rend)
*rp2++ = *rp1++;
if (last_reduction)
{
last_reduction->next = p;
last_reduction = p;
}
else
{
first_reduction = p;
last_reduction = p;
}
}
}
void
augment_automaton()
{
register int i;
register int k;
register core *statep;
register shifts *sp;
register shifts *sp2;
register shifts *sp1;
sp = first_shift;
if (sp)
{
if (sp->number == 0)
{
k = sp->nshifts;
statep = first_state->next;
while (statep->accessing_symbol < start_symbol
&& statep->number < k)
statep = statep->next;
if (statep->accessing_symbol == start_symbol)
{
k = statep->number;
while (sp && sp->number < k)
{
sp1 = sp;
sp = sp->next;
}
if (sp && sp->number == k)
{
sp2 = (shifts *) xmalloc((unsigned) (sizeof(shifts)
+ sp->nshifts * sizeof(short)));
sp2->number = k;
sp2->nshifts = sp->nshifts + 1;
sp2->shifts[0] = nstates;
for (i = sp->nshifts; i > 0; i--)
sp2->shifts[i] = sp->shifts[i - 1];
sp2->next = sp->next;
sp1->next = sp2;
if (sp == last_shift)
last_shift = sp2;
FREE(sp);
}
else
{
sp2 = NEW(shifts);
sp2->number = k;
sp2->nshifts = 1;
sp2->shifts[0] = nstates;
sp2->next = sp;
sp1->next = sp2;
if (sp == 0)
last_shift = sp2;
}
}
else
{
sp = first_shift;
sp2 = (shifts *) xmalloc(sizeof(shifts)
+ sp->nshifts * sizeof(short));
sp2->nshifts = sp->nshifts + 1;
statep = first_state->next;
for (k = 0, i = 0; i < sp->nshifts; k++, i++)
{
if (statep->accessing_symbol > start_symbol && i == k)
sp2->shifts[k++] = nstates;
sp2->shifts[k] = sp->shifts[i];
statep = statep->next;
}
if (i == k)
sp2->shifts[k++] = nstates;
sp2->next = sp->next;
first_shift = sp2;
if (last_shift == sp)
last_shift = sp2;
FREE(sp);
insert_start_shift();
}
}
else
{
sp = NEW(shifts);
sp->nshifts = 1;
sp->shifts[0] = nstates;
sp->next = first_shift;
first_shift = sp;
insert_start_shift();
}
}
else
{
sp = NEW(shifts);
sp->nshifts = 1;
sp->shifts[0] = nstates;
first_shift = sp;
last_shift = sp;
insert_start_shift();
}
statep = (core *) xmalloc((unsigned) (sizeof(core) - sizeof(short)));
statep->number = nstates;
last_state->next = statep;
last_state = statep;
sp = NEW(shifts);
sp->number = nstates++;
sp->nshifts = 1;
sp->shifts[0] = nstates;
last_shift->next = sp;
last_shift = sp;
final_state = nstates;
statep = (core *) xmalloc((unsigned) (sizeof(core) - sizeof(short)));
statep->number = nstates++;
last_state->next = statep;
last_state = statep;
}
void
insert_start_shift()
{
register core *statep;
register shifts *sp;
statep = (core *) xmalloc((unsigned) (sizeof(core) - sizeof(short)));
statep->number = nstates;
statep->accessing_symbol = start_symbol;
last_state->next = statep;
last_state = statep;
sp = NEW(shifts);
sp->number = nstates++;
sp->nshifts = 1;
sp->shifts[0] = nstates;
last_shift->next = sp;
last_shift = sp;
}