219 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  *  L L G E N
 | |
|  *
 | |
|  *  An Extended LL(1) Parser Generator
 | |
|  *
 | |
|  *  Author : Ceriel J.H. Jacobs
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * sets.c
 | |
|  * Set manipulation and allocation routines.
 | |
|  */
 | |
| 
 | |
| # include "types.h"
 | |
| # include "extern.h"
 | |
| # include "sets.h"
 | |
| # include "assert.h"
 | |
| 
 | |
| # ifndef NORCSID
 | |
| static string rcsid9 = "$Header$";
 | |
| # endif
 | |
| 
 | |
| /* In this file the following routines are defined: */
 | |
| extern		setinit();
 | |
| extern p_set	setalloc();
 | |
| extern p_set	get_set();
 | |
| extern int	setunion();
 | |
| extern int	setintersect();
 | |
| extern 		setminus();
 | |
| extern int	setempty();
 | |
| extern int	findindex();
 | |
| extern int	setcount();
 | |
| 
 | |
| int		nbytes;
 | |
| static int	setsize;
 | |
| int		tsetsize;
 | |
| p_set		*setptr, *maxptr;
 | |
| static t_info	set_info;
 | |
| p_mem		alloc();
 | |
| 
 | |
| setinit(ntneeded) {
 | |
| 	/*
 | |
| 	 * Initialises some variables needed for setcomputations
 | |
| 	 */
 | |
| 	register int	 bitset;
 | |
| 
 | |
| 	nbytes = NBYTES(ntokens);
 | |
| 	bitset = ALIGN(nbytes);
 | |
| 	tsetsize = NINTS(bitset);
 | |
| 	if (ntneeded) {
 | |
| 		/* nonterminals must be included in the sets */
 | |
| 		bitset += NBYTES(nnonterms);
 | |
| 	}
 | |
| 	setsize = NINTS(bitset);
 | |
| 	set_info.i_esize = sizeof(p_set);
 | |
| 	set_info.i_incr = 20;
 | |
| }
 | |
| 
 | |
| p_set
 | |
| get_set() {
 | |
| 	/*
 | |
| 	 * Allocate a set that cannot be freed
 | |
| 	 */
 | |
| 	register p_set p, q;
 | |
| 	static p_set sets, maxsets;
 | |
| 
 | |
| 	if ((p = sets) >= maxsets) {
 | |
| 		q = p = (p_set) alloc((unsigned) (50*setsize*sizeof(*sets)));
 | |
| 		maxsets = p + 50 * setsize;
 | |
| 		do {
 | |
| 			*q++ = 0;
 | |
| 		} while (q < maxsets);
 | |
| 	}
 | |
| 	sets = p + setsize;;
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| p_set
 | |
| setalloc() {
 | |
| 	/*
 | |
| 	 * Allocate a set which can later be freed.
 | |
| 	 */
 | |
| 	register p_set	p;
 | |
| 	register int	size = setsize;
 | |
| 
 | |
| 	p = (p_set) alloc((unsigned) (size * sizeof(*p))) + size;
 | |
| 	do {
 | |
| 		*--p = 0;
 | |
| 	} while (--size);
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| int
 | |
| setunion(a,b) register p_set a,b; {
 | |
| 	/*
 | |
| 	 * a = a union b.
 | |
| 	 * Return 1 if the set a changed
 | |
| 	 */
 | |
| 	register int	i;
 | |
| 	register int	j;
 | |
| 	register int	nsub = 0;
 | |
| 
 | |
| 	i = setsize;
 | |
| 	do {
 | |
| 		*a = (j = *a) | *b++;
 | |
| 		if (*a++ != j) {
 | |
| 			nsub = 1;
 | |
| 		}
 | |
| 	} while (--i);
 | |
| 	return nsub;
 | |
| }
 | |
| 
 | |
| int
 | |
| setintersect(a,b) register p_set a,b; {
 | |
| 	/*
 | |
| 	 * a = a intersect b.
 | |
| 	 * return 1 if the result is empty
 | |
| 	 */
 | |
| 	register int	i;
 | |
| 	register int	nempty;
 | |
| 
 | |
| 	nempty = 1;
 | |
| 	i =  setsize;
 | |
| 	do {
 | |
| 		if (*a++ &= *b++) nempty = 0;
 | |
| 	} while (--i);
 | |
| 	return nempty;
 | |
| }
 | |
| 
 | |
| setminus(a,b) register p_set a,b; {
 | |
| 	/*
 | |
| 	 * a = a setminus b
 | |
| 	 */
 | |
| 	register int	i;
 | |
| 
 | |
| 	i = setsize;
 | |
| 	do {
 | |
| 		*a++ &= ~(*b++);
 | |
| 	} while (--i);
 | |
| }
 | |
| 
 | |
| int
 | |
| setempty(p) register p_set p; {
 | |
| 	/*
 | |
| 	 * Return 1 if the set p is empty
 | |
| 	 */
 | |
| 	register int	i;
 | |
| 
 | |
| 	i = tsetsize;
 | |
| 	do {
 | |
| 		if (*p++) return 0;
 | |
| 	} while (--i);
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| findindex(set) p_set set; {
 | |
| 	/*
 | |
| 	 * The set "set" will serve as a recovery set.
 | |
| 	 * Search for it in the table. If not present, enter it.
 | |
| 	 * Here is room for improvement. At the moment, the list of
 | |
| 	 * sets is examined with linear search.
 | |
| 	 */
 | |
| 	register p_set	*t;
 | |
| 	p_mem		new_mem();
 | |
| 	register p_set	a;
 | |
| 	register p_set	b;
 | |
| 	register int	i;
 | |
| 	int		saved;
 | |
| 
 | |
| 	/*
 | |
| 	 * First search for the set in the table
 | |
| 	 */
 | |
| 	for (t = setptr; t < maxptr; t++) {
 | |
| 		a = *t;
 | |
| 		b = set;
 | |
| 		i = tsetsize;
 | |
| 		do {
 | |
| 			if (*a++ != *b++) break;
 | |
| 		} while (--i);
 | |
| 		if (i) continue;
 | |
| 		/*
 | |
| 		 * Here, the sets are equal.
 | |
| 		 */
 | |
| 		return nbytes * (t - setptr);
 | |
| 	}
 | |
| 	/*
 | |
| 	 * Now check if the set consists of only one element.
 | |
| 	 * It would be a waste to use a set for that
 | |
| 	 */
 | |
| 	if (setcount(set, &saved) == 1) return -(saved + 1);
 | |
| 	/*
 | |
| 	 * If it does, return its number as a negative number.
 | |
| 	 */
 | |
| 	maxptr = (p_set *) new_mem(&set_info);
 | |
| 	setptr = (p_set *) set_info.i_ptr;
 | |
| 	*maxptr = setalloc();
 | |
| 	setunion(*maxptr, set);
 | |
| 	return nbytes * (maxptr++ - setptr);
 | |
| }
 | |
| 
 | |
| int
 | |
| setcount(set, saved) register p_set set; int *saved; {
 | |
| 	register int i, j;
 | |
| 
 | |
| 	for (j = 0, i = 0; i < ntokens; i++) {
 | |
| 		if (IN(set,i)) {
 | |
| 			j++;
 | |
| 			*saved = i;
 | |
| 		}
 | |
| 	}
 | |
| 	return j;
 | |
| }
 |