1790 lines
		
	
	
	
		
			39 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			1790 lines
		
	
	
	
		
			39 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
/*
 | 
						|
	compile with -DNOFIRST to disable firstset optimization
 | 
						|
		-DFOLLOW_OPT to enable followset optimization
 | 
						|
		NOTE: Followset optimization is not
 | 
						|
			supported when using -s option of LLgen
 | 
						|
		-DDEBUG to print debug information
 | 
						|
*/
 | 
						|
 | 
						|
extern int	LLsymb;
 | 
						|
extern int	LLstartsymb;
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
void		LLmessage(int);
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
struct stacks {
 | 
						|
 | 
						|
	/* Acces to the stacks is through a 'dynamic array' of pointers
 | 
						|
	 * to the heads. We implemented it this way to save on the number
 | 
						|
	 * of Malloc() calls. nr_heads is the number of heads; heads_buf_size
 | 
						|
	 * is the current size of heads_buf.
 | 
						|
	 */
 | 
						|
 | 
						|
	int nr_heads;
 | 
						|
	struct stack_elt **heads_buf;
 | 
						|
	int heads_buf_size;
 | 
						|
 | 
						|
	/* r_rec contains nonterminals already tried to build a new
 | 
						|
	 * stack with, to prevent right-recursive rules making the
 | 
						|
	 * process loop forever
 | 
						|
	 */
 | 
						|
 | 
						|
	char r_rec[(LLNNONTERMINALS + 7)/8];
 | 
						|
 | 
						|
	/* join_array contains pointers to already substituted stack
 | 
						|
	 * elements, so that if the same nonterminal turns up again
 | 
						|
	 * we can make a link
 | 
						|
	 */
 | 
						|
 | 
						|
	struct stack_elt *join_array[LLNNONTERMINALS];
 | 
						|
 | 
						|
	/* cleanup_buf contains pointerts to elements that can possibly
 | 
						|
	 * be deleted. Again this is implemented as a `growing array'.
 | 
						|
	 * Although it's not so clean to do it this way, it DOES save
 | 
						|
	 * a lot of time, mainly because much less pointer manipulation
 | 
						|
	 * is required, and because it's not necessary to deallocate
 | 
						|
	 * the buffer after each turn. Just set nr_cleanups to 0...
 | 
						|
	 */
 | 
						|
 | 
						|
	int nr_cleanups;
 | 
						|
	int cleanup_buf_size;
 | 
						|
	struct stack_elt **cleanup_buf;
 | 
						|
 | 
						|
	/* visited_buf contains pointers to elements whose flags
 | 
						|
	 * need to be cleared
 | 
						|
	 */
 | 
						|
 | 
						|
	int nr_visited;
 | 
						|
	int visited_buf_size;
 | 
						|
	struct stack_elt **visited_buf;
 | 
						|
 | 
						|
 | 
						|
	/* start_seen indicates if the last prediction phase
 | 
						|
	 * has matched the start symbol
 | 
						|
	 */
 | 
						|
 | 
						|
	int start_seen;
 | 
						|
 | 
						|
	/* exp_terminals will contain the terminals that are `on top'
 | 
						|
	 * of the prediction graph after a prediction phase
 | 
						|
	 */
 | 
						|
 | 
						|
	char exp_terminals[LLSETSIZE];
 | 
						|
 | 
						|
	/* check_run_ok indicates whether a stack element can be deleted
 | 
						|
	 * or not
 | 
						|
	*/
 | 
						|
 | 
						|
	int check_run_ok;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
static int allocates = 0;
 | 
						|
static int deallocates = 0;
 | 
						|
static int max_in_use = 0;
 | 
						|
static int edge_allocates = 0;
 | 
						|
static int edge_deallocates = 0;
 | 
						|
static int edge_max_in_use = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
static int grammar_index = 0;
 | 
						|
 | 
						|
/* The grammar should only be build the first time we enter the
 | 
						|
 * recovery routine. grammar_read == 0 indicates this has not
 | 
						|
 * been done yet
 | 
						|
 */
 | 
						|
 | 
						|
static int grammar_read = 0;
 | 
						|
 | 
						|
/* 'terminals' is an array indexed by the number of a terminal and links
 | 
						|
 * all rules containing this terminal in the RHS
 | 
						|
 */
 | 
						|
 | 
						|
static struct terminal *terminals;
 | 
						|
 | 
						|
/* 'nonterminals' is an array indexed by the number of a nonterminal
 | 
						|
 * and contains all rules with this nonterminal in the LHS and links all
 | 
						|
 * rules containing this nonterminal in the RHS
 | 
						|
 */
 | 
						|
 | 
						|
static struct nonterminal *nonterminals;
 | 
						|
 | 
						|
 | 
						|
/* These functions must be called instead of the original functions in
 | 
						|
 * 'malloc.h'. They offer a checking allocation mechanism.
 | 
						|
*/
 | 
						|
#if LL_ANSI_C
 | 
						|
static char *Malloc(unsigned);
 | 
						|
static char *Realloc(char*, unsigned);
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
static char *Malloc();
 | 
						|
static char *Realloc();
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* These functions build the grammar */
 | 
						|
#if LL_ANSI_C
 | 
						|
static void init_grammar(void);
 | 
						|
static void build_grammar(void);
 | 
						|
static struct lhs *build_rule(void);
 | 
						|
static struct symbol *build_rhs(struct lhs*);
 | 
						|
static struct symbol *make_link(struct symbol*);
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
static init_grammar();
 | 
						|
static build_grammar();
 | 
						|
static struct lhs *build_rule();
 | 
						|
static struct symbol *build_rhs();
 | 
						|
static struct symbol *make_link();
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* These functions operate on the stacks */
 | 
						|
#if LL_ANSI_C
 | 
						|
static int optimize(struct stacks*, struct symbol*, int);
 | 
						|
static void read_token(void);
 | 
						|
static void start_stack(struct stacks*, int, int);
 | 
						|
static void continuation(struct stacks*, int, int);
 | 
						|
static struct stack_elt *push_rule(struct stack_elt*, struct symbol*);
 | 
						|
static void new_head(struct stacks*, struct stack_elt*);
 | 
						|
static void to_delete(struct stacks*, struct stack_elt*);
 | 
						|
static void substitute(struct stacks*, struct stack_elt*, int);
 | 
						|
static int join(struct stacks*, struct stack_elt*, int);
 | 
						|
static int path(struct stack_elt*, struct stack_elt*);
 | 
						|
static int part_of_loop(struct stack_elt*);
 | 
						|
static void generate_heads(struct stacks*, struct stack_elt*, int);
 | 
						|
static void delete(struct stacks*, struct stack_elt*);
 | 
						|
static void hyp_run(struct stack_elt*);
 | 
						|
static void check_run(struct stacks*, struct stack_elt*);
 | 
						|
static struct stack_elt *split(struct stack_elt*);
 | 
						|
#ifdef DEBUG
 | 
						|
static void test(struct stacks*);
 | 
						|
static void dump_stack(struct stack_elt*, int);
 | 
						|
#endif
 | 
						|
static void clear_flags(struct stack_elt*, char);
 | 
						|
static void clear_gen_flags(struct stacks*);
 | 
						|
static void match_heads(struct stacks*, int);
 | 
						|
static void cleanup(struct stacks*);
 | 
						|
static void initialize(struct stacks*);
 | 
						|
static void calculate(struct stacks*, int);
 | 
						|
static void kill_stack(struct stacks *stack);
 | 
						|
void LLnc_recover(void);
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
static int optimize();
 | 
						|
static read_token();
 | 
						|
static start_stack();
 | 
						|
static continuation();
 | 
						|
static struct stack_elt *push_rule();
 | 
						|
static new_head();
 | 
						|
static to_delete();
 | 
						|
static substitute();
 | 
						|
static int join();
 | 
						|
static int path();
 | 
						|
static int part_of_loop();
 | 
						|
static generate_heads();
 | 
						|
static delete();
 | 
						|
static hyp_run();
 | 
						|
static check_run();
 | 
						|
static struct stack_elt *split();
 | 
						|
static test();
 | 
						|
static dump_stack();
 | 
						|
static clear_flags();
 | 
						|
static clear_gen_flags();
 | 
						|
static match_heads();
 | 
						|
static cleanup();
 | 
						|
static initialize();
 | 
						|
static calculate();
 | 
						|
static kill_stack();
 | 
						|
LLnc_recover();
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static char *Malloc(unsigned size)
 | 
						|
#else
 | 
						|
static char *Malloc(size)
 | 
						|
unsigned size;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	char *p;
 | 
						|
 | 
						|
	if ((p = malloc(size)) == (char *)0) {
 | 
						|
		fprintf(stderr, "fatal error: out of memory\n");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static char *Realloc(char *ptr, unsigned size)
 | 
						|
#else
 | 
						|
static char *Realloc(ptr, size)
 | 
						|
char *ptr;
 | 
						|
unsigned size;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	char *p;
 | 
						|
 | 
						|
	if ((p = realloc(ptr, size)) == (char *)0) {
 | 
						|
		fprintf(stderr, "fatal error: out of memory\n");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void init_grammar(void)
 | 
						|
#else
 | 
						|
static init_grammar()
 | 
						|
#endif
 | 
						|
{
 | 
						|
/* Allocate and initialize an array for terminals and nonterminals */
 | 
						|
 | 
						|
	int i;
 | 
						|
 | 
						|
	terminals = (struct terminal *)
 | 
						|
		Malloc((unsigned) LLFIRST_NT * sizeof(struct terminal));
 | 
						|
	for (i = 0; i < LLFIRST_NT; i++) {
 | 
						|
		(terminals + i)->link = (struct symbol *)0;
 | 
						|
	}
 | 
						|
 | 
						|
	nonterminals = (struct nonterminal *)
 | 
						|
		Malloc((unsigned)LLNNONTERMINALS * sizeof(struct nonterminal));
 | 
						|
	for (i = 0; i < LLNNONTERMINALS; i++) {
 | 
						|
		(nonterminals + i)->rule = (struct lhs *)0;
 | 
						|
		(nonterminals + i)->link = (struct symbol *)0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void build_grammar(void)
 | 
						|
#else
 | 
						|
static build_grammar()
 | 
						|
#endif
 | 
						|
{
 | 
						|
/* Build a rule for every nonterminal. The LHS must be saved first because
 | 
						|
 * of the fact that the right side of an assignment statement (in C) will
 | 
						|
 * be evaluated before the left side
 | 
						|
 */
 | 
						|
	int nt, j;
 | 
						|
 | 
						|
	init_grammar();
 | 
						|
	for (j = 0; j < LLNNONTERMINALS; j++) {
 | 
						|
		nt = LLgrammar[grammar_index];
 | 
						|
		(nonterminals + nt - LLFIRST_NT)->rule = build_rule();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static struct lhs *build_rule(void)
 | 
						|
#else
 | 
						|
static struct lhs *build_rule()
 | 
						|
#endif
 | 
						|
{
 | 
						|
/* Build LHS and call a funcion to create RHS */
 | 
						|
 | 
						|
	struct lhs *l;
 | 
						|
	int j;
 | 
						|
 | 
						|
	l = (struct lhs *)Malloc(sizeof(struct lhs));
 | 
						|
	l->nr = LLgrammar[grammar_index++];
 | 
						|
 | 
						|
	/* Build first set */
 | 
						|
	for (j = 0; j < LLSETSIZE; j++)	{
 | 
						|
		l->first[j] = LLgrammar[grammar_index++];
 | 
						|
	}
 | 
						|
 | 
						|
	/* Build follow set */
 | 
						|
	for (j = 0; j < LLSETSIZE; j++)	{
 | 
						|
		l->follow[j] = LLgrammar[grammar_index++];
 | 
						|
	}
 | 
						|
 | 
						|
	l->empty = LLgrammar[grammar_index++];	/* Can NT produce empty? */
 | 
						|
 | 
						|
	l->rhs = build_rhs(l);
 | 
						|
 | 
						|
	return l;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static struct symbol *build_rhs(struct lhs *l)
 | 
						|
#else
 | 
						|
static struct symbol *build_rhs(l)
 | 
						|
struct lhs *l;
 | 
						|
#endif
 | 
						|
{
 | 
						|
/* Build RHS by creating structs for all symbols including ALT and
 | 
						|
 * EORULE. Also call a function for linking same terminals and
 | 
						|
 * nonterminals.
 | 
						|
 */
 | 
						|
 | 
						|
	struct symbol *r;
 | 
						|
 | 
						|
	r = (struct symbol *)Malloc(sizeof(struct symbol));
 | 
						|
	if (LLgrammar[grammar_index] == LLALT) {
 | 
						|
		grammar_index++;
 | 
						|
		r->x = LLALT;
 | 
						|
		r->nr = -1;			/* Not applicable */
 | 
						|
		r->link = (struct symbol *)0;	/* Not applicable */
 | 
						|
		r->next = build_rhs(l);
 | 
						|
		r->lhs = l;
 | 
						|
	}
 | 
						|
	else if (LLgrammar[grammar_index] == LLEORULE) {
 | 
						|
		grammar_index++;
 | 
						|
		r->x = LLEORULE;
 | 
						|
		r->nr = -1;			/* Not applicable */
 | 
						|
		r->link = (struct symbol *)0;	/* Not applicable */
 | 
						|
		r->next = (struct symbol *)0;	/* Not applicable */
 | 
						|
		r->lhs = l;
 | 
						|
	}
 | 
						|
	else if (LLgrammar[grammar_index] < LLFIRST_NT) {
 | 
						|
		r->x = LLTERMINAL;
 | 
						|
		r->nr = LLgrammar[grammar_index++];
 | 
						|
		r->link = make_link(r);
 | 
						|
		r->next = build_rhs(l);
 | 
						|
		r->lhs = l;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		r->x = LLNONTERMINAL;
 | 
						|
		r->nr = LLgrammar[grammar_index++];
 | 
						|
		r->link = make_link(r);
 | 
						|
		r->next = build_rhs(l);
 | 
						|
		r->lhs = l;
 | 
						|
	}
 | 
						|
	return r;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static struct symbol *make_link(struct symbol *r)
 | 
						|
#else
 | 
						|
static struct symbol *make_link(r)
 | 
						|
struct symbol *r;
 | 
						|
#endif
 | 
						|
{
 | 
						|
/* Link same terminals and nonterminals. Every new symbol is appended
 | 
						|
 * in front of the corresponding list for efficiency.
 | 
						|
 */
 | 
						|
 | 
						|
	struct symbol *tmp;
 | 
						|
 | 
						|
	if (r->nr < LLFIRST_NT) {
 | 
						|
		/* Terminal array */
 | 
						|
		tmp = (terminals + r->nr)->link;
 | 
						|
		(terminals + r->nr)->link = r;
 | 
						|
	}
 | 
						|
	else {					/* Nonterminal array */
 | 
						|
		tmp = (nonterminals + (r->nr - LLFIRST_NT))->link;
 | 
						|
		(nonterminals + (r->nr - LLFIRST_NT))->link = r;
 | 
						|
	}
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static int optimize(struct stacks* stack, struct symbol *symb_ptr, int l_ahead)
 | 
						|
#else
 | 
						|
static int optimize(stack, symb_ptr, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
struct symbol *symb_ptr;
 | 
						|
int l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Return 1 if rule symb_ptr can start with terminal l_ahead, else return 0.
 | 
						|
 * The array with expected terminals will also be filled in.
 | 
						|
 */
 | 
						|
{
 | 
						|
	struct lhs *l;
 | 
						|
	int i;
 | 
						|
 | 
						|
#ifdef NOFIRST
 | 
						|
	return(1);
 | 
						|
#else
 | 
						|
 | 
						|
	if ((l_ahead <= 0) || (l_ahead == EOFILE)) return 1;
 | 
						|
 | 
						|
	switch(symb_ptr->x) {
 | 
						|
	case LLTERMINAL:
 | 
						|
		LLPUTIN(stack->exp_terminals, LLindex[symb_ptr->nr]);
 | 
						|
		if (symb_ptr->nr != l_ahead) return 0;
 | 
						|
		else return 1;/*???*/
 | 
						|
 | 
						|
 	case LLNONTERMINAL:
 | 
						|
		l = (nonterminals + symb_ptr->nr - LLFIRST_NT)->rule;
 | 
						|
		if (LLIN(l->first, LLindex[l_ahead])) return 1;
 | 
						|
		else if (l->empty) {
 | 
						|
		 	/* Try next symbol */
 | 
						|
			return optimize(stack, symb_ptr->next, l_ahead);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			for (i = 0; i < LLSETSIZE; i++) {
 | 
						|
				stack->exp_terminals[i] |= (l->first)[i];
 | 
						|
			}
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
	default:
 | 
						|
 | 
						|
#ifndef FOLLOW_OPT
 | 
						|
		return(1);
 | 
						|
#else
 | 
						|
 | 
						|
		l = (nonterminals + symb_ptr->lhs->nr - LLFIRST_NT)->rule;
 | 
						|
 | 
						|
		if (LLIN(l->follow, LLindex[l_ahead])) return 1;
 | 
						|
		else {
 | 
						|
			for (i = 0; i < LLSETSIZE; i++) {
 | 
						|
				stack->exp_terminals[i] |= (l->follow)[i];
 | 
						|
			}
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
#endif /*FOLLOW_OPT */
 | 
						|
	}
 | 
						|
#endif /* NOFIRST */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void read_token(void)
 | 
						|
#else
 | 
						|
static read_token()
 | 
						|
#endif
 | 
						|
 | 
						|
/* Read token and put it in global variable LLsymb, skipping
 | 
						|
 * invalid tokens
 | 
						|
 */
 | 
						|
{
 | 
						|
	LLsymb = LL_LEXI();
 | 
						|
	while (LLindex[LLsymb] < 0) {
 | 
						|
		/* Skip garbage tokens */
 | 
						|
		LLmessage(0);
 | 
						|
		LLsymb = LL_LEXI();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void start_stack(struct stacks *stack, int base, int l_ahead)
 | 
						|
#else
 | 
						|
static start_stack(stack, base, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
int base, l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Start stack on base symbol base with lookahead l_ahead */
 | 
						|
 | 
						|
{
 | 
						|
	struct stack_elt *bottom, *top;
 | 
						|
	struct symbol *symb_ptr;
 | 
						|
	int i;
 | 
						|
 | 
						|
	/* Find first applicable rule */
 | 
						|
	symb_ptr = (terminals + base)->link;
 | 
						|
 | 
						|
	/* Now try all applicable rules */
 | 
						|
	while (symb_ptr != (struct symbol *)0) {
 | 
						|
 | 
						|
		/* If the current rule cannot start with l_ahead,
 | 
						|
		 * try the next one
 | 
						|
		 */
 | 
						|
		if (!optimize(stack, symb_ptr->next, l_ahead)) {
 | 
						|
			symb_ptr = symb_ptr->link;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (	(symb_ptr->next->x == LLTERMINAL)
 | 
						|
		||	(symb_ptr->next->x == LLNONTERMINAL)
 | 
						|
		) {
 | 
						|
			/* Allocate an end-of-stack */
 | 
						|
#ifdef DEBUG
 | 
						|
			allocates++;
 | 
						|
			if (allocates - deallocates > max_in_use) {
 | 
						|
				max_in_use = allocates - deallocates;
 | 
						|
			}
 | 
						|
#endif
 | 
						|
			bottom = (struct stack_elt *)
 | 
						|
					Malloc(sizeof(struct stack_elt));
 | 
						|
			bottom->edges = (struct edge *)0;
 | 
						|
			bottom->nr = LLEOSTACK;
 | 
						|
			bottom->flags = 0;
 | 
						|
			bottom->nr_nexts = 0;
 | 
						|
			bottom->ref_count = 0;
 | 
						|
			bottom->hyp_ref_count = -1;
 | 
						|
 | 
						|
			/* And use the rule to build a stack on it */
 | 
						|
			top = push_rule(bottom, symb_ptr->next);
 | 
						|
 | 
						|
			/* Remember that we're now trying to match the LHS
 | 
						|
			 * of the used rule
 | 
						|
			 */
 | 
						|
			bottom->matched = symb_ptr->lhs->nr;
 | 
						|
 | 
						|
			if (top->nr >= LLFIRST_NT) {
 | 
						|
				substitute(stack, top, l_ahead);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				new_head(stack, top);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Perhaps this only has produced an empty stack, in
 | 
						|
			 * that case bottom can be deallocated.
 | 
						|
		 	 */
 | 
						|
			if (bottom->ref_count == 0) {
 | 
						|
				to_delete(stack, bottom);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			/* base was the last element of the rule, so we
 | 
						|
			 * figure we have matched the LHS of this rule.
 | 
						|
			 */
 | 
						|
			if (symb_ptr->lhs->nr == LLstartsymb) {
 | 
						|
				stack->start_seen = 1;
 | 
						|
			}
 | 
						|
 | 
						|
			continuation(stack, symb_ptr->lhs->nr, l_ahead);
 | 
						|
		}
 | 
						|
		symb_ptr = symb_ptr->link;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/* Reinitialize some arrays */
 | 
						|
	for (i = 0; i < (LLNNONTERMINALS + 7)/8; i++) {
 | 
						|
		stack->r_rec[i] = (char) 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < LLNNONTERMINALS; i++) {
 | 
						|
		stack->join_array[i] = (struct stack_elt *)0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Delete all HEAD flags */
 | 
						|
	for (i = 0; i < stack->nr_heads; i++) {
 | 
						|
		(*(stack->heads_buf + i))->flags &= ~LLHEAD;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Delete flags turned on by 'generate_heads()' */
 | 
						|
		clear_gen_flags(stack);
 | 
						|
	/* Try to delete elements on cleanup_buf */
 | 
						|
	cleanup(stack);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void continuation(struct stacks *stack, int nt, int l_ahead)
 | 
						|
#else
 | 
						|
static continuation(stack, nt, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
int nt, l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* We have 'eaten' a whole stack, and think we recognized nt. Now
 | 
						|
look for rules that we can proceed with, ie containing nt in the RHS.
 | 
						|
Each rule found will be developed untill a terminal is at the top
 | 
						|
of the stack.*/
 | 
						|
{
 | 
						|
 | 
						|
	struct symbol *symb_ptr;
 | 
						|
	struct stack_elt *bottom, *top;
 | 
						|
 | 
						|
	/* If we've already tried this nt, don't do it again.
 | 
						|
	 * Otherwise we may loop forever on right-recursive rules
 | 
						|
	 */
 | 
						|
	if (LLIN(stack->r_rec, nt - LLFIRST_NT)) return;
 | 
						|
 | 
						|
	/* Mark that we have looked for a continuation for nt */
 | 
						|
	LLPUTIN(stack->r_rec, nt - LLFIRST_NT);
 | 
						|
 | 
						|
	/* Find first applicable rule */
 | 
						|
	symb_ptr = (nonterminals + nt - LLFIRST_NT)->link;
 | 
						|
 | 
						|
	/* Try all applicable rules */
 | 
						|
	while (symb_ptr != (struct symbol *)0) {
 | 
						|
 | 
						|
		/* If the current rule cannot start with l_ahead,
 | 
						|
		 * try the next one
 | 
						|
		 */
 | 
						|
		if (!optimize(stack, symb_ptr->next, l_ahead)) {
 | 
						|
			symb_ptr = symb_ptr->link;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (	(symb_ptr->next->x == LLTERMINAL)
 | 
						|
		||	(symb_ptr->next->x == LLNONTERMINAL)
 | 
						|
		) {
 | 
						|
#ifdef DEBUG
 | 
						|
			allocates++;
 | 
						|
			if (allocates - deallocates > max_in_use) {
 | 
						|
					max_in_use = allocates - deallocates;
 | 
						|
				}
 | 
						|
#endif
 | 
						|
			bottom = (struct stack_elt *)
 | 
						|
					Malloc(sizeof(struct stack_elt));
 | 
						|
			bottom->edges = (struct edge *)0;
 | 
						|
			bottom->nr = LLEOSTACK;
 | 
						|
			bottom->flags = 0;
 | 
						|
			bottom->nr_nexts = 0;
 | 
						|
			bottom->ref_count = 0;
 | 
						|
			bottom->hyp_ref_count = -1;
 | 
						|
 | 
						|
			/* Use the rule to build a stack on bottom */
 | 
						|
			top = push_rule(bottom, symb_ptr->next);
 | 
						|
 | 
						|
			/* Remember that we're now trying to match the LHS
 | 
						|
			 * of the used rule
 | 
						|
			 */
 | 
						|
			bottom->matched = symb_ptr->lhs->nr;
 | 
						|
 | 
						|
			if (top->nr >= LLFIRST_NT) {
 | 
						|
				substitute(stack, top, l_ahead);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				new_head(stack, top);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Perhaps this only has produced an empty stack, in
 | 
						|
			 * that case bottom can be deallocated.
 | 
						|
		 	 */
 | 
						|
			if (bottom->ref_count == 0) {
 | 
						|
				delete(stack, bottom);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			/* Stack is still empty */
 | 
						|
			if (symb_ptr->lhs->nr == LLstartsymb) {
 | 
						|
				stack->start_seen = 1;
 | 
						|
			}
 | 
						|
 | 
						|
			continuation(stack, symb_ptr->lhs->nr, l_ahead);
 | 
						|
		}
 | 
						|
 | 
						|
		symb_ptr = symb_ptr->link;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static struct stack_elt *push_rule(struct stack_elt *element,
 | 
						|
					struct symbol *symb_ptr)
 | 
						|
#else
 | 
						|
static struct stack_elt *push_rule(element, symb_ptr)
 | 
						|
struct stack_elt *element;
 | 
						|
struct symbol *symb_ptr;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Append the rule symb_ptr to stack element 'element'. Return a
 | 
						|
 * pointer to the new top of the stack
 | 
						|
 */
 | 
						|
{
 | 
						|
	struct stack_elt *se, *top;
 | 
						|
 | 
						|
	if (	(symb_ptr->next->x == LLTERMINAL)
 | 
						|
	||	(symb_ptr->next->x == LLNONTERMINAL)
 | 
						|
	) {
 | 
						|
		top = push_rule(element, symb_ptr->next);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		top = element;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	allocates++;
 | 
						|
	if (allocates - deallocates > max_in_use) {
 | 
						|
		max_in_use = allocates - deallocates;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	se = (struct stack_elt *)Malloc(sizeof(struct stack_elt));
 | 
						|
	se->flags = 0;
 | 
						|
	se->nr = symb_ptr->nr;
 | 
						|
	se->ref_count = 0;
 | 
						|
	se->hyp_ref_count = -1;
 | 
						|
	se->matched = -1;
 | 
						|
	se->nr_nexts = 1;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	edge_allocates++;
 | 
						|
	if (edge_allocates - edge_deallocates > edge_max_in_use) {
 | 
						|
		edge_max_in_use = edge_allocates - edge_deallocates;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	se->edges = (struct edge *)Malloc(sizeof(struct edge));
 | 
						|
	se->edges->ptr = top;
 | 
						|
	se->edges->flags = 0;
 | 
						|
 | 
						|
	top->ref_count++;
 | 
						|
	return se;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void new_head(struct stacks *stack, struct stack_elt *ptr)
 | 
						|
#else
 | 
						|
static new_head(stack, ptr)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *ptr;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Make ptr a head of stack */
 | 
						|
{
 | 
						|
 | 
						|
	/* Is this already a head?*/
 | 
						|
	if (ptr->flags & LLHEAD) return;
 | 
						|
 | 
						|
	if (stack->heads_buf_size == 0) {
 | 
						|
		stack->heads_buf_size = LLHEADS_BUF_INCR;
 | 
						|
		stack->heads_buf = (struct stack_elt **)
 | 
						|
			Malloc(LLHEADS_BUF_INCR * sizeof(struct stack_elt *));
 | 
						|
	}
 | 
						|
	else if (stack->nr_heads == stack->heads_buf_size) {
 | 
						|
		/* buffer full? */
 | 
						|
		stack->heads_buf_size += LLHEADS_BUF_INCR;
 | 
						|
		stack->heads_buf = (struct stack_elt **)
 | 
						|
			Realloc((char *)
 | 
						|
				stack->heads_buf, (unsigned)
 | 
						|
				stack->heads_buf_size *
 | 
						|
					sizeof(struct stack_elt *)
 | 
						|
			);
 | 
						|
	}
 | 
						|
 | 
						|
	*(stack->heads_buf + stack->nr_heads) = ptr;	/* Add at the tail */
 | 
						|
	stack->nr_heads++;		/* Increase number of heads */
 | 
						|
	ptr->flags |= LLHEAD;		/* Mark it as a head */
 | 
						|
	ptr->ref_count++;		/* Increase reference count */
 | 
						|
	LLPUTIN(stack->exp_terminals, LLindex[ptr->nr]);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void to_delete(struct stacks *stack, struct stack_elt *ptr)
 | 
						|
#else
 | 
						|
static to_delete(stack, ptr)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *ptr;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Remember that ptr has to be deleted */
 | 
						|
{
 | 
						|
 | 
						|
	int i;
 | 
						|
 | 
						|
#ifdef NOCLEAN
 | 
						|
	return;
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	for (i = 0; i < stack->nr_cleanups; i++) {
 | 
						|
		/* Check if already in buffer */
 | 
						|
		if (*(stack->cleanup_buf + i) == ptr) return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (stack->cleanup_buf_size == 0) {
 | 
						|
		stack->cleanup_buf_size = LLCLEANUP_BUF_INCR;
 | 
						|
		stack->cleanup_buf = (struct stack_elt **)
 | 
						|
		Malloc(LLCLEANUP_BUF_INCR * sizeof(struct stack_elt *));
 | 
						|
	}
 | 
						|
	else if (stack->nr_cleanups == stack->cleanup_buf_size) {
 | 
						|
		stack->cleanup_buf_size += LLCLEANUP_BUF_INCR;
 | 
						|
		stack->cleanup_buf = (struct stack_elt **)
 | 
						|
			Realloc((char *) stack->cleanup_buf,
 | 
						|
				(unsigned) stack->cleanup_buf_size *
 | 
						|
				sizeof(struct stack_elt *));
 | 
						|
	}
 | 
						|
	*(stack->cleanup_buf + stack->nr_cleanups) = ptr;
 | 
						|
	stack->nr_cleanups++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void substitute(struct stacks *stack, struct stack_elt *top, int l_ahead)
 | 
						|
#else
 | 
						|
static substitute(stack, top, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *top;
 | 
						|
int l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function substitutes the NT pointed to by 'top'. 'top' should be a top
 | 
						|
 * of a stack
 | 
						|
 */
 | 
						|
{
 | 
						|
	struct symbol *symb_ptr;
 | 
						|
	struct stack_elt *new_top;
 | 
						|
 | 
						|
	/* Try to join top NT */
 | 
						|
	if (join(stack, top, l_ahead)) return;
 | 
						|
 | 
						|
	/* Find RHS of the rule of nonterminal 'top->nr' */
 | 
						|
	symb_ptr = (nonterminals + top->nr - LLFIRST_NT)->rule->rhs;
 | 
						|
 | 
						|
	/* Mark top as dummy */
 | 
						|
	top->flags |= LLDUMMY;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		/* If this an empty production, search down the stack for
 | 
						|
		 * terminals
 | 
						|
		 */
 | 
						|
		if ((symb_ptr->x == LLALT) || (symb_ptr->x == LLEORULE)) {
 | 
						|
			generate_heads(stack, top, l_ahead);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Skip other empty productions, they have no effect. */
 | 
						|
		while (symb_ptr->x == LLALT) {
 | 
						|
			symb_ptr = symb_ptr->next;
 | 
						|
		}
 | 
						|
 | 
						|
		if (symb_ptr->x == LLEORULE) {
 | 
						|
			/* If there are only empty productions, the NT on top
 | 
						|
			 * can be deleted
 | 
						|
			 */
 | 
						|
			if (top->ref_count == 0) {
 | 
						|
				to_delete(stack, top);
 | 
						|
			}
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		/* If this rule can produce 'l_ahead' on the top of the stack
 | 
						|
		 * substitute the nonterminal
 | 
						|
		 */
 | 
						|
		if (optimize(stack, symb_ptr, l_ahead)) {
 | 
						|
			new_top = push_rule(top, symb_ptr);
 | 
						|
 | 
						|
			/* If the new element on top is a nonterminal
 | 
						|
			 * substitute it, else make it a head
 | 
						|
			 */
 | 
						|
			if (new_top->nr >= LLFIRST_NT) {
 | 
						|
				substitute(stack, new_top, l_ahead);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				new_head(stack, new_top);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* Search to next alternative */
 | 
						|
		while (	(symb_ptr->x == LLTERMINAL)
 | 
						|
		||	(symb_ptr->x == LLNONTERMINAL)
 | 
						|
		) {
 | 
						|
			symb_ptr = symb_ptr->next;
 | 
						|
		}
 | 
						|
 | 
						|
		if (symb_ptr->x == LLEORULE) {
 | 
						|
			if (top->ref_count == 0) {
 | 
						|
				to_delete(stack, top);
 | 
						|
			}
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			symb_ptr = symb_ptr->next;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static int join(struct stacks *stack, struct stack_elt *top, int l_ahead)
 | 
						|
#else
 | 
						|
static int join(stack, top, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *top;
 | 
						|
int l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function tries to connect a NT on top of a stack with another stack,
 | 
						|
 * which has already substituted this NT
 | 
						|
 */
 | 
						|
{
 | 
						|
	struct stack_elt *se;
 | 
						|
	int size;
 | 
						|
 | 
						|
	if (	(se = stack->join_array[top->nr - LLFIRST_NT]) ==
 | 
						|
			(struct stack_elt *)0
 | 
						|
	) {
 | 
						|
		stack->join_array[top->nr - LLFIRST_NT] = top;
 | 
						|
		return 0;		/* Join not possible */
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		se->nr_nexts++;		/* Increase number of descendants */
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
		edge_allocates++;
 | 
						|
		if (edge_allocates - edge_deallocates > edge_max_in_use) {
 | 
						|
			edge_max_in_use = edge_allocates - edge_deallocates;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
 | 
						|
		/* Allocate one more pointer to descendants */
 | 
						|
		size = se->nr_nexts * sizeof(struct edge);
 | 
						|
		se->edges = (struct edge *)Realloc((char *) se->edges,
 | 
						|
							(unsigned) size);
 | 
						|
 | 
						|
		/* Link it */
 | 
						|
		(se->edges + se->nr_nexts - 1)->ptr = top->edges->ptr;
 | 
						|
		(se->edges + se->nr_nexts - 1)->flags = 0;
 | 
						|
 | 
						|
		/* The successor of 'top' gets an extra predecessor.
 | 
						|
		 * 'top' has always only one successor because the stacks are
 | 
						|
		 * constructed in 'depth first' order
 | 
						|
		 */
 | 
						|
		top->edges->ptr->ref_count++;
 | 
						|
 | 
						|
 | 
						|
#ifndef NOLOOPS
 | 
						|
		/* If we have made a new loop find all stack elements of this
 | 
						|
		 * loop and mark them
 | 
						|
		 */
 | 
						|
		if (path(top->edges->ptr, se)) {
 | 
						|
			(se->edges + se->nr_nexts - 1)->flags |= LLLOOP;
 | 
						|
			(se->edges + se->nr_nexts - 1)->flags |= LLYES;
 | 
						|
		}
 | 
						|
		clear_flags(top->edges->ptr, (LLNO | LLYES));
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
		/* Check if joined NT produces empty */
 | 
						|
		if ((nonterminals + se->nr - LLFIRST_NT)->rule->empty) {
 | 
						|
			generate_heads(stack, top, l_ahead);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Deallocate top symbol */
 | 
						|
		if (top->ref_count == 0) {
 | 
						|
			to_delete(stack, top);
 | 
						|
		}
 | 
						|
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifndef NOLOOPS
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static int path(struct stack_elt *se1, struct stack_elt *se2)
 | 
						|
#else
 | 
						|
static int path(se1, se2)
 | 
						|
struct stack_elt *se1, *se2;
 | 
						|
#endif /* LL_ANSI_C */
 | 
						|
 | 
						|
/* If there is a path from se1 to se2 it returns 1 and marks all the paths
 | 
						|
 * betweeen these two points, otherwise it returns 0. The flags LLYES and
 | 
						|
 * LLNO are used for optimization. */
 | 
						|
{
 | 
						|
	int i, result = 0;
 | 
						|
 | 
						|
	if (se1 == se2) return 1;
 | 
						|
 | 
						|
	for (i = 0; i < se1->nr_nexts; i++) {
 | 
						|
		if (	(!((se1->edges + i)->flags & LLNO))
 | 
						|
		&&	(!((se1->edges + i)->flags & LLLOOP_SEARCH))
 | 
						|
		) {
 | 
						|
			(se1->edges + i)->flags |= LLLOOP_SEARCH;
 | 
						|
 | 
						|
			if (path((se1->edges + i)->ptr, se2)) {
 | 
						|
				(se1->edges + i)->flags |= LLLOOP;
 | 
						|
				result = 1;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				(se1->edges + i)->flags |= LLNO;
 | 
						|
			}
 | 
						|
 | 
						|
			(se1->edges + i)->flags &= ~LLLOOP_SEARCH;
 | 
						|
		}
 | 
						|
		(se1->edges + i)->flags |= LLYES;
 | 
						|
	}
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static int part_of_loop(struct stack_elt *se)
 | 
						|
#else
 | 
						|
static int part_of_loop(se)
 | 
						|
struct stack_elt *se;
 | 
						|
#endif /* LL_ANSI_C */
 | 
						|
 | 
						|
/* Checks if 'se' belongs to a loop */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
		if ((se->edges + i)->flags & LLLOOP) return 1;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* NOLOOPS */
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void generate_heads(struct stacks *stack, struct stack_elt *se,
 | 
						|
				int l_ahead)
 | 
						|
#else
 | 
						|
static generate_heads(stack, se, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *se;
 | 
						|
int l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This funcion finds all heads starting at 'se'. */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	struct stack_elt *next_se;
 | 
						|
 | 
						|
 | 
						|
	for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
 | 
						|
		if (!((se->edges + i)->ptr->flags & LLGEN_SEARCH)) {
 | 
						|
 | 
						|
			(se->edges + i)->ptr->flags |= LLGEN_SEARCH;
 | 
						|
 | 
						|
			next_se = (se->edges + i)->ptr;
 | 
						|
 | 
						|
			/* Remember a flag has to be cleared later */
 | 
						|
 | 
						|
			if (stack->visited_buf_size == 0) {
 | 
						|
				stack->visited_buf_size = LL_VIS_INCR;
 | 
						|
				stack->visited_buf = (struct stack_elt **)
 | 
						|
				Malloc(LL_VIS_INCR * sizeof(struct stack_elt *));
 | 
						|
			}
 | 
						|
			else if (stack->nr_visited == stack->visited_buf_size) {
 | 
						|
				stack->visited_buf_size += LL_VIS_INCR;
 | 
						|
				stack->visited_buf = (struct stack_elt **)
 | 
						|
					Realloc((char *) stack->visited_buf,
 | 
						|
					(unsigned) stack->visited_buf_size *
 | 
						|
					sizeof(struct stack_elt *));
 | 
						|
			}
 | 
						|
			*(stack->visited_buf + stack->nr_visited) = next_se;
 | 
						|
			stack->nr_visited++;
 | 
						|
 | 
						|
			if (next_se->flags & LLDUMMY) {
 | 
						|
				generate_heads(stack, next_se, l_ahead);
 | 
						|
			}
 | 
						|
			else if (next_se->nr == LLEOSTACK) {
 | 
						|
				/* We have matched a nt */
 | 
						|
				if (next_se->matched == LLstartsymb) {
 | 
						|
					stack->start_seen = 1;
 | 
						|
				}
 | 
						|
 | 
						|
				continuation(stack, next_se->matched, l_ahead);
 | 
						|
				if (next_se->ref_count == 0) {
 | 
						|
					to_delete(stack, next_se);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else if (next_se->nr < LLFIRST_NT) {
 | 
						|
				/* terminal */
 | 
						|
				new_head(stack, next_se);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (next_se->ref_count > 0) {
 | 
						|
					next_se = split(next_se);
 | 
						|
				}
 | 
						|
				substitute(stack, next_se, l_ahead);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void delete(struct stacks *stack, struct stack_elt *se)
 | 
						|
#else
 | 
						|
static delete(stack, se)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *se;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function runs down the stack(s) deleting every element which cannot be
 | 
						|
 * reached anymore. */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
#ifdef NOCLEAN
 | 
						|
	return;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (se->ref_count == 0) {
 | 
						|
 | 
						|
		/* Decrease reference counts of all successors */
 | 
						|
		for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
			if ((se->edges + i)->ptr->ref_count != 0) {
 | 
						|
				(se->edges + i)->ptr->ref_count--;
 | 
						|
 | 
						|
				/* Try to delete next element */
 | 
						|
				delete(stack, (se->edges + i)->ptr);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* If this element is saved in the join_array clear it */
 | 
						|
		if (se->nr >= LLFIRST_NT) {
 | 
						|
			if (stack->join_array[se->nr - LLFIRST_NT] == se) {
 | 
						|
				stack->join_array[se->nr - LLFIRST_NT] =
 | 
						|
					(struct stack_elt *)0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#ifdef DEBUG
 | 
						|
		deallocates++;
 | 
						|
		edge_deallocates += se->nr_nexts;
 | 
						|
#endif
 | 
						|
		free((char *) se->edges);
 | 
						|
		free((char *) se);
 | 
						|
	}
 | 
						|
 | 
						|
#ifndef NOLOOPS
 | 
						|
	/* If this element belongs to a loop try to delete it */
 | 
						|
	else if (part_of_loop(se)) {
 | 
						|
 | 
						|
		/* Do a temporary delete */
 | 
						|
		hyp_run(se);
 | 
						|
 | 
						|
		/* Check it */
 | 
						|
		stack->check_run_ok = 1;
 | 
						|
		check_run(stack, se);
 | 
						|
 | 
						|
		/* If it can be deleted delete it */
 | 
						|
		if (stack->check_run_ok) {
 | 
						|
			se->ref_count = 0;
 | 
						|
			delete(stack, se);
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifndef NOLOOPS
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void hyp_run(struct stack_elt *se)
 | 
						|
#else
 | 
						|
static hyp_run(se)
 | 
						|
struct stack_elt *se;
 | 
						|
#endif /* LL_ANSI_C */
 | 
						|
 | 
						|
/* This function sets the 'hyp_ref_counts' of all elements of the loop that
 | 
						|
 * 'se' belongs to to the value that 'ref_count' will get when 'se' is
 | 
						|
 * deleted
 | 
						|
 */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	struct stack_elt *next_se;
 | 
						|
 | 
						|
	for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
		next_se = (se->edges + i)->ptr;
 | 
						|
 | 
						|
		if (	(!((se->edges + i)->flags & LLHYP_SEARCH))
 | 
						|
		&&	((se->edges + i)->flags & LLLOOP)
 | 
						|
		) {
 | 
						|
			(se->edges + i)->flags |= LLHYP_SEARCH;
 | 
						|
 | 
						|
			/* If this element is not yet visited initialize
 | 
						|
			 * 'hyp_ref_count' else decrease it by one
 | 
						|
			 */
 | 
						|
			if (next_se->hyp_ref_count == -1) {
 | 
						|
				next_se->hyp_ref_count = next_se->ref_count - 1;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				next_se->hyp_ref_count--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* Continue searching */
 | 
						|
			hyp_run(next_se);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void check_run(struct stacks *stack, struct stack_elt *se)
 | 
						|
#else
 | 
						|
static check_run(stack, se)
 | 
						|
struct stacks *stack;
 | 
						|
struct stack_elt *se;
 | 
						|
#endif /* LL_ANSI_C */
 | 
						|
 | 
						|
/* This function checks all 'hyp_ref_counts' that 'hyp_run()' has set.
 | 
						|
 * If one of them is not 0, 'check_run_ok' will be set to 0 indicating
 | 
						|
 * that 'se' cannot be deleted. 'check_run()' also resets all 'hyp_ref_counts'
 | 
						|
 */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (se->hyp_ref_count > 0) {
 | 
						|
		stack->check_run_ok = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Reset 'hyp_ref_count' */
 | 
						|
	se->hyp_ref_count = -1;
 | 
						|
	for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
		if ((se->edges + i)->flags & LLHYP_SEARCH) {
 | 
						|
			(se->edges + i)->flags &= ~LLHYP_SEARCH;
 | 
						|
			check_run(stack, (se->edges + i)->ptr);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#endif /* NOLOOPS */
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static struct stack_elt *split(struct stack_elt *se)
 | 
						|
#else
 | 
						|
static struct stack_elt *split(se)
 | 
						|
struct stack_elt *se;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function splits of a NT in de stack, and returns a pointer to it */
 | 
						|
{
 | 
						|
	struct stack_elt *new_stack;
 | 
						|
	int i;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	allocates++;
 | 
						|
	if (allocates - deallocates > max_in_use) {
 | 
						|
		max_in_use = allocates - deallocates;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	new_stack = (struct stack_elt *)Malloc(sizeof(struct stack_elt));
 | 
						|
	new_stack->flags = 0;		/* Used by 'clear_gen_flags()' */
 | 
						|
	new_stack->nr = se->nr;
 | 
						|
	new_stack->ref_count = 0;	/* Copy is new top */
 | 
						|
	new_stack->hyp_ref_count = -1;
 | 
						|
	new_stack->matched = -1;
 | 
						|
	new_stack->nr_nexts = se->nr_nexts;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	edge_allocates++;
 | 
						|
	if (edge_allocates - edge_deallocates > edge_max_in_use) {
 | 
						|
		edge_max_in_use = edge_allocates - edge_deallocates;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	new_stack->edges = (struct edge *)
 | 
						|
		Malloc((unsigned)se->nr_nexts * sizeof(struct edge));
 | 
						|
 | 
						|
	/* Copy gets the same successors as the original */
 | 
						|
	memcpy((char *) new_stack->edges, (char *) se->edges,
 | 
						|
					se->nr_nexts * sizeof(struct edge));
 | 
						|
 | 
						|
	/* Each successor gets a new predecessor */
 | 
						|
	for (i = 0; i < new_stack->nr_nexts; i++) {
 | 
						|
		(new_stack->edges + i)->ptr->ref_count++;
 | 
						|
		(new_stack->edges + i)->flags = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	return new_stack;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
#if LL_ANSI_C
 | 
						|
static void test(struct stacks *stack)
 | 
						|
#else
 | 
						|
static test(stack)
 | 
						|
struct stacks *stack;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	struct stack_elt *se;
 | 
						|
	int i;
 | 
						|
 | 
						|
	printf("STACKS:\n");
 | 
						|
	for (i = 0; i < stack->nr_heads; i++) {
 | 
						|
		printf("%2d: ", i + 1);
 | 
						|
		if (*(stack->heads_buf + i) == (struct stack_elt *)0) {
 | 
						|
			printf("NIL\n");
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		se = *(stack->heads_buf + i);
 | 
						|
		dump_stack(se, 1);
 | 
						|
		clear_flags(se, PRINT_SEARCH);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void dump_stack(struct stack_elt *se, int level)
 | 
						|
#else
 | 
						|
static dump_stack(se, level)
 | 
						|
struct stack_elt *se;
 | 
						|
int level;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	int i, j;
 | 
						|
 | 
						|
	while (se->nr != LLEOSTACK) {
 | 
						|
		if ((se->flags & LLDUMMY) && (se->nr_nexts > 1)) {
 | 
						|
			printf("[%d] <%d,%d,%d>\n",
 | 
						|
				se->nr, se->ref_count,
 | 
						|
				se->hyp_ref_count,
 | 
						|
				se->flags
 | 
						|
			);
 | 
						|
			for (j = 0; j < se->nr_nexts; j++) {
 | 
						|
				for (i = 1; i <= level; i++) {
 | 
						|
					printf("    ");
 | 
						|
				}
 | 
						|
				printf("%d: ", j + 1);
 | 
						|
				if (!((se->edges + j)->flags & PRINT_SEARCH)) {
 | 
						|
					printf(" (%d) ", (se->edges + j)->flags);
 | 
						|
					(se->edges + j)->flags |= PRINT_SEARCH;
 | 
						|
					dump_stack((se->edges+j)->ptr,level+1);
 | 
						|
					/*clear_flags((se->edges+j)->ptr,PRINT_SEARCH);*/
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					printf("LOOP\n");
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if (se->flags & LLDUMMY) {
 | 
						|
				printf("[%d] <%d,%d,%d> ",
 | 
						|
					se->nr,se->ref_count,
 | 
						|
					se->hyp_ref_count,
 | 
						|
					se->flags
 | 
						|
				);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				printf("%d <%d,%d,%d> ",
 | 
						|
					se->nr, se->ref_count,
 | 
						|
					se->hyp_ref_count,
 | 
						|
					se->flags
 | 
						|
				);
 | 
						|
			}
 | 
						|
			if (!(se->edges->flags & PRINT_SEARCH)) {
 | 
						|
				printf(" (%d) ", se->edges->flags);
 | 
						|
				se->edges->flags |= PRINT_SEARCH;
 | 
						|
				se = se->edges->ptr;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				printf("LOOP\n");
 | 
						|
				return;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void clear_flags(struct stack_elt *se, char flag)
 | 
						|
#else
 | 
						|
static clear_flags(se, flag)
 | 
						|
struct stack_elt *se;
 | 
						|
char flag;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Clears edge flag 'flag' */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < se->nr_nexts; i++) {
 | 
						|
		if ((se->edges + i)->flags & flag) {
 | 
						|
			(se->edges + i)->flags &= ~flag; /* clear flag */
 | 
						|
			clear_flags((se->edges + i)->ptr, flag);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void clear_gen_flags(struct stacks *stack)
 | 
						|
#else
 | 
						|
static clear_gen_flags(stack)
 | 
						|
struct stacks *stack;
 | 
						|
#endif
 | 
						|
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < stack->nr_visited; i++) {
 | 
						|
		(*(stack->visited_buf + i))->flags &= ~(LLGEN_SEARCH);
 | 
						|
	}
 | 
						|
 | 
						|
	stack->nr_visited = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void match_heads(struct stacks *stack, int symb)
 | 
						|
#else
 | 
						|
static match_heads(stack, symb)
 | 
						|
struct stacks *stack;
 | 
						|
int symb;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Match heads_buf against symb, leaving only matching heads,
 | 
						|
 * whilst deallocating the non-matching stacks
 | 
						|
 */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	int old_nr_heads;
 | 
						|
	struct stack_elt **old_heads_buf;
 | 
						|
 | 
						|
 | 
						|
	/* Copy the 'old' heads */
 | 
						|
	old_nr_heads = stack->nr_heads;
 | 
						|
	old_heads_buf = stack->heads_buf;
 | 
						|
 | 
						|
 | 
						|
	/* Set heads in stack to 0 */
 | 
						|
	stack->nr_heads = 0;
 | 
						|
	stack->heads_buf_size = 0;
 | 
						|
	stack->heads_buf = (struct stack_elt **) 0;
 | 
						|
 | 
						|
 | 
						|
	for (i = 0; i < old_nr_heads; i++) {
 | 
						|
		if ((*(old_heads_buf + i))->nr != symb) {
 | 
						|
			/* Does not match? */
 | 
						|
			(*(old_heads_buf + i))->ref_count--;
 | 
						|
			(*(old_heads_buf + i))->flags &= ~LLHEAD;
 | 
						|
			delete(stack, *(old_heads_buf + i));
 | 
						|
		}
 | 
						|
		else {	/* Matches */
 | 
						|
			if (stack->heads_buf_size == 0) {
 | 
						|
				stack->heads_buf_size = LLHEADS_BUF_INCR;
 | 
						|
				stack->heads_buf = (struct stack_elt **)
 | 
						|
					Malloc((unsigned)stack->heads_buf_size *
 | 
						|
						sizeof(struct stack_elt *));
 | 
						|
			}
 | 
						|
			else if (stack->nr_heads == stack->heads_buf_size) {
 | 
						|
				stack->heads_buf_size += LLHEADS_BUF_INCR;
 | 
						|
				stack->heads_buf = (struct stack_elt **)
 | 
						|
					Realloc((char *) stack->heads_buf,
 | 
						|
						(unsigned) stack->heads_buf_size *
 | 
						|
						sizeof(struct stack_elt *));
 | 
						|
			}
 | 
						|
			*(stack->heads_buf + stack->nr_heads) =
 | 
						|
				*(old_heads_buf + i);
 | 
						|
			stack->nr_heads++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	free((char *) old_heads_buf);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void cleanup(struct stacks *stack)
 | 
						|
#else
 | 
						|
static cleanup(stack)
 | 
						|
struct stacks *stack;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Deletes all elements in 'cleanup_buf()' */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < stack->nr_cleanups; i++) {
 | 
						|
		delete(stack, *(stack->cleanup_buf + i));
 | 
						|
	}
 | 
						|
 | 
						|
	stack->nr_cleanups = 0;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void initialize(struct stacks *stack)
 | 
						|
#else
 | 
						|
static initialize(stack)
 | 
						|
struct stacks *stack;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Initializes some variables and arrays */
 | 
						|
{
 | 
						|
	int j;
 | 
						|
 | 
						|
	stack->nr_heads = 0;
 | 
						|
	stack->heads_buf_size = 0;
 | 
						|
	stack->heads_buf = (struct stack_elt **)0;
 | 
						|
 | 
						|
	stack->nr_cleanups = 0;
 | 
						|
	stack->cleanup_buf_size = 0;
 | 
						|
	stack->cleanup_buf = (struct stack_elt **)0;
 | 
						|
 | 
						|
	stack->nr_visited = 0;
 | 
						|
	stack->visited_buf_size = 0;
 | 
						|
	stack->visited_buf = (struct stack_elt **)0;
 | 
						|
 | 
						|
	for (j = 0; j < (LLNNONTERMINALS + 7)/8; j++) {
 | 
						|
		stack->r_rec[j] = (char) 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for (j = 0; j < LLNNONTERMINALS; j++) {
 | 
						|
		stack->join_array[j] = (struct stack_elt *)0;
 | 
						|
	}
 | 
						|
 | 
						|
	for (j = 0; j < LLSETSIZE; j++) {
 | 
						|
		stack->exp_terminals[j] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	stack->start_seen = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void calculate(struct stacks *stack, int l_ahead)
 | 
						|
#else
 | 
						|
static calculate(stack, l_ahead)
 | 
						|
struct stacks *stack;
 | 
						|
int l_ahead;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function finds all new heads and deletes the old heads */
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	int old_nr_heads;
 | 
						|
	struct stack_elt **old_heads_buf;
 | 
						|
 | 
						|
	/* Make a copy of the heads */
 | 
						|
	old_nr_heads = stack->nr_heads;
 | 
						|
	old_heads_buf = stack->heads_buf;
 | 
						|
 | 
						|
	stack->nr_heads = 0;
 | 
						|
	stack->heads_buf = (struct stack_elt **) 0;
 | 
						|
	stack->heads_buf_size = 0;
 | 
						|
 | 
						|
	for (i = 0; i < old_nr_heads; i++) {
 | 
						|
		/* Find all new heads */
 | 
						|
		generate_heads(stack, *(old_heads_buf + i), l_ahead);
 | 
						|
		clear_gen_flags(stack);
 | 
						|
 | 
						|
		/* Old head can be deleted now */
 | 
						|
		(*(old_heads_buf + i))->ref_count--;
 | 
						|
		delete(stack, *(old_heads_buf + i));
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	cleanup(stack);
 | 
						|
	free((char *) old_heads_buf);
 | 
						|
 | 
						|
	/* Reinitialize some things */
 | 
						|
	for (i = 0; i < (LLNNONTERMINALS + 7)/8; i++) {
 | 
						|
		stack->r_rec[i] = (char) 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < LLNNONTERMINALS; i++) {
 | 
						|
		stack->join_array[i] = (struct stack_elt *)0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Delete all HEAD flags */
 | 
						|
	for (i = 0; i < stack->nr_heads; i++) {
 | 
						|
		(*(stack->heads_buf + i))->flags &= ~LLHEAD;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
static void kill_stack(struct stacks *stack)
 | 
						|
#else
 | 
						|
static kill_stack(stack)
 | 
						|
struct stacks *stack;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < stack->nr_heads; i++) {
 | 
						|
		(*(stack->heads_buf + i))->ref_count--;
 | 
						|
		delete(stack, *(stack->heads_buf + i));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#if LL_ANSI_C
 | 
						|
void LLnc_recover(void)
 | 
						|
#else
 | 
						|
LLnc_recover()
 | 
						|
#endif
 | 
						|
 | 
						|
/* This function contains the main loop for non correcting syntax error
 | 
						|
 * recovery
 | 
						|
 */
 | 
						|
{
 | 
						|
	int j;
 | 
						|
	int base_symb;
 | 
						|
	struct stacks stack;
 | 
						|
	int max_nr_heads;
 | 
						|
	int max_nr_good_heads;
 | 
						|
 | 
						|
	initialize(&stack);
 | 
						|
	max_nr_heads = 0;
 | 
						|
	max_nr_good_heads = 0;
 | 
						|
 | 
						|
	/* Grammar has to be read only once */
 | 
						|
	if (!grammar_read) {
 | 
						|
		build_grammar();
 | 
						|
		grammar_read = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Read first token */
 | 
						|
	read_token();
 | 
						|
	base_symb = LLsymb;
 | 
						|
 | 
						|
	/* Check on end of file */
 | 
						|
	if ((base_symb <= 0) || (base_symb == EOFILE)) {
 | 
						|
 | 
						|
		if ((nonterminals + LLstartsymb - LLFIRST_NT)->rule->empty != 1
 | 
						|
		) {
 | 
						|
			LLsymb = EOFILE;
 | 
						|
			LLmessage(0);
 | 
						|
		}
 | 
						|
 | 
						|
		kill_stack(&stack);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Read look ahead token */
 | 
						|
	read_token();
 | 
						|
 | 
						|
	/* Now search applicable rules and starts the ball rolling */
 | 
						|
	start_stack(&stack, base_symb, LLsymb);
 | 
						|
 | 
						|
	if (stack.nr_heads > max_nr_heads) {
 | 
						|
		max_nr_heads = stack.nr_heads;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/* Only matching heads are needed */
 | 
						|
	match_heads(&stack, LLsymb);
 | 
						|
 | 
						|
	if (stack.nr_heads > max_nr_good_heads) {
 | 
						|
		max_nr_good_heads = stack.nr_heads;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	test(&stack);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* Loop untill end of inputfile */
 | 
						|
	while ((LLsymb > 0) && (LLsymb != EOFILE)) {
 | 
						|
		/* When entering the loop LLsymb always contains the
 | 
						|
		 * symbol that was used as look_ahead to construct the stacks,
 | 
						|
		 * or, if optimization is OFF, it contains the symbol with
 | 
						|
		 * which the current heads have been matched 
 | 
						|
		 */
 | 
						|
 | 
						|
		if (stack.nr_heads == 0) {
 | 
						|
			/* No more heads left */
 | 
						|
			LLmessage(0);
 | 
						|
 | 
						|
			/* Restart the whole thing */
 | 
						|
			initialize(&stack);
 | 
						|
 | 
						|
			/* The look-ahead caused the empty stack, don't
 | 
						|
			 * use it to start a new one !
 | 
						|
			 */
 | 
						|
 | 
						|
			read_token();
 | 
						|
			base_symb = LLsymb;
 | 
						|
 | 
						|
			/* Check on end of file */
 | 
						|
			if ((base_symb <= 0) || (base_symb == EOFILE)) {
 | 
						|
				if ((nonterminals + LLstartsymb - LLFIRST_NT)->rule->empty != 1) {
 | 
						|
					LLsymb = EOFILE;
 | 
						|
					LLmessage(0);
 | 
						|
				}
 | 
						|
				kill_stack(&stack);
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			read_token();
 | 
						|
 | 
						|
			start_stack(&stack, base_symb, LLsymb);
 | 
						|
 | 
						|
			if (stack.nr_heads > max_nr_heads) {
 | 
						|
				max_nr_heads = stack.nr_heads;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			match_heads(&stack, LLsymb);
 | 
						|
 | 
						|
			if (stack.nr_heads > max_nr_good_heads) {
 | 
						|
				max_nr_good_heads = stack.nr_heads;
 | 
						|
			}
 | 
						|
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		/* Normal case starts here */
 | 
						|
		stack.start_seen = 0;
 | 
						|
 | 
						|
		for (j = 0; j < LLSETSIZE; j++) {
 | 
						|
			stack.exp_terminals[j] = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Read next symbol */
 | 
						|
		read_token();
 | 
						|
 | 
						|
		/* Generate all new heads and delete old ones */
 | 
						|
		calculate(&stack, LLsymb);
 | 
						|
 | 
						|
		/* Leave out not wanted heads */
 | 
						|
 | 
						|
		if (stack.nr_heads > max_nr_heads) {
 | 
						|
			max_nr_heads = stack.nr_heads;
 | 
						|
		}
 | 
						|
 | 
						|
		match_heads(&stack, LLsymb);
 | 
						|
 | 
						|
		if (stack.nr_heads > max_nr_good_heads) {
 | 
						|
			max_nr_good_heads = stack.nr_heads;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
		test(&stack);
 | 
						|
#endif
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	/* End of file reached, check if we have seen a start symbol */
 | 
						|
	if (stack.start_seen == 1) return;
 | 
						|
	else {
 | 
						|
		LLsymb = EOFILE;
 | 
						|
		LLmessage(0);
 | 
						|
	}
 | 
						|
 | 
						|
	kill_stack(&stack);
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	printf("Maximum number of heads: %d\n", max_nr_heads);
 | 
						|
	printf("Maximum number of good heads: %d\n", max_nr_good_heads);
 | 
						|
	printf("Number of node allocates: %d\n", allocates);
 | 
						|
	printf("Number of node deallocates: %d\n", deallocates);
 | 
						|
	printf("Maximum number of nodes in use: %8d\n", max_in_use);
 | 
						|
	printf("Sizeof(struct stack_elt)              = %8d\n", sizeof(struct stack_elt));
 | 
						|
	printf("                                        --------x\n");
 | 
						|
	printf("                                        %8d\n", max_in_use * sizeof(
 | 
						|
					struct stack_elt));
 | 
						|
	printf("Number of edge allocates: %d\n", edge_allocates);
 | 
						|
	printf("Number of edge deallocates: %d\n", edge_deallocates);
 | 
						|
	printf("Maximum number of edges in use: %8d\n", edge_max_in_use);
 | 
						|
	printf("Sizeof(struct edge)              = %8d\n", sizeof(struct edge));
 | 
						|
	printf("                                   --------x\n");
 | 
						|
	printf("                                   %8d\n", edge_max_in_use * sizeof(struct edge));
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 |