[comp.sources.amiga] v02i021: bison

grwalter@watmath.waterloo.edu (Fred Walter) (09/15/87)

This version of bison is an update to the version on FISH disk 51,
which was an update to the version on disk 4 that Johan Widen did.
The changes that Doug Leavitt supplied in the Diffs directory
were found to be necessary, so I merged them into the source,
along with making some other minor changes.

The problem that was fixed was that bison was causing the AMIGA to
guru when used on sufficiently large/complex source files.

Only the files that were changed are included in the following shar
file. (ie. you need a copy of the sources from FISH disk 51 to
compile this). If people desire, I can post the uuencoded binary (all
100k+ of it).

There probably are still more bugs left.
... sigh.

         G. R. Walter
         grwalter@watmath.waterloo.cdn

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This archive created: Tue Sep 15 14:06:14 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	BISON.LNK
#	LR0.c
#	MAKE.BISON
#	Makefile
#	README
#	allocate.c
#	calc.y
#	closure.c
#	new.h
#	print.c
#	string.h
#	symtab.c
#	warshall.c
cat << \SHAR_EOF > BISON.LNK
FROM LIB:c.o+allocate.o+warshall.o+closure.o+output.o
FROM reader.o+lr0.o+symtab.o+nullable.o+lex.o+print.o
FROM files.o+main.o+derives.o+lalr.o+conflicts.o
FROM gram.o+getargs.o
TO bison
LIB LIB:lc.lib+LIB:amiga.lib
NODEBUG
SHAR_EOF
cat << \SHAR_EOF > LR0.c
/* Generate the nondeterministic finite state machine for bison,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

/* See comments in state.h for the data structures that represent it.
   The entry point is generate_states.  */

#include <stdio.h>
#include "machine.h"
#include "new.h"
#include "gram.h"
#include "state.h"


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();

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;

/* hash table for states, to recognize equivalent ones.  */

#define	STATE_TABLE_SIZE	1009
static core **state_table;



allocate_itemsets()
{
  register short *itemp;
  register int symbol;
  register int i;
  register count;
  register int maxcount;
  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++;
    }

  /* see comments before new-itemset.  All the vectors of items
     live inside kernel_items.  The number of active items after
     some symbol cannot be more than the number of times that symbol
     appears as an item, which is symbol_count[symbol].
     We allocate that much space for each symbol.  */

  kernel_base = NEW2(nsyms, short *);
  kernel_items = NEW2(count, short);

  count = 0;
  maxcount = 0;
  for (i = 0; i < nsyms; i++)
    {
      kernel_base[i] = kernel_items + count;
      count += symbol_count[i];
      if (maxcount < symbol_count[i])
	maxcount = symbol_count[i];
    }

  shift_symbol = symbol_count;
  kernel_end = NEW2(nsyms, short *);
}



allocate_storage()
{
  allocate_itemsets();

  shiftset = NEW2(nsyms, short);
  redset = NEW2(nrules + 1, short);
  state_table = NEW2(STATE_TABLE_SIZE, core *);
}



free_storage()
{
  FREE(shift_symbol);
  FREE(redset);
  FREE(shiftset);
  FREE(kernel_base);
  FREE(kernel_end);
  FREE(kernel_items);
  FREE(state_table);
}



/* compute the nondeterministic finite state machine (see state.h for details)
from the grammar.  */

generate_states()
{
  allocate_storage();
  initialize_closure(nitems);
  initialize_states();

  while (this_state)
    {
      /* Set up ruleset and itemset for the transitions out of this state.
         ruleset gets a 1 bit for each rule that could reduce now.
	 itemset gets a vector of all the items that could be accepted next.  */
      closure(this_state->items, this_state->nitems);
      /* record the reductions allowed out of this state */
      save_reductions();
      /* find the itemsets of the states that shifts can reach */
      new_itemsets();
      /* find or create the core structures for those states */
      append_states();

      /* create the shifts structures for the shifts to those states,
         now that the state numbers transitioning to are known */
      if (nshifts > 0)
        save_shifts();

      /* states are queued when they are created; process them all */
      this_state = this_state->next;
    }

  /* discard various storage */
  finalize_closure();
  free_storage();

  /* set up initial and final states as parser wants them */
  augment_automaton();
}



/* Find which symbols can be shifted in the current state,
   and for each one record which items would be active after that shift.
   Uses the contents of itemset.
   shift_symbol is set to a vector of the symbols that can be shifted.
   For each symbol in the grammer, kernel_base[symbol] points to
   a vector of item numbers activated if that symbol is shifted,
   and kernel_end[symbol] points after the end of that vector.  */

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;
}



/* Use the information computed by new_itemset to find the state numbers
   reached by each shift transition from the current state.

   shiftset is set up as a vector of state numbers of those states.  */

append_states()
{
  register int i;
  register int j;
  register int symbol;

#ifdef	TRACE
  fprintf(stderr, "Entering append_states\n");
#endif

  /* first sort shift_symbol into increasing order */

  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);
    }
}



/* find the state number for the state we would get to
(from the current state) by shifting symbol.
Create a new state if no equivalent one exists already.
Used by append_states  */

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;

  /* add up the target state's active item numbers to get a hash key */
  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   /* bucket exhausted and no match */
		{
		  sp = sp->link = new_state(symbol);
		  found = 1;
		}
	    }
	}
    }
  else      /* bucket is empty */
    {
      state_table[key] = sp = new_state(symbol);
    }

  return ((int) sp->number);
}



/* subroutine of get_state.  create a new state for those items, if necessary.  */

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 *) 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);
}



initialize_states()
{
  register core *p;

  p = (core *) allocate((unsigned) (sizeof(core) - sizeof(short)));
  first_state = last_state = this_state = p;
  nstates = 1;
}



save_shifts()
{
  register shifts *p;
  register short *sp1;
  register short *sp2;
  register short *send;

  p = (shifts *) allocate((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;
    }
}



/* find which rules can be used for reduction transitions from the current state
   and make a reductions structure for the state to record their rule numbers.  */

save_reductions()
{
  register short *isp;
  register short *rp1;
  register short *rp2;
  register int item;
  register int count;
  register reductions *p;

  short *rend;

  /* find and count the active items that represent ends of rules */

  count = 0;
  for (isp = itemset; isp < itemsetend; isp++)
    {
      item = ritem[*isp];
      if (item < 0)
	{
	  redset[count++] = -item;
	}
    }

  /* make a reductions structure and copy the data into it.  */

  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;
	}
    }
}



/* Make sure that the initial state has a shift that accepts the
grammar's start symbol and goes to the next-to-final state,
which has a shift going to the final state, which has a shift
to the termination state.
Create such states and shifts if they don't happen to exist already.  */

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->number < k)
		{
		  sp1 = sp;
		  sp = sp->next;
		}

	      if (sp->number == k)
		{
		  sp2 = (shifts *) allocate((unsigned) (sizeof(shifts)
					+ sp->nshifts * sizeof(short)));
		  sp2->next = sp->next;
		  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];

		  sp1->next = sp2;
		  FREE(sp);
		}
	      else
		{
		  sp2 = NEW(shifts);
		  sp2->next = sp;
		  sp2->number = k;
		  sp2->nshifts = 1;
		  sp2->shifts[0] = nstates;

		  sp1->next = sp2;
		  if (!sp)
		    last_shift = sp2;
		}
	    }
	  else
	    {
	      k = statep->number;
	      sp = first_shift;

	      sp2 = (shifts *) allocate((unsigned) (sizeof(shifts)
					+ sp->nshifts * sizeof(short)));
	      sp2->next = sp->next;
	      sp2->nshifts = sp->nshifts + 1;

	      for (i = 0; i < k; i++)
		sp2->shifts[i] = sp->shifts[i];

	      sp2->shifts[k] = nstates;

	      for (i = k; i < sp->nshifts; i++)
		sp2->shifts[i + 1] = sp->shifts[i];

	      first_shift = sp2;
	      if (last_shift == sp)
		last_shift = sp2;

	      FREE(sp);

	      insert_start_shift();
	    }
	}
      else
	{
	  sp = NEW(shifts);
	  sp->next = first_shift;
	  sp->nshifts = 1;
	  sp->shifts[0] = nstates;

	  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 *) allocate((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 *) allocate((unsigned) (sizeof(core) - sizeof(short)));
  statep->number = nstates++;
  last_state->next = statep;
  last_state = statep;
}


/* subroutine of augment_automaton */

insert_start_shift()
{
  register core *statep;
  register shifts *sp;

  statep = (core *) allocate((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;
}
SHAR_EOF
cat << \SHAR_EOF > MAKE.BISON
lc -damiga -cw #?.c
blink with BISON.LNK
SHAR_EOF
cat << \SHAR_EOF > Makefile
CC =		cc
#CFLAGS =	-g

LPRFLAGS =	

OBJ1 =		LR0.o allocate.o closure.o conflicts.o derives.o files.o
OBJ2 =		getargs.o gram.o lalr.o lex.o main.o nullable.o output.o
OBJ3 =		print.o reader.o symtab.o warshall.o
OBJECTS = 	$(OBJ1) $(OBJ2) $(OBJ3)

CFILES1 =	LR0.c allocate.c closure.c conflicts.c derives.c files.c
CFILES2 =	getargs.c gram.c lalr.c lex.c main.c nullable.c output.c
CFILES3 =	print.c reader.c symtab.c warshall.c
CFILES =	$(CFILES1) $(CFILES2) $(CFILES3)

FILES1 =	Makefile files.h gram.h lex.h machine.h new.h state.h
FILES2 =	symtab.h types.h
FILES =		$(FILES1) $(FILES2) $(CFILES)

start :		bison

listing :
		pr $(FILES) | lpr $(LPRFLAGS)

lint :
		lint $(CFILES)

clean :
		rm -f *.o

bison :		$(OBJECTS)
		$(CC) -o bison $(OBJECTS)

LR0.o :		LR0.c
		$(CC) $(CFLAGS) -c LR0.c

allocate.o :	allocate.c
		$(CC) $(CFLAGS) -c allocate.c

closure.o :	closure.c
		$(CC) $(CFLAGS) -c closure.c

conflicts.o :	conflicts.c
		$(CC) $(CFLAGS) -c conflicts.c

derives.o :	derives.c
		$(CC) $(CFLAGS) -c derives.c

files.o :	files.c files.h
		$(CC) $(CFLAGS) -c files.c

getargs.o :	getargs.c
		$(CC) $(CFLAGS) -c getargs.c

gram.o :	gram.c
		$(CC) $(CFLAGS) -c gram.c

lalr.o :	lalr.c
		$(CC) $(CFLAGS) -c lalr.c

lex.o :		lex.c lex.h
		$(CC) $(CFLAGS) -c lex.c

main.o :	main.c
		$(CC) $(CFLAGS) -c main.c

nullable.o :	nullable.c
		$(CC) $(CFLAGS) -c nullable.c

output.o :	output.c
		$(CC) $(CFLAGS) -c output.c

print.o :	print.c
		$(CC) $(CFLAGS) -c print.c

reader.o :	reader.c
		$(CC) $(CFLAGS) -c reader.c

symtab.o :	symtab.c symtab.h
		$(CC) $(CFLAGS) -c symtab.c

warshall.o :	warshall.c
		$(CC) $(CFLAGS) -c warshall.c
SHAR_EOF
cat << \SHAR_EOF > README
This version of bison is an update to the version on FISH disk 51,
which was an update to the version on disk 4 that Johan Widen did.
The changes that Doug Leavitt supplied in the Diffs directory
were found to be necessary, so I merged them into the source,
along with making some other minor changes.

The problem that was fixed was that bison was causing the AMIGA to
guru when used on sufficiently large/complex source files.

To compile this using Lattice C 3.10 just

         execute MAKE.BISON

There probably are still more bugs left.
... sigh.

         G. R. Walter
         grwalter@watmath.waterloo.cdn
SHAR_EOF
cat << \SHAR_EOF > allocate.c
/* Allocate and clear storage for bison,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#include <stdio.h>


char *
allocate(n)
register unsigned n;
{
  register char *block;
#ifdef	amiga
  extern char *calloc();
#else
  register char *cp;
  register char *cend;
  extern char *malloc();
#endif

#ifdef	amiga
  block = calloc(n+4,1);
#else
  block = malloc(n);
#endif
  if (block == NULL)
    {
      fprintf(stderr, "storage limit exceeded");
      done(1);
    }

#ifdef	amiga
  block[0] = 'A';
  block[1] = 'M';
  block[2] = 'E';
  block[3] = 'N';
  return(block+4);
#else
  for(cp = block, cend = block+n;  cp < cend;  *cp++ = 0);
  return (block);
#endif
}

#ifdef	amiga
	void
bisonfree(loc)
char	*loc;
{
	register unsigned long l1, l2;
	register char *p;

	if (loc == (char *)0)
		return;
	l1 = (unsigned long)loc;
	l2 = l1 - 4;
	if (l2 > l1)
		return;		/* check for wrap */
	p = (char *)l2;
	if (p[0] != 'A' || p[1] != 'M' || p[2] != 'E' || p[3] != 'M')
		return;		/* Not allocated memory */
	free(p);		/* Free the real location */
}
#endif
SHAR_EOF
cat << \SHAR_EOF > calc.y
%{
#include <ctype.h>

int regs[26];
int base;

int val;
int printflag;

%}

%start stmt

%token DIGIT LETTER EXIT

%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS

%%

stmt	:	expr
			{ val = $1; printflag = 1; }
	|	 LETTER '=' expr
			{ regs[$1] = $3; }
	|	EXIT
			{ exit(0); }
	;

expr	:	'(' expr ')'
			{ $$ = $2; }
	|	expr '+' expr
			{ if ($1 == 69)
			    {
			      $$ = 2;
			      printf ("$1 became %d\n", $1);
			      $1 = 69;
			    }
			  $$ = $1 + $3; }
	|	expr '-' expr
			{ $$ = $1 - $3; }
	|	expr '*' expr
			{ $$ = $1 * $3; }
	|	expr '/' expr
			{ $$ = $1 / $3; }
	|	expr '%' expr
			{ $$ = $1 % $3; }
	|	expr '|' expr
			{ $$ = $1 | $3; }
	|	expr '&' expr
			{ $$ = $1 & $3; }
	|	'-' expr %prec UMINUS
			{ $$ = - $2; }
	|	LETTER
			{ $$ = regs[$1]; }
	|	number
/* 	|	'?'
			{ yydebug = !yydebug; }
*/	;

number	:	DIGIT
			{ $$ = $1;  base = ($1 == 0) ? 8 : 10; }
	|	number DIGIT
			{ $$ = base * $1 + $2; }
	;

%%

static int eol;

int
yylex()
{
  int c;

  while ( (c=getchar()) == ' ') {}
  if (c == '\n')
    { eol = 1;
      return 0; }
  if (c == 'Q')
    return(EXIT);
  if (islower(c))
    {
      yylval = c - 'a';
      return (LETTER);
    }
  if (isdigit(c))
    {
      yylval = c - '0';
      return (DIGIT);
    }
  return (c);
}

yyerror(s)
char *s;
{
  printf("%s\n", s);
}

main()
{
  for (;;)
    {
      eol = 0;
      printflag = 0;

      if (yyparse()) printflag = 0;

      if (printflag) printf("%d\n", val);

      while (!eol) yylex();
    }
}
SHAR_EOF
cat << \SHAR_EOF > closure.c
/* Subroutines for bison, copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

/* 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 "machine.h"
#include "new.h"
#include "gram.h"


extern short **derives;


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;



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.  */

set_fderives()
{
  register unsigned *rrow;
  register unsigned *vrow;
  register int j;
  register unsigned mask;
  register unsigned cword;
  register short *rp;

  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++;
      mask = 1;
      for (j = ntokens; j < nsyms; j++)
	{
	  if (cword & mask)
	    {
	      rp = derives[j];
	      while ((ruleno = *rp++) > 0)
		{
		  SETBIT(rrow, ruleno);
		}
	    }

	  mask <<= 1;
	  if (mask == 0)
	    {
	      cword = *vrow++;
	      mask = 1;
	    }
	}

      vrow += varsetsize;
      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. */

set_firsts()
{
  register unsigned *row;
  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
}



closure(core, n)
short *core;
int n;
{
  register int ruleno;
  register unsigned word;
  register unsigned mask;
  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
	{
	  mask = 1;
	  while (mask)
	    {
	      if (word & mask)
		{
		  itemno = rrhs[ruleno];
		  while (csp < csend && *csp < itemno)
		    *itemsetend++ = *csp++;
		  *itemsetend++ = itemno;
		}

	      mask <<= 1;
	      ruleno++;
	    }
	}
    }

  while (csp < csend)
    *itemsetend++ = *csp++;

#ifdef	DEBUG
  print_closure(n);
#endif
}



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;
  register unsigned cword;
  register unsigned mask;

  extern char **tags;

  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) * vrowsize);

      cword = *rowp++;
      mask = 1;
      for (j = 0; j < nsyms; j++)
	{
	  if (cword & mask)
	    printf("   %s\n", tags[j + ntokens]);

	  mask <<= 1;

	  if (mask == 0)
	    {
	      cword = *rowp++;
	      mask = 1;
	    }
	}
    }
}



print_fderives()
{
  register int i;
  register int j;
  register unsigned *rp;
  register unsigned cword;
  register unsigned mask;

  extern char **tags;

  printf("\n\n\nFDERIVES\n");

  for (i = ntokens; i < nsyms; i++)
    {
      printf("\n\n%s derives\n\n", tags[i]);
      rp = fderives + i * rrowsize;
      cword = *rp++;
      mask = 1;
      for (j = 0; j <= nrules; j++)
        {
	  if (cword & mask)
	    printf("   %d\n", j);

	  mask <<= 1;
	  if (mask == 0)
	    {
	      cword = *rp++;
	      mask = 1;
	    }
	}
    }

  fflush(stdout);
}

#endif
SHAR_EOF
cat << \SHAR_EOF > new.h
/* Storage allocation interface for bison,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#define	NEW(t)		((t *) allocate((unsigned) sizeof(t)))
#define	NEW2(n, t)	((t *) allocate((unsigned) ((n) * sizeof(t))))

#ifdef	amiga
#define FREE(x)		bisonfree(x);
#else
#define	FREE(x)		{if(x) free((char *) (x));}
#endif


extern	char *allocate();
SHAR_EOF
cat << \SHAR_EOF > print.c
/* Print information on generated parser, for bison,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#include <stdio.h>
#include "machine.h"
#include "new.h"
#include "files.h"
#include "gram.h"
#include "state.h"


extern char **tags;
extern int nstates;
extern short *accessing_symbol;
extern core **state_table;
extern shifts **shift_table;
extern reductions **reduction_table;
extern char *consistent;
extern char any_conflicts;



terse()
{
  if (any_conflicts)
    {
      conflict_log();
    }
}



verbose()
{
  register int i;

  if (any_conflicts)
    verbose_conflict_log();

  for (i = 0; i < nstates; i++)
    {
      print_state(i);
    }
}



print_state(state)
int state;
{
  fprintf(foutput, "\n\nstate %d\n\n", state);
  print_core(state);
  print_actions(state);
}



print_core(state)
int state;
{
  register int i;
  register int k;
  register int rule;
  register core *statep;
  register short *sp;
  register short *sp1;

  statep = state_table[state];
  k = statep->nitems;

  if (k == 0) return;

  for (i = 0; i < k; i++)
    {
      sp1 = sp = ritem + statep->items[i];

      while (*sp > 0)
	sp++;

      rule = -(*sp);
      fprintf(foutput, "    %s  ->  ", tags[rlhs[rule]]);

      for (sp = ritem + rrhs[rule]; sp < sp1; sp++)
	{
	  fprintf(foutput, "%s ", tags[*sp]);
	}

      putc('.', foutput);

      while (*sp > 0)
	{
	  fprintf(foutput, " %s", tags[*sp]);
	  sp++;
	}

      putc('\n', foutput);
    }

  putc('\n', foutput);
}



print_actions(state)
int state;
{
  register int i;
  register int k;
  register int state1;
  register int symbol;
  register shifts *shiftp;
  register reductions *redp;
  register int rule;

  shiftp = shift_table[state];
  redp = reduction_table[state];

  if (!shiftp && !redp)
    {
      fprintf(foutput, "    NO ACTIONS\n");
      return;
    }

  if (shiftp)
    {
      k = shiftp->nshifts;

      for (i = 0; i < k; i++)
	{
	  if (! shiftp->shifts[i]) continue;
	  state1 = shiftp->shifts[i];
	  symbol = accessing_symbol[state1];
	  if (ISVAR(symbol)) break;
	  fprintf(foutput, "    %-4s\tshift  %d\n", tags[symbol], state1);
	}

      if (i > 0)
	putc('\n', foutput);
    }
  else
    {
      i = 0;
      k = 0;
    }

  if (consistent[state] && redp)
    {
      rule = redp->rules[0];
      symbol = rlhs[rule];
      fprintf(foutput, "    $default\treduce  %d  (%s)\n\n",
     	        rule, tags[symbol]);
    }
  else if (redp)
    {
      print_reductions(state);
    }

  if (i < k)
    {
      for (; i < k; i++)
	{
	  if (! shiftp->shifts[i]) continue;
	  state1 = shiftp->shifts[i];
	  symbol = accessing_symbol[state1];
	  fprintf(foutput, "    %-4s\tgoto  %d\n", tags[symbol], state1);
	}

      putc('\n', foutput);
    }
}
SHAR_EOF
cat << \SHAR_EOF > string.h
extern char *strcat();
extern char *strncat();
extern char *strcpy();
extern char *strncpy();
extern char *stpcpy();
extern char *stpblk();
extern char *stpsym();
extern char *stptok();
extern char *stpchr();
extern char *strchr();
extern char *strrchr();
extern char *stpbrk();
extern char *strpbrk();

extern int	 strcmp();
extern int   strncmp();
extern int   strlen();
SHAR_EOF
cat << \SHAR_EOF > symtab.c
/* Symbol table manager for Bison,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#include <stdio.h>
#ifdef BSD
#include <strings.h>
#else
#include <string.h>
#endif
#include "new.h"
#include "symtab.h"
#include "gram.h"


bucket **symtab;
bucket *firstsymbol;
bucket *lastsymbol;



int
hash(key)
char *key;
{
  register char *cp;
  register int k;

  cp = key;
  k = 0;
  while (*cp)
    k = ((k << 1) ^ (*cp++)) & 0x3fff;

  return (k % TABSIZE);
}



char *
copys(s)
char *s;
{
  register int i;
  register char *cp;
  register char *result;

  i = 1;
  for (cp = s; *cp; cp++)
    i++;

  result =  allocate(i);
  strcpy(result, s);
  return (result);
}



tabinit()
{
  symtab = NEW2(TABSIZE, bucket *);

  firstsymbol = NULL;
  lastsymbol = NULL;
}




bucket *getsym(key)
char *key;
{
  register int hashval;
  register bucket *bp;
  register int found;

  hashval = hash(key);
  bp = symtab[hashval];

  found = 0;
  while (bp != NULL && found == 0)
    {
      if (strcmp(key, bp->tag) == 0)
	found = 1;
      else
	bp = bp->link;
    }

  if (found == 0)
    {
      nsyms++;

      bp = NEW(bucket);
      bp->link = symtab[hashval];
      bp->next = NULL;
      bp->tag = copys(key);
      bp->class = SUNKNOWN;

      if (firstsymbol == NULL)
	{
	  firstsymbol = bp;
	  lastsymbol = bp;
	}
      else
	{
	  lastsymbol->next = bp;
	  lastsymbol = bp;
	}

      symtab[hashval] = bp;
    }

  return (bp);
}



free_symtab()
{
  register int i;
  register bucket *bp, *bptrail;

  for (i = 0; i < TABSIZE; i++)
    {
      bp = symtab[i];
      while (bp)
	{
	  bptrail = bp;
	  bp = bp->link;
	  FREE(bptrail);
	}
    }
}
SHAR_EOF
cat << \SHAR_EOF > warshall.c
/* Generate transitive closure of a matrix,
   copyright (C) 1984 Bob Corbett and Richard Stallman

   Permission is granted to anyone to make or distribute verbatim copies of this program
   provided that the copyright notice and this permission notice are preserved;
   and provided that the recipient is not asked to waive or limit his right to
   redistribute copies as permitted by this permission notice;
   and provided that anyone possessing an executable copy
   is granted access to copy the source code, in machine-readable form,
   in some reasonable manner.

   Permission is granted to distribute derived works or enhanced versions of
   this program under the above conditions with the additional condition
   that the entire derivative or enhanced work
   must be covered by a permission notice identical to this one.

   Anything distributed as part of a package containing portions derived
   from this program, which cannot in current practice perform its function usefully
   in the absense of what was derived directly from this program,
   is to be considered as forming, together with the latter,
   a single work derived from this program,
   which must be entirely covered by a permission notice identical to this one
   in order for distribution of the package to be permitted.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#include <stdio.h>
#include "machine.h"


/* given n by n matrix of bits R, modify its contents
   to be the transive closure of what was given.  */

  void
TC(R, n)
  unsigned *R;
  int n;
{
  register int rowsize;
  register unsigned mask;
  register unsigned *rowj;
  register unsigned *rp;
  register unsigned *rend;
  register unsigned *ccol;

  unsigned *relend;
  unsigned *cword;
  unsigned *rowi;

  rowsize = WORDSIZE(n) * sizeof(unsigned);
  relend = (unsigned *) ((unsigned) R + n*rowsize);

  cword = R;
  mask = 1;
  rowi = R;
  while (rowi < relend)
    {
      ccol = cword;
      rowj = R;

      while (rowj < relend)
	{
	  if (*ccol & mask)
	    {
	      rp = rowi;
	      rend = (unsigned *) ((unsigned) rowj + rowsize);

	      while (rowj < rend)
		*rowj++ |= *rp++;
	    }
	  else
	    {
	      rowj = (unsigned *) ((unsigned) rowj + rowsize);
	    }

	  ccol = (unsigned *) ((unsigned) ccol + rowsize);
	}

      mask <<= 1;
      if (mask == 0)
	{
	  mask = 1;
	  cword++;
	}

      rowi = (unsigned *) ((unsigned) rowi + rowsize);
    }
}


/* Reflexive Transitive Closure.  Same as TC
   and then set all the bits on the diagonal of R.  */

  void
RTC(R, n)
  unsigned *R;
  int n;
{
  register int rowsize;
  register unsigned mask;
  register unsigned *rp;
  register unsigned *relend;

  TC(R, n);

  rowsize = WORDSIZE(n) * sizeof(unsigned);
  relend = (unsigned *) ((unsigned) R + n*rowsize);

  mask = 1;
  rp = R;
  while (rp < relend)
    {
      *rp |= mask;

      mask <<= 1;
      if (mask == 0)
	{
	  mask = 1;
	  rp++;
	}

      rp = (unsigned *) ((unsigned) rp + rowsize);
    }
}
SHAR_EOF