679 lines
12 KiB
C
679 lines
12 KiB
C
/* $NetBSD: lr0.c,v 1.10 2009/04/14 09:41:30 lukem Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1989 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Robert Paul Corbett.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#if defined(__RCSID) && !defined(lint)
|
|
#if 0
|
|
static char sccsid[] = "@(#)lr0.c 5.3 (Berkeley) 1/20/91";
|
|
#else
|
|
__RCSID("$NetBSD: lr0.c,v 1.10 2009/04/14 09:41:30 lukem Exp $");
|
|
#endif
|
|
#endif /* not lint */
|
|
|
|
#include "defs.h"
|
|
|
|
extern short *itemset;
|
|
extern short *itemsetend;
|
|
extern unsigned *ruleset;
|
|
|
|
int nstates;
|
|
core *first_state;
|
|
shifts *first_shift;
|
|
reductions *first_reduction;
|
|
|
|
static int get_state(int);
|
|
static core *new_state(int);
|
|
|
|
static void allocate_itemsets(void);
|
|
static void allocate_storage(void);
|
|
static void append_states(void);
|
|
static void free_storage(void);
|
|
static void generate_states(void);
|
|
static void initialize_states(void);
|
|
static void new_itemsets(void);
|
|
#ifdef DEBUG
|
|
static void show_cores(void);
|
|
static void show_ritems(void);
|
|
static void show_rrhs(void);
|
|
static void show_shifts(void);
|
|
#endif
|
|
static void save_shifts(void);
|
|
static void save_reductions(void);
|
|
static void set_derives(void);
|
|
static void set_nullable(void);
|
|
#ifdef DEBUG
|
|
static void print_derives(void);
|
|
static void free_derives(void);
|
|
static void free_nullable(void);
|
|
#endif
|
|
|
|
static core **state_set;
|
|
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;
|
|
|
|
static void
|
|
allocate_itemsets(void)
|
|
{
|
|
short *itemp;
|
|
short *item_end;
|
|
int symbol;
|
|
int i;
|
|
int count;
|
|
int max;
|
|
short *symbol_count;
|
|
|
|
count = 0;
|
|
symbol_count = NEW2(nsyms, short);
|
|
|
|
item_end = ritem + nitems;
|
|
for (itemp = ritem; itemp < item_end; itemp++)
|
|
{
|
|
symbol = *itemp;
|
|
if (symbol >= 0)
|
|
{
|
|
count++;
|
|
symbol_count[symbol]++;
|
|
}
|
|
}
|
|
|
|
kernel_base = NEW2(nsyms, short *);
|
|
kernel_items = NEW2(count, short);
|
|
|
|
count = 0;
|
|
max = 0;
|
|
for (i = 0; i < nsyms; i++)
|
|
{
|
|
kernel_base[i] = kernel_items + count;
|
|
count += symbol_count[i];
|
|
if (max < symbol_count[i])
|
|
max = symbol_count[i];
|
|
}
|
|
|
|
shift_symbol = symbol_count;
|
|
kernel_end = NEW2(nsyms, short *);
|
|
}
|
|
|
|
static void
|
|
allocate_storage(void)
|
|
{
|
|
allocate_itemsets();
|
|
shiftset = NEW2(nsyms, short);
|
|
redset = NEW2(nrules + 1, short);
|
|
state_set = NEW2(nitems, core *);
|
|
}
|
|
|
|
static void
|
|
append_states(void)
|
|
{
|
|
int i;
|
|
int j;
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
free_storage(void)
|
|
{
|
|
FREE(shift_symbol);
|
|
FREE(redset);
|
|
FREE(shiftset);
|
|
FREE(kernel_base);
|
|
FREE(kernel_end);
|
|
FREE(kernel_items);
|
|
FREE(state_set);
|
|
}
|
|
|
|
|
|
static void
|
|
generate_states(void)
|
|
{
|
|
allocate_storage();
|
|
itemset = NEW2(nitems, short);
|
|
ruleset = NEW2(WORDSIZE(nrules), unsigned);
|
|
set_first_derives();
|
|
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();
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
get_state(int symbol)
|
|
{
|
|
int key;
|
|
short *isp1;
|
|
short *isp2;
|
|
short *iend;
|
|
core *sp;
|
|
int found;
|
|
int n;
|
|
|
|
#ifdef TRACE
|
|
fprintf(stderr, "Entering get_state(%d)\n", symbol);
|
|
#endif
|
|
|
|
isp1 = kernel_base[symbol];
|
|
iend = kernel_end[symbol];
|
|
n = iend - isp1;
|
|
|
|
key = *isp1;
|
|
assert(0 <= key && key < nitems);
|
|
sp = state_set[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_set[key] = sp = new_state(symbol);
|
|
}
|
|
|
|
return (sp->number);
|
|
}
|
|
|
|
|
|
static void
|
|
initialize_states(void)
|
|
{
|
|
int i;
|
|
short *start_derives;
|
|
core *p;
|
|
|
|
start_derives = derives[start_symbol];
|
|
for (i = 0; start_derives[i] >= 0; ++i)
|
|
continue;
|
|
|
|
p = (core *) MALLOC(sizeof(core) + i*sizeof(short));
|
|
if (p == 0) no_space();
|
|
|
|
p->next = 0;
|
|
p->link = 0;
|
|
p->number = 0;
|
|
p->accessing_symbol = 0;
|
|
p->nitems = i;
|
|
|
|
for (i = 0; start_derives[i] >= 0; ++i)
|
|
p->items[i] = rrhs[start_derives[i]];
|
|
|
|
first_state = last_state = this_state = p;
|
|
nstates = 1;
|
|
}
|
|
|
|
|
|
static void
|
|
new_itemsets(void)
|
|
{
|
|
int i;
|
|
int shiftcount;
|
|
short *isp;
|
|
short *ksp;
|
|
int symbol;
|
|
|
|
for (i = 0; i < nsyms; i++)
|
|
kernel_end[i] = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
static core *
|
|
new_state(int symbol)
|
|
{
|
|
int n;
|
|
core *p;
|
|
short *isp1;
|
|
short *isp2;
|
|
short *iend;
|
|
|
|
#ifdef TRACE
|
|
fprintf(stderr, "Entering new_state(%d)\n", symbol);
|
|
#endif
|
|
|
|
if (nstates >= MAXSHORT)
|
|
fatal("too many states");
|
|
|
|
isp1 = kernel_base[symbol];
|
|
iend = kernel_end[symbol];
|
|
n = iend - isp1;
|
|
|
|
p = (core *) allocate((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);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* show_cores is used for debugging */
|
|
static void
|
|
show_cores(void)
|
|
{
|
|
core *p;
|
|
int i, j, k, n;
|
|
int itemno;
|
|
|
|
k = 0;
|
|
for (p = first_state; p; ++k, p = p->next)
|
|
{
|
|
if (k) printf("\n");
|
|
printf("state %d, number = %d, accessing symbol = %s\n",
|
|
k, p->number, symbol_name[p->accessing_symbol]);
|
|
n = p->nitems;
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
itemno = p->items[i];
|
|
printf("%4d ", itemno);
|
|
j = itemno;
|
|
while (ritem[j] >= 0) ++j;
|
|
printf("%s :", symbol_name[rlhs[-ritem[j]]]);
|
|
j = rrhs[-ritem[j]];
|
|
while (j < itemno)
|
|
printf(" %s", symbol_name[ritem[j++]]);
|
|
printf(" .");
|
|
while (ritem[j] >= 0)
|
|
printf(" %s", symbol_name[ritem[j++]]);
|
|
printf("\n");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* show_ritems is used for debugging */
|
|
static void
|
|
show_ritems(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nitems; ++i)
|
|
printf("ritem[%d] = %d\n", i, ritem[i]);
|
|
}
|
|
|
|
|
|
/* show_rrhs is used for debugging */
|
|
static void
|
|
show_rrhs(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nrules; ++i)
|
|
printf("rrhs[%d] = %d\n", i, rrhs[i]);
|
|
}
|
|
|
|
|
|
/* show_shifts is used for debugging */
|
|
static void
|
|
show_shifts(void)
|
|
{
|
|
shifts *p;
|
|
int i, j, k;
|
|
|
|
k = 0;
|
|
for (p = first_shift; p; ++k, p = p->next)
|
|
{
|
|
if (k) printf("\n");
|
|
printf("shift %d, number = %d, nshifts = %d\n", k, p->number,
|
|
p->nshifts);
|
|
j = p->nshifts;
|
|
for (i = 0; i < j; ++i)
|
|
printf("\t%d\n", p->shift[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
static void
|
|
save_shifts(void)
|
|
{
|
|
shifts *p;
|
|
short *sp1;
|
|
short *sp2;
|
|
short *send;
|
|
|
|
p = (shifts *) allocate((unsigned) (sizeof(shifts) +
|
|
(nshifts - 1) * sizeof(short)));
|
|
|
|
p->number = this_state->number;
|
|
p->nshifts = nshifts;
|
|
|
|
sp1 = shiftset;
|
|
sp2 = p->shift;
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
save_reductions(void)
|
|
{
|
|
short *isp;
|
|
short *rp1;
|
|
short *rp2;
|
|
int item;
|
|
int count;
|
|
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 *) allocate((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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
set_derives(void)
|
|
{
|
|
int i, k;
|
|
int lhs;
|
|
short *rules;
|
|
|
|
derives = NEW2(nsyms, short *);
|
|
if (start_symbol >= nsyms)
|
|
return;
|
|
|
|
rules = NEW2(nvars + nrules, short);
|
|
|
|
k = 0;
|
|
for (lhs = start_symbol; lhs < nsyms; lhs++)
|
|
{
|
|
derives[lhs] = rules + k;
|
|
for (i = 0; i < nrules; i++)
|
|
{
|
|
if (rlhs[i] == lhs)
|
|
{
|
|
rules[k] = i;
|
|
k++;
|
|
}
|
|
}
|
|
rules[k] = -1;
|
|
k++;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
print_derives();
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
free_derives(void)
|
|
{
|
|
FREE(derives[start_symbol]);
|
|
FREE(derives);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
print_derives(void)
|
|
{
|
|
int i;
|
|
short *sp;
|
|
|
|
printf("\nDERIVES\n\n");
|
|
|
|
for (i = start_symbol; i < nsyms; i++)
|
|
{
|
|
printf("%s derives ", symbol_name[i]);
|
|
for (sp = derives[i]; *sp >= 0; sp++)
|
|
{
|
|
printf(" %d", *sp);
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
putchar('\n');
|
|
}
|
|
#endif
|
|
|
|
|
|
static void
|
|
set_nullable(void)
|
|
{
|
|
int i, j;
|
|
int empty;
|
|
int isdone;
|
|
|
|
nullable = MALLOC(nsyms);
|
|
if (nullable == 0) no_space();
|
|
|
|
for (i = 0; i < nsyms; ++i)
|
|
nullable[i] = 0;
|
|
|
|
isdone = 0;
|
|
while (!isdone)
|
|
{
|
|
isdone = 1;
|
|
for (i = 1; i < nitems; i++)
|
|
{
|
|
empty = 1;
|
|
while ((j = ritem[i]) >= 0)
|
|
{
|
|
if (!nullable[j])
|
|
empty = 0;
|
|
++i;
|
|
}
|
|
if (empty)
|
|
{
|
|
j = rlhs[-j];
|
|
if (!nullable[j])
|
|
{
|
|
nullable[j] = 1;
|
|
isdone = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
for (i = 0; i < nsyms; i++)
|
|
{
|
|
if (nullable[i])
|
|
printf("%s is nullable\n", symbol_name[i]);
|
|
else
|
|
printf("%s is not nullable\n", symbol_name[i]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
free_nullable(void)
|
|
{
|
|
FREE(nullable);
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
lr0(void)
|
|
{
|
|
set_derives();
|
|
set_nullable();
|
|
generate_states();
|
|
}
|