extern unsigned int LLtcnt[];
extern int LLcsymb;
+#if LL_NON_CORR
+extern int LLstartsymb;
+#endif
+
#define LLsdecr(d) {LL_assert(LLscnt[d] > 0); LLscnt[d]--;}
#define LLtdecr(d) {LL_assert(LLtcnt[d] > 0); LLtcnt[d]--;}
#define LLsincr(d) LLscnt[d]++
--- /dev/null
+#define LLALT 9999 /* Alternative is following */
+
+#define LLTERMINAL 1 /* Symbol is a terminal */
+#define LLNONTERMINAL 2 /* Symbol is a nonterminal */
+#define LLEORULE 0 /* No more alternatives */
+
+
+struct lhs { /* LHS of a rule */
+ int nr; /* Nr of the nonterminal */
+ struct symbol *rhs; /* Pointer to RHS */
+ char first[LLSETSIZE]; /* First set */
+ char follow[LLSETSIZE]; /* Follow set */
+ char empty; /* Set if nonterminal produces empty */
+};
+
+struct symbol { /* Symbol in the RHS of a rule */
+ int x; /* LLTERMINAL or LLNONTERMINAL */
+ int nr; /* Nr of the symbol */
+ struct symbol *link; /* Ptr to next rule with this symbol */
+ struct symbol *next; /* Ptr to next symbol in this rule */
+ struct lhs *lhs; /* Ptr to LHS */
+};
+
+struct terminal { /* Array with links to terminals in a */
+ struct symbol *link; /* rule */
+};
+
+struct nonterminal { /* Array with links to nt's in a rule */
+ struct symbol *link; /* and pointer to LHS's */
+ struct lhs *rule;
+};
+
+struct stack_elt { /* Stack element */
+ int flags; /* Some flags */
+ int nr; /* Nr of symbol */
+ int ref_count; /* Nr of predecessors */
+ int hyp_ref_count; /* Temporary nr of predecessors */
+ int matched; /* Nr of LHS trying to match */
+ int nr_nexts; /* Nr of successors */
+ struct edge *edges; /* Array of edges to other stack elt's*/
+};
+
+/* Possible flags in a stack element */
+#define LLHEAD 1 /* Stack element is a head */
+#define LLDUMMY 2 /* Stack element is substituted */
+#define LLGEN_SEARCH 8 /* Set by 'generate_heads()' */
+
+
+struct edge { /* Edges of a stack element */
+ char flags; /* Some flags */
+ struct stack_elt *ptr; /* Array with pointers to stack elt's */
+};
+
+/* Possible flags in an edge */
+#define LLLOOP 1 /* Belongs to a loop */
+#define LLLOOP_SEARCH 2 /* Used by 'loop()' */
+#define LLHYP_SEARCH 4 /* Used by 'hyp_run()' */
+#define PRINT_SEARCH 8 /* DEBUG */
+#define LLMARK_SEARCH 16 /* Used by 'mark_loop()' */
+#define LLYES 32
+#define LLNO 64
+
+#define LLEOSTACK -1 /* Indicates last element of a stack */
+#define LLHEADS_BUF_INCR 10 /* Nr of elements the buffer will be */
+#define LLCLEANUP_BUF_INCR 25 /* increased by */
+#define LL_VIS_INCR 200
+
+/* Macro's to manipulate bit sets */
+#define LLIN(a, i) ((a)[(i)/8] & (1 << ((i) % 8)))
+#define LLPUTIN(a, i) ((a)[(i)/8] |= (1 << ((i) % 8)))
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include "Lpars.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*);
+static void test(struct stacks*);
+static void dump_stack(struct stack_elt*, int);
+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
+}
+
int LLcsymb, LLsymb;
static int LLlevel;
+#if LL_NON_CORR
+int LLstartsymb;
+static int fake_eof = 0;
+#endif
+
#if LL_ANSI_C
#define LL_VOIDCST (void)
void LLmessage(int);
/*
* Check if the next symbol is equal to the parameter
*/
+
+#if LL_NON_CORR
+ /* See if the error recovery has eaten an eof */
+ if (fake_eof) {
+ LLsymb = EOFILE;
+ fake_eof = 0;
+ }
+ else {
+ LLsymb = LL_LEXI();
+ }
+
+ if (LLsymb == t) {
+#else
if ((LLsymb = LL_LEXI()) == t) {
+#endif
+
+#if LL_NON_CORR
+ /* Check if a previous parser has 'crashed', in that
+ * case continue with non-correcting parser
+ */
+ if (err_seen && !nc_done) {
+ LLnc_recover();
+ nc_done = 1;
+ /* Remember that the error recovery has eaten an eof */
+ fake_eof = 1;
+ if (t != LLsymb) {
+ LLerror(t);
+ }
+ else
+ return;
+ }
+#endif
return;
}
/*
#else
LLread() {
#endif
+
+#if LL_NON_CORR
+ /* Again, check if another parser has crashed,
+ * in that case intercept and go to the
+ * non-correcting parser
+ */
+
+ if (err_seen && !nc_done) {
+ LLnc_recover();
+ nc_done = 1;
+ /* Pretend we read end of file */
+ LLsymb = EOFILE;
+ LLcsymb = LLindex[EOFILE];
+ fake_eof = 0;
+ return;
+ }
+
+ if (fake_eof) {
+ LLsymb = EOFILE;
+ LLcsymb = LLindex[EOFILE];
+ fake_eof = 0;
+ return;
+ }
+#endif
+
for (;;) {
if ((LLcsymb = LLindex[(LLsymb = LL_LEXI())]) >= 0) return;
LLmessage(0);
return;
}
#endif
+
+#if LL_NON_CORR
+ if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
+ LLmessage(0);
+ LLnc_recover();
+ nc_done = 1;
+ LLsymb = EOFILE;
+ }
+#endif
+
if ((LLcsymb = LLindex[LLsymb]) < 0) {
LLmessage(0);
LLread();
LL_VOIDCST LLskip();
#endif
LLtcnt[i]--;
- if (LLsymb != t) LLmessage(t);
+ if (LLsymb != t) {
+#if LL_NON_CORR
+ /* A little kludge here; when using non-correcting recovery
+ * it can happen that a program is correct but incomplete.
+ * Here, we test this, and make sure the appropriate
+ * message is generated
+ */
+ if (! nc_done) {
+ int oldLLsymb;
+ oldLLsymb = LLsymb;
+ LLsymb = EOFILE;
+ LLmessage(0);
+ nc_done = 1;
+ /* Not really, but to prevent more than 1 error message */
+ LLsymb = oldLLsymb;
+ }
+#endif
+ LLmessage(t);
+ }
}
#if LL_ANSI_C
}
return;
}
+#endif
+#if LL_NON_CORR
+ if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
+ LLmessage(0);
+ LLnc_recover();
+ nc_done = 1;
+ LLsymb = EOFILE;
+ }
#endif
LLmessage(t);
}
continue;
}
#endif /* LL_USERHOOK */
+#if LL_NON_CORR
+ if ((!nc_done) && (LLsymb > 0)) {
+ LLmessage(0);
+ LLnc_recover();
+ nc_done = 1;
+ fake_eof = 1;
+ }
+ else {
+ LLmessage(0);
+ }
+#else
LLmessage(0);
+#endif
retval = 1;
LLread();
}
p_gram search();
long ftell();
-static int nparams; /* parameter count for nonterminals */
static int acount; /* count #of global actions */
-static int order;
static p_term t_list;
static int t_cnt;
static p_gram alt_table;
#define RULEINCR 32
/* Here are defined : */
-STATIC newnorder();
-STATIC newtorder();
-STATIC copyact();
+STATIC newnorder();
+STATIC newtorder();
STATIC mkalt();
STATIC mkterm();
STATIC p_gram copyrule();
}
';'
| C_ONERROR C_IDENT
- { if (! onerror) {
+ {
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ warning(linecount, "%%onerror conflicts with -n option");
+ }
+ else
+#endif
+ if (! onerror) {
onerror = store(lextoken.t_string);
}
else error(linecount,"Duplicate %%onerror");
}
';'
- | action(0) { acount++; }
+ | C_ACTION { acount++; }
/*
* A global C-declaration
*/
p->n_lineno = linecount;
p->n_off = ftell(fact);
}
- [ params(1) { if (nparams > 0) {
+ [ C_PARAMS { if (lextoken.t_num > 0) {
p->n_flags |= PARAMS;
- if (nparams > 15) {
+ if (lextoken.t_num > 15) {
error(linecount,"Too many parameters");
}
- else setntparams(p,nparams);
+ else setntparams(p,lextoken.t_num);
}
}
]?
- [ action(0) { p->n_flags |= LOCALS; }
+ [ C_ACTION { p->n_flags |= LOCALS; }
]?
- ':' productions(&rr) ';'
+ ':' { in_production = 1; }
+ productions(&rr) ';'
+ { in_production = 0; }
/*
* Do not use p->n_rule now! The nonterms array
* might have been re-allocated.
{ nonterms[g_getcont(temp)].n_rule = rr;}
;
-action(int n;)
- /*
- * The parameter n is non-zero when the opening and closing
- * bracket must be copied along with the action
- */
- : '{' { copyact('{','}',n,0); }
- '}'
- ;
-
productions(p_gram *p;)
/*
* One or more alternatives
t = 0;
*p = prod;
}
- ]+ { if (conflres & ~DEF) {
+ ]+ { if (conflres & (COND|PREFERING|AVOIDING)) {
error(n_lc,
"Resolver on last alternative not allowed");
}
*p = copyrule(&alt_table[n_alts-altcnt],altcnt+1);
}
|
- { if (conflres & ~DEF) {
+ { if (conflres & (COND|PREFERING|AVOIDING)) {
error(o_lc,
"No alternation conflict resolver allowed here");
}
int cnt, kind;
int termdeleted = 0;
} :
- [ C_DEFAULT { *conflres = DEF; }
+ [ C_DEFAULT { *conflres |= DEF; }
]?
[
/*
* Optional conflict reslover
*/
- C_IF expr { *conflres |= COND; }
+ C_IF C_EXPR { *conflres |= COND; }
| C_PREFER { *conflres |= PREFERING; }
| C_AVOID { *conflres |= AVOIDING; }
]?
+ [ C_ILLEGAL {
+#ifdef NON_CORRECTING
+ if (n_rules >= max_rules-2) {
+ rule_table = (p_gram) ralloc(
+ (p_mem) rule_table,
+ (unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
+ }
+ elmcnt++;
+ rule_table[n_rules++] =
+ *search(TERMINAL, "LLILLEGAL", BOTH);
+ if (*conflres & DEF) {
+ error(linecount, "%%illegal not allowed in %%default rule");
+ }
+#endif
+ }
+ ]?
[ %persistent elem(&elem)
{ if (n_rules >= max_rules-2) {
rule_table = (p_gram) ralloc(
p_gram p1;
int ln;
p_gram pe;
+#ifdef NON_CORRECTING
+ int erroneous = 0;
+#endif
} :
'[' { ln = linecount; }
- [ C_WHILE expr { t |= RESOLVER; }
+ [ C_WHILE C_EXPR { t |= RESOLVER; }
]?
[ C_PERSISTENT { t |= PERSISTENT; }
]?
mkterm(p1,t,ln,pres);
}
|
+ [ C_ERRONEOUS {
+#ifdef NON_CORRECTING
+ erroneous = 1;
+#endif
+ }
+ ]?
+
+ [
C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH);
*pres = *pe;
+#ifdef NON_CORRECTING
+ if (erroneous) {
+ if (g_gettype(pres) != TERMINAL){
+ warning(linecount,
+ "Erroneous only allowed on terminal");
+ erroneous = 0;
+ }
+ else
+ pres->g_erroneous = 1;
+ }
+#endif
+
}
- [ params(0) { if (nparams > 15) {
+ [ C_PARAMS { if (lextoken.t_num > 15) {
error(linecount,"Too many parameters");
- } else g_setnpar(pres,nparams);
+ } else g_setnpar(pres,lextoken.t_num);
if (g_gettype(pres) == TERMINAL) {
error(linecount,
"Terminal with parameters");
]?
| C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH);
*pres = *pe;
+#ifdef NON_CORRECTING
+ if (erroneous)
+ pres->g_erroneous = 1;
+#endif
}
+ ]
| { g_settype(pres,ACTION);
pres->g_lineno = linecount;
+#ifdef NON_CORRECTING
+ g_setsubparse(pres, (p_start) 0);
+#endif
}
- action(1)
- ;
-params(int formal)
-{
- long off = ftell(fact);
-}
- : '(' { copyact('(', ')', formal ? 2 : 0, 0); }
- ')'
- { if (nparams == 0) {
- fseek(fact, off, 0);
+ [ C_SUBSTART
+
+ {
+#ifdef NON_CORRECTING
+ nsubstarts++;
+#endif
+ }
+
+ C_IDENT
+ {
+#ifdef NON_CORRECTING
+ register p_gram temp;
+ register p_start subp;
+
+ temp = search(NONTERM,lextoken.t_string,BOTH);
+ subp = (p_start) alloc (sizeof(t_start));
+
+ subp->ff_nont = g_getcont(temp);
+ subp->ff_name = (string) 0;
+ subp->ff_next = (p_start) 0;
+ g_setsubparse(pres, subp);
+#endif
+ }
+
+ [ ',' C_IDENT
+ {
+#ifdef NON_CORRECTING
+ register p_gram temp;
+ register p_start ff;
+
+ temp = search(NONTERM,lextoken.t_string,BOTH);
+
+ ff = g_getsubparse(pres);
+ while (ff) {
+ if (ff->ff_nont == g_getcont(temp)) {
+ warning(linecount, "\"%s\" used twice in %%substart", lextoken.t_string);
+ break;
+ }
+ ff = ff->ff_next;
+
}
+
+ ff = (p_start) alloc(sizeof(t_start));
+ ff->ff_nont = g_getcont(temp);
+ ff->ff_name = (string) 0;
+ ff->ff_next = g_getsubparse(pres);
+ g_setsubparse(pres, ff);
+#endif
}
- ;
-expr : '(' { copyact('(',')',1,0); }
- ')'
+ ]* ';'
+ ]?
+
+ C_ACTION
;
repeats(int *kind; int *cnt;) { int t1 = 0; } :
;
{
-STATIC
-copyact(ch1,ch2,flag,level) char ch1,ch2; {
- /*
- * Copy an action to file f. Opening bracket is ch1, closing bracket
- * is ch2.
- * If flag & 1, copy opening and closing parameters too.
- * If flag & 2, don't allow ','.
- */
- static int text_seen = 0;
- register FILE *f;
- register ch; /* Current char */
- register match; /* used to read strings */
- int saved; /* save linecount */
- int sav_strip = strip_grammar;
-
- f = fact;
- if (ch1 == '{' || flag != 1) strip_grammar = 0;
- if (!level) {
- saved = linecount;
- text_seen = 0;
- nparams = 0; /* count comma's */
- putc('\0',f);
- fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
- }
- if (level || (flag & 1)) putc(ch1,f);
- for (;;) {
- ch = input();
- if (ch == ch2) {
- if (!level) {
- unput(ch);
- if (text_seen) nparams++;
- }
- if (level || (flag & 1)) putc(ch,f);
- if (strip_grammar != sav_strip) {
- if (ch1 == '{' || flag != 1) putchar(ch);
- }
- strip_grammar = sav_strip;
- return;
- }
- switch(ch) {
- case ')':
- case '}':
- case ']':
- error(linecount,"Parentheses mismatch");
- break;
- case '(':
- text_seen = 1;
- copyact('(',')',flag,level+1);
- continue;
- case '{':
- text_seen = 1;
- copyact('{','}',flag,level+1);
- continue;
- case '[':
- text_seen = 1;
- copyact('[',']',flag,level+1);
- continue;
- case '/':
- ch = input();
- unput(ch);
- if (ch == '*') {
- putc('/', f);
- skipcomment(1);
- continue;
- }
- ch = '/';
- text_seen = 1;
- break;
- case ';':
- case ',':
- if (! level && text_seen) {
- text_seen = 0;
- nparams++;
- if (ch == ',' && (flag & 2)) {
- warning(linecount, "Parameters may not be separated with a ','");
- ch = ';';
- }
- }
- break;
- case '\'':
- case '"' :
- /*
- * watch out for brackets in strings, they do not
- * count !
- */
- text_seen = 1;
- match = ch;
- putc(ch,f);
- while((ch = input())) {
- if (ch == match) break;
- if (ch == '\\') {
- putc(ch,f);
- ch = input();
- }
- if (ch == '\n') {
- error(linecount,"Newline in string");
- unput(match);
- }
- putc(ch,f);
- }
- if (ch == match) break;
- /* Fall through */
- case EOF :
- if (!level) error(saved,"Action does not terminate");
- strip_grammar = sav_strip;
- return;
- default:
- if (c_class[ch] != ISSPA) text_seen = 1;
- }
- putc(ch,f);
- }
-}
-
STATIC p_gram
copyrule(p,length) register p_gram p; {
/*
*/
p->i_size += p->i_incr * p->i_esize;
}
- p->i_ptr = !p->i_ptr ?
+ p->i_ptr = !p->i_ptr ?
alloc(p->i_size) :
ralloc(p->i_ptr, p->i_size);
p->i_max = p->i_ptr + sz;
ISKEY, /* '%' */
0, /* '&' */
ISLIT, /* ''' */
- ISTOK, /* '(' */
- ISTOK, /* ')' */
+ ISACT, /* '(' */
+ 0, /* ')' */
ISTOK, /* '*' */
ISTOK, /* '+' */
ISTOK, /* ',' */
ISLET, /* 'x' */
ISLET, /* 'y' */
ISLET, /* 'z' */
- ISTOK, /* '{' */
+ ISACT, /* '{' */
ISTOK, /* '|' */
- ISTOK, /* '}' */
+ 0, /* '}' */
0, /* '~' */
0 /* 0177 */
};
#define ISTOK 5
#define ISCOM 6
#define ISLIT 7
+#define ISACT 8
static string rcsid1 = "$Id$";
# endif
-
static string c_first = "> firstset ";
static string c_contains = "> containset ";
static string c_follow = "> followset ";
f_input = x->f_name;
for (s = x->f_nonterminals; s != -1; s = p->n_next) {
p = &nonterms[s];
- if (check(p->n_rule)) p->n_flags |= VERBOSE;
+ if (check(p->n_rule)) p->n_flags |= VERBOSE;
}
}
for (x = files; x < maxfiles; x++) {
n = &nonterms[g_getcont(p)];
if (g_getnpar(p) != getntparams(n)) {
error(p->g_lineno,
- "Call of %s: parameter count mismatch",
+ "Call of %s: parameter count mismatch",
n->n_name);
}
break; }
temp = setalloc();
setunion(temp,q->t_first);
if (!setintersect(temp,q->t_follow)) {
- /*
- * q->t_first * q->t_follow != EMPTY
- */
+ /*
+ * q->t_first * q->t_follow != EMPTY
+ */
if (!(q->t_flags & RESOLVER)) {
- /*
- * No conflict resolver
- */
+ /*
+ * No conflict resolver
+ */
error(p->g_lineno,
"Repetition conflict");
retval = 1;
"Alternation conflict");
retval = 1;
moreverbose(temp);
- }
+ }
} else {
if (l->l_flag & (COND|PREFERING|AVOIDING)) {
l->l_flag |= NOCONF;
"Conflict resolver without conflict");
}
}
- if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
free( (p_mem) temp);
+ if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
retval |= check(l->l_rule);
break; }
}
spaces();
p++; continue; }
case LITERAL :
- case TERMINAL : {
+ case TERMINAL : {
register p_token pt = &tokens[g_getcont(p)];
fprintf(f,pt->t_tokno<0400 ?
while (g_gettype(p) != EORULE) {
setminus(g_getlink(p)->l_symbs,set);
p++;
- }
+ }
}
STATIC
STATIC contains();
STATIC int nsafes();
STATIC int do_safes();
+#ifdef NON_CORRECTING
+STATIC int nc_nfirst();
+STATIC nc_first();
+STATIC int nc_nfollow();
+STATIC nc_follow();
+#endif
do_compute() {
/*
setntsafe(p,SCANDONE);
}
co_trans(nsafes);
+
+#ifdef NON_CORRECTING
+ if (subpars_sim) {
+ int s;
+
+ /* compute the union of the first sets of all start symbols
+ Used to compute the nc-first-sets when -s option is given */
+ start_firsts = get_set();
+ for (st = start; st; st = st->ff_next) {
+ s = setunion(start_firsts, (&nonterms[st->ff_nont])->n_first);
+ }
+ }
+
+ if (non_corr) {
+ /* compute the non_corr first sets for all nonterminals and terms */
+
+ co_trans(nc_nfirst);
+ for (st = start; st; st = st->ff_next) {
+ p = &nonterms[st->ff_nont];
+ PUTIN(p->n_nc_follow,0);
+ }
+ co_trans(nc_nfollow);
+ }
+#endif
+
# ifndef NDEBUG
if (debug) {
fputs("Safeties:\n", stderr);
p = &nonterms[i];
p->n_flags |= GENSTATIC;
p->n_first = get_set();
+#ifdef NON_CORRECTING
+ p->n_nc_first = get_set();
+ p->n_nc_follow = get_set();
+#endif
p->n_follow = get_set();
walk(f->f_used, p->n_rule);
}
q = g_getterm(p);
q->t_first = get_set();
+#ifdef NON_CORRECTING
+ q->t_nc_first = get_set();
+ q->t_nc_follow = get_set();
+#endif
q->t_follow = get_set();
walk(u, q->t_rule);
break; }
l = g_getlink(p);
l->l_symbs = get_set();
+#ifdef NON_CORRECTING
+ l->l_nc_symbs = get_set();
+#endif
l->l_others = get_set();
walk(u, l->l_rule);
break; }
for (;;) {
switch (g_gettype(p)) {
- case EORULE :
+ case EORULE :
return 1;
case TERM : {
register p_term q;
return first(p->n_first, p->n_rule, 0);
}
+#ifdef NON_CORRECTING
+STATIC int nc_nfirst(p) register p_nont p; {
+ return nc_first(p->n_nc_first, p->n_rule, 0);
+}
+#endif
+
STATIC
first(setp,p,flag) p_set setp; register p_gram p; {
/*
*/
register s; /* Will gather return value */
int noenter;/* when set, unables entering of elements into
- * setp. This is necessary to walk through the
- * rest of rule p.
+ * setp. This is necessary to walk through the
+ * rest of rule p.
*/
s = 0;
}
}
+#ifdef NON_CORRECTING
+STATIC
+nc_first(setp,p,flag) p_set setp; register p_gram p; {
+ /*
+ * Compute the non_corr FIRST set of rule p.
+ * If flag = 0, also the non_corr first sets for terms and
+ * alternations in the rule p are computed.
+ * The non_corr FIRST set is put in setp.
+ * return 1 if the set refered to by "setp" changed
+ * If the -s flag was given, the union of the first-sets of all
+ * start symbols is used whenever an action occurs. Else, only the
+ * first-sets of startsynbols in the %substart are used
+ */
+
+ register s; /* Will gather return value */
+ int noenter;/* when set, unables entering of elements into
+ * setp. This is necessary to walk through the
+ * rest of rule p.
+ */
+
+ s = 0;
+ noenter = 0;
+ for (;;) {
+ switch (g_gettype(p)) {
+ case EORULE :
+ return s;
+ case TERM : {
+ register p_term q;
+
+ q = g_getterm(p);
+ if (flag == 0) {
+ if (nc_first(q->t_nc_first,q->t_rule,0))/*nothing*/;
+ }
+ if (!noenter) s |= setunion(setp,q->t_nc_first);
+ p++;
+ if (r_getkind(q) == STAR ||
+ r_getkind(q) == OPT ||
+ empty(q->t_rule)) continue;
+ break; }
+ case ALTERNATION : {
+ register p_link l;
+
+ l = g_getlink(p);
+ if (flag == 0) {
+ if (nc_first(l->l_nc_symbs,l->l_rule,0))/*nothing*/;
+ }
+ if (noenter == 0) {
+ s |= setunion(setp,l->l_nc_symbs);
+ }
+ if (g_gettype(p+1) == EORULE) return s;
+ }
+ p++;
+ continue;
+ case ACTION : {
+ register p_start subp;
+
+ if (!noenter)
+ if (subpars_sim)
+ s |= setunion(setp, start_firsts);
+ else {
+ for (subp = g_getsubparse(p); subp;
+ subp = subp->ff_next)
+ s |= setunion(setp, (&nonterms[subp->ff_nont])->n_nc_first);
+
+ }
+ p++;
+ continue;
+ }
+ case LITERAL :
+ case TERMINAL :
+ if (g_getcont(p) == g_getcont(illegal_gram)) {
+ /* Ignore for this set. */
+ p++;
+ continue;
+ }
+ if ((noenter == 0) && !IN(setp,g_getcont(p))) {
+ s = 1;
+ PUTIN(setp,g_getcont(p));
+ }
+ p++;
+ break;
+ case NONTERM : {
+ register p_nont n;
+
+ n = &nonterms[g_getcont(p)];
+ if (noenter == 0) {
+ s |= setunion(setp,n->n_nc_first);
+ if (ntneeded) NTPUTIN(setp,g_getcont(p));
+ }
+ p++;
+ if (n->n_flags & EMPTY) continue;
+ break; }
+ }
+ if (flag == 0) {
+ noenter = 1;
+ continue;
+ }
+ return s;
+ }
+}
+#endif
+
STATIC int
nfollow(p) register p_nont p; {
return follow(p->n_follow, p->n_rule);
}
}
+#ifdef NON_CORRECTING
+
+STATIC int
+nc_nfollow(p) register p_nont p; {
+ return follow(p->n_nc_follow, p->n_rule);
+}
+
+STATIC
+nc_follow(setp,p) p_set setp; register p_gram p; {
+ /*
+ * setp is the follow set for the rule p.
+ * Compute the follow sets in the rule p from this set.
+ * Return 1 if a follow set of a nonterminal changed.
+ */
+ register s; /* Will gather return value */
+
+ s = 0;
+ for (;;) {
+ switch (g_gettype(p)) {
+ case EORULE :
+ return s;
+ case TERM : {
+ register p_term q;
+
+ q = g_getterm(p);
+ if (empty(p+1)) {
+ /*
+ * If what follows the term can be empty,
+ * everything that can follow the whole
+ * rule can also follow the term
+ */
+ s |= setunion(q->t_nc_follow,setp);
+ }
+ /*
+ * Everything that can start the rest of the rule
+ * can follow the term
+ */
+ s |= nc_first(q->t_nc_follow,p+1,1);
+ if (r_getkind(q) == STAR ||
+ r_getkind(q) == PLUS ||
+ r_getnum(q) ) {
+ /*
+ * If the term involves a repetition
+ * of possibly more than one,
+ * everything that can start the term
+ * can also follow it.
+ */
+ s |= nc_follow(q->t_nc_first,q->t_rule);
+ }
+ /*
+ * Now propagate the set computed sofar
+ */
+ s |= nc_follow(q->t_nc_follow, q->t_rule);
+ break; }
+ case ALTERNATION :
+ /*
+ * Just propagate setp
+ */
+ s |= nc_follow(setp,g_getlink(p)->l_rule);
+ break;
+ case NONTERM : {
+ register p_nont n;
+
+ n = &nonterms[g_getcont(p)];
+ s |= nc_first(n->n_nc_follow,p+1,1);
+ if (empty(p+1)) {
+ /*
+ * If the rest of p can produce empty,
+ * everything that follows p can follow
+ * the nonterminal
+ */
+ s |= setunion(n->n_nc_follow,setp);
+ }
+ break; }
+ }
+ p++;
+ }
+}
+
+#endif
+
STATIC
co_dirsymb(setp,p) p_set setp; register p_gram p; {
/*
* Compute the minimum length of a terminal production for each
* nonterminal.
* This length consists of two fields: the number of terminals,
- * and a number that is composed of
+ * and a number that is composed of
* - the number of this alternative
* - a crude measure of the number of terms and nonterminals in the
* production of this shortest string.
switch (g_gettype(p)) {
case LITERAL :
case TERMINAL :
+#ifdef NON_CORRECTING
+ if (g_getcont(p) == g_getcont(illegal_gram)) {
+ add(&X, INFINITY, 0);
+ break;
+ }
+#endif
add(&X, 1, 0);
break;
case ALTERNATION :
while (g_gettype(p) != EORULE) {
cnt++;
l = g_getlink(p);
+ p++;
complength(l->l_rule,&i);
i.val += cnt;
if (l->l_flag & DEF) {
if (compare(&i, &X) < 0) {
X = i;
}
- p++;
}
/* Fall through */
case EORULE :
q = g_getterm(p);
rep = r_getkind(q);
X.val += 1;
- if ((q->t_flags&PERSISTENT) ||
+ if ((q->t_flags&PERSISTENT) ||
rep==FIXED || rep==PLUS) {
complength(q->t_rule,&i);
add(&X, i.cnt, i.val);
do {
cnt++;
l = g_getlink(p);
+ p++;
complength(l->l_rule,&i);
i.val += cnt;
if (l->l_flag & DEF) temp = 1;
count = i;
}
setdefaults(l->l_rule);
- p++;
} while (g_gettype(p) != EORULE);
if (!temp) {
/* No user specified default */
do_contains(n) register p_nont n; {
/*
* Compute the total set of symbols that nonterminal n can
- * produce
+ * produce
*/
if (n->n_contains == 0) {
for (;;) {
switch (g_gettype(p)) {
case ACTION:
- p++;
+ p++;
continue;
case LITERAL:
case TERMINAL:
safe = t_after(rep, i, retval);
break; }
case ALTERNATION : {
- register p_link l;
+ register p_link l;
register int i;
retval = -1;
while (g_gettype(p) == ALTERNATION) {
l = g_getlink(p);
+ p++;
if (safe > SAFE && (l->l_flag & DEF)) {
i = do_safes(l->l_rule,SAFESCANDONE,ch);
}
}
else if (i > retval) retval = i;
}
- p++;
}
return retval; }
case NONTERM : {
extern int nterms; /* number of terms */
extern int nalts; /* number of alternatives */
extern p_start start; /* will contain startsymbols */
+#ifdef NON_CORRECTING
+extern int nsubstarts; /* number of subparserstarts */
+extern p_set start_firsts; /* Will contain the union of first sets of
+ startsymbols when -n -s option is on */
+#endif
extern int linecount; /* line number */
extern int assval; /* to create difference between literals
* and other terminals
extern t_token lextoken; /* the current token */
extern int nerrors;
extern string rec_file, incl_file;
+#ifdef NON_CORRECTING
+extern string nc_rec_file, nc_incl_file;
+#endif
extern int low_percentage, high_percentage;
extern int min_cases_for_jmptable;
extern int jmptable_option;
extern int ansi_c;
+#ifdef NON_CORRECTING
+extern int non_corr;
+extern int subpars_sim;
+extern p_gram illegal_gram;
+#endif
extern int strip_grammar;
+extern int in_production;
STATIC opentemp();
STATIC geninclude();
STATIC genrecovery();
+#ifdef NON_CORRECTING
+STATIC genncrecovery();
+#endif
STATIC string genname();
STATIC generate();
STATIC prset();
else {
fputs("#if __STDC__ || __cplusplus\n#define LL_ANSI_C 1\n#endif\n", fpars);
}
+#ifdef NON_CORRECTING
+ if (non_corr) fputs("#define LL_NON_CORR 1\n", fpars);
+#endif
fprintf(fpars, "#define LL_LEXI %s\n", lexical);
copyfile(incl_file);
}
gencode(argc) {
register p_file p = files;
-
+
/* Set up for code generation */
if ((fact = fopen(f_temp,"r")) == NULL) {
fatal(0,e_noopen,f_temp);
}
+#ifdef NON_CORRECTING
+ /* The non-correcting error recovery must be generated BEFORE
+ parser code is generated!!!! In case of conflict resolvers,
+ the code-generation process will delete conflicting symbols
+ from first and followsets, making them UNUSABLE for the
+ non-correcting error recovery code.
+ */
+ if (non_corr)
+ genncrecovery();
+#endif
/* For every source file .... */
while (argc--) {
/* Open temporary */
}
geninclude();
genrecovery();
+
fclose(fact);
}
}
fprintf(fpars, "#define %s_MAXTOKNO %d\n", prefix ? prefix : "LL",
maxno);
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ fprintf(fpars, "#define %sNONCORR\n", prefix ? prefix : "LL");
+ }
+#endif
doclose(fpars);
install(f_include, ".");
}
STATIC
genrecovery() {
- register FILE *f;
+ register FILE *f;
register p_token t;
register int *q;
register p_nont p;
i > 0 ? i : 1,
ntokens);
if (onerror) fprintf(f,"#define LL_USERHOOK %s\n", onerror);
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ fputs("static int nc_done = 0;\n", f);
+ fputs("static int err_seen = 0;\n", f);
+ }
+#endif
/* Now generate the routines that call the startsymbols */
fputs("#if LL_ANSI_C\n", f);
for (st = start; st; st = st->ff_next) {
for (st = start; st; st = st->ff_next) {
fprintf(f, "#if LL_ANSI_C\nvoid %s(void)\n#else\n%s()\n#endif\n", st->ff_name, st->ff_name);
p = &nonterms[st->ff_nont];
- fputs(" {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+2];\n\tLLnewlevel(s);\n\tLLread();\n", f);
+ fputs(" {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+2];", f);
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ fputs(" \n\tint oldstartsymb;", f);
+ fputs(" \n\tint oldncflag;", f);
+ fputs(" \n\toldstartsymb = LLstartsymb;", f);
+ fputs(" \n\toldncflag = nc_done;", f);
+ fputs(" \n\tnc_done = 0;", f);
+ fprintf(f, "\n\tLLstartsymb = %d;", st->ff_nont + assval);
+ }
+#endif
+ fputs("\n\tLLnewlevel(s);\n\tLLread();\n", f);
if (g_gettype(p->n_rule) == ALTERNATION) {
genpush(findindex(p->n_contains));
}
fputs("\tLL_NOSCANDONE(EOFILE);\n",f);
}
else fputs("\tLL_SCANDONE(EOFILE);\n",f);
- fputs("\tLLoldlevel(s);\n}\n",f);
+ fputs("\tLLoldlevel(s);\n",f);
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ fputs("\tLLstartsymb = oldstartsymb;\n", f);
+ fputs("\tif (nc_done == 1) { \n", f);
+ fputs("\t\terr_seen = 1;\n", f);
+ fputs("\tnc_done = oldncflag;\n", f);
+ fputs("\t}\n", f);
+ }
+#endif
+ fputs("}\n", f);
+
}
/* Now generate the sets */
fputs("static char LLsets[] = {\n",f);
install(f_rec, ".");
}
+#ifdef NON_CORRECTING
+STATIC
+genncrecovery() {
+ register FILE *f;
+ register p_token t;
+ register int *q;
+ int *index;
+
+ /* Generate the non-correcting error recovery file */
+
+ opentemp((string) 0);
+ f = fpars;
+
+ genhdr();
+ correct_prefix();
+ save_grammar(f);
+
+ fprintf(f, "#define LLFIRST_NT %d\n", assval);
+ fprintf(f, "#define LLSETSIZE %d\n", nbytes);
+
+ index = (int *) alloc((unsigned) (assval * sizeof(int)));
+ for (q = index; q < &index[assval];) *q++ = -1;
+ for (t = tokens; t < maxt; t++) {
+ index[t->t_tokno] = t - tokens;
+ }
+ fputs("#define LLindex (LL_index+1)\nstatic short LL_index[] = {0,0,\n",f);
+ for (q = index+1; q < &index[assval]; q++) {
+ fprintf(f, "%d,\n", *q);
+ }
+ fputs(c_arrend, f);
+ free((p_mem) index);
+
+ copyfile(nc_incl_file);
+ copyfile(nc_rec_file);
+
+ doclose(f);
+ install(f_nc, ".");
+}
+#endif
+
STATIC
generate(f) p_file f; {
/*
for (ff = f->f_firsts; ff; ff = ff->ff_next) {
macro(ff->ff_name,&nonterms[ff->ff_nont]);
}
-
+
/* For every nonterminal generate a function */
for (s = f->f_nonterminals; s != -1; s = p->n_next) {
p = &nonterms[s];
getparams() {
/* getparams is called if a nonterminal has parameters. The names
* of the parameters have to be found, and they should be declared
- */
+ */
long off;
register int l;
long ftell();
}
fputs(") ",fpars);
/*
- * Now copy the declarations
+ * Now copy the declarations
*/
l = getc(fact); /* patch: some implementations of fseek
do not work properly after "ungetc"
/* getansiparams is called if a nonterminal has parameters
* and an ANSI C function definition/declaration has to be produced.
* If a definition has to be produced, "mkdef" is set to 1.
- */
+ */
register int l;
int delayed = 0;
int term_is_persistent = (q->t_flags & PERSISTENT);
int ispushed = NOPOP;
- if (!(toplevel > 0 &&
+ if (!(toplevel > 0 &&
(safety == 0 || (!onerror && safety <= SAFESCANDONE)) &&
(rep_kind == OPT || (rep_kind == FIXED && rep_count == 0)))) {
ispushed = findindex(q->t_contains);
STATIC
gencases(tokenlist, caseno, compacted)
- int *tokenlist;
+ int *tokenlist;
{
/*
* setp points to a bitset indicating which cases must
* be generated.
- * YECH, the PCC compiler does not accept many cases without statements
- * inbetween, so after every case label an empty statement is
- * generated.
+ * YECH, the PCC compiler does not accept many cases without
+ * statements in between, so after every case label an empty
+ * statement is generated.
* The C-grammar used by PCC is really stupid on this point :
* it contains the rule
- * statement : label statement
+ * statement : label statement
* which is right-recursive, and as is well known, LALR parsers don't
- * handle these things very good.
+ * handle these things very well.
* The grammar should have been written :
- * labeledstatement : labels statement ;
+ * labeledstatement : labels statement ;
* labels : labels label | ;
*/
register p_token p;
(p->t_tokno < 0400 ? "/* case '%s' */\n" :
"/* case %s */\n") :
p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n"
- : "case /* %s */ %d : ;\n",
+ : "case /* %s */ %d : ;\n",
p->t_string, i);
}
}
register int i;
register FILE *f = fpars;
- fprintf(f, "static %s LL%d_tklist[] = {",
+ fprintf(f, "static %s LL%d_tklist[] = {",
casecnt <= 127 ? "char" : "short",
listno);
-
+
for (i = 0; i < ntokens; i++) {
fprintf(f, "%c%d,", i % 10 == 0 ? '\n': ' ', tokenlist[i]);
}
fprintf(f, "#define LLnewlevel %snewlevel\n", s);
fprintf(f, "#define LLoldlevel %soldlevel\n", s);
fprintf(f, "#define LLmessage %smessage\n", s);
+#ifdef NON_CORRECTING
+ fprintf(f, "#define LLnc_recovery %sncrecovery\n", s);
+ fprintf(f, "#define LLstartsymb %sstartsymb\n", s);
+#endif
}
fprintf(f, "#include \"%s\"\n", f_include);
}
int ntokens;
int nterms, nalts;
int norder, torder;
+#ifdef NON_CORRECTING
+int nsubstarts;
+p_set start_firsts;
+#endif
p_start start;
int linecount;
int assval;
FILE *fact;
char f_pars[] = PARSERFILE;
char f_temp[] = ACTFILE;
+#ifdef NON_CORRECTING
+char f_nc[20];
+#endif
char f_out[20];
string f_input;
char f_include[20];
t_token lextoken;
int nerrors;
string rec_file, incl_file;
+#ifdef NON_CORRECTING
+string nc_rec_file, nc_incl_file;
+#endif
int low_percentage = 10, high_percentage = 30;
int min_cases_for_jmptable = 8;
int jmptable_option;
int ansi_c = 0;
+#ifdef NON_CORRECTING
+int non_corr = 0;
+int subpars_sim = 0;
+p_gram illegal_gram;
+#endif
int strip_grammar = 0;
+int in_production; /* set when the parser is reading a production
+ rule.
+ */
# define ACTFILE "tempXXXXXX" /* temporary file to save actions */
# define HFILE "%spars.h" /* file for "#define's " */
# define RFILE "%spars.c" /* Error recovery */
-
+#ifdef NON_CORRECTING
+# define NCFILE "%sncor.c" /* Non-corrcting error recovery */
+#endif
extern FILE *finput;
extern FILE *fpars;
extern FILE *fact;
extern string f_input;
extern char f_include[];
extern char f_rec[];
+#ifdef NON_CORRECTING
+extern char f_nc[];
+#endif
main(argc,argv) register string argv[]; {
register string arg;
string libpath();
- char *beg_sbrk;
+ char *beg_sbrk = 0;
/* Initialize */
assval = 0400;
/* read options */
-
+
while (argc >= 2 && (arg = argv[1], *arg == '-')) {
while (*++arg) {
switch(*arg) {
fprintf(stderr,"duplicate -r flag\n");
exit(1);
}
- rec_file = ++arg;
+ rec_file = ++arg;
break;
case 'i':
case 'I':
fprintf(stderr,"duplicate -i flag\n");
exit(1);
}
- incl_file = ++arg;
+ incl_file = ++arg;
break;
#endif /* not NDEBUG */
case 'x':
case 'A':
ansi_c = 1;
continue;
+#ifdef NON_CORRECTING
+ case 'n':
+ case 'N':
+ non_corr = 1;
+ continue;
case 's':
case 'S':
+ subpars_sim = 1;
+ continue;
+#endif
+ case 'g':
+ case 'G':
strip_grammar = 1;
continue;
default:
if (verbose) beg_sbrk = sbrk(0);
+#ifdef NON_CORRECTING
+ if ((subpars_sim) && (!non_corr)) {
+ fprintf(stderr,"option -s illegal without -n, turned off\n");
+ subpars_sim = 0;
+ }
+#endif
+
/*
* Now check wether the sets should include nonterminals
*/
# ifndef NDEBUG
}
# endif
+#ifdef NON_CORRECTING
+ if (non_corr) {
+ nc_incl_file = libpath("nc_incl");
+ nc_rec_file = libpath ("nc_rec");
+ }
+#endif
mktemp(f_temp);
mktemp(f_pars);
if ((fact = fopen(f_temp,"w")) == NULL) {
*/
sprintf(f_include, HFILE, prefix ? prefix : "L");
sprintf(f_rec, RFILE, prefix ? prefix : "L");
+#ifdef NON_CORRECTING
+ if (non_corr)
+ sprintf(f_nc, NCFILE, prefix ? prefix : "L");
+#endif
setinit(ntneeded);
maxnt = &nonterms[nnonterms];
maxt = &tokens[ntokens];
/*
* There must be a start symbol!
*/
- if (start == 0) {
+ if (! nerrors && start == 0) {
fatal(linecount,"Missing %%start");
}
if (nerrors) comfatal();
}
/* VARARGS1 */
-error(lineno,s,t,u) string s,t,u; {
+error(lineno,s,t,u) string s,t,u; {
/*
* Just an error message
*/
}
/* VARARGS1 */
-warning(lineno,s,t,u) string s,t,u; {
+warning(lineno,s,t,u) string s,t,u; {
/*
* Just a warning
*/
register FILE *f;
if ((f = fopen(file,"r")) == NULL) {
- fatal(0,"Cannot open libraryfile, call an expert");
+ fatal(0,"Cannot open library file %s, call an expert",file);
}
while ((c = getc(f)) != EOF) putc(c,fpars);
fclose(f);
nont_info.i_esize = sizeof (t_nont);
nont_info.i_incr = 50;
search(TERMINAL,"EOFILE",ENTERING);
+#ifdef NON_CORRECTING
+ illegal_gram = search(TERMINAL,"LLILLEGAL",ENTERING);
+#endif
}
STATIC p_entry
p->h_name = str;
p->h_next = next;
p->h_type.g_lineno = linecount;
+#ifdef NON_CORRECTING
+ p->h_type.g_erroneous = 0;
+#endif
return p;
}
-string
+string
store(s) string s; {
/*
* Store a string s in the name table
"%s : is already defined",str);
}
p->h_type.g_lineno = linecount;
- return &(p->h_type);
+ return &(p->h_type);
}
}
p = newentry(store(str), h_root[i]);
h_root[i] = p;
if (type == TERMINAL || type == LITERAL) {
register p_token pt;
-
+
pt = (p_token) new_mem(&token_info);
tokens = (p_token) token_info.i_ptr;
pt->t_string = p->h_name;
if (str[2] == '\0') {
switch(str[1]) {
case 'n' :
- val = '\n';
+ val = '\n';
break;
case 'r' :
val = '\r';
val = '\b';
break;
case 'f' :
- val = '\f';
+ val = '\f';
break;
case 't' :
- val = '\t';
+ val = '\t';
break;
case '\'':
- val = '\'';
+ val = '\'';
break;
case '\\':
- val = '\\';
+ val = '\\';
break;
default :
- error(linecount,e_literal);
+ error(linecount,e_literal);
}
} else {
/*
val = 64*str[1] - 73*'0' +
8*str[2] + str[3];
}
- } else {
+ } else {
/*
* No escape in literal
*/
return &(p->h_type);
}
/*
- * type == NONTERM || type == UNKNOWN
+ * type == NONTERM || type == UNKNOWN
* UNKNOWN and not yet declared means : NONTERM
*/
{
OBJECTS = main.$(SUF) gencode.$(SUF) compute.$(SUF) LLgen.$(SUF) tokens.$(SUF) \
check.$(SUF) reach.$(SUF) global.$(SUF) name.$(SUF) sets.$(SUF) \
- Lpars.$(SUF) alloc.$(SUF) machdep.$(SUF) cclass.$(SUF)
+ Lpars.$(SUF) alloc.$(SUF) machdep.$(SUF) cclass.$(SUF) savegram.$(SUF)
CSRC = $(SRC_DIR)/main.c $(SRC_DIR)/gencode.c $(SRC_DIR)/compute.c \
$(SRC_DIR)/check.c $(SRC_DIR)/reach.c $(SRC_DIR)/global.c \
$(SRC_DIR)/name.c $(SRC_DIR)/sets.c $(SRC_DIR)/alloc.c \
- $(SRC_DIR)/machdep.c $(SRC_DIR)/cclass.c
+ $(SRC_DIR)/machdep.c $(SRC_DIR)/cclass.c $(SRC_DIR)/savegram.c
CFILES = LLgen.c tokens.c Lpars.c $(CSRC)
GFILES = $(SRC_DIR)/tokens.g $(SRC_DIR)/LLgen.g
FILES = $(SRC_DIR)/types.h $(SRC_DIR)/extern.h \
--- /dev/null
+/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
+ * All rights reserved.
+ */
+
+#ifdef NON_CORRECTING
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * savegram.c
+ * Save the input grammar for non-correcting error recovery
+ *
+ * Grammar rules are `flattened' by introducing anonymous nonterminals.
+ * [B]? becomes X; X: B | {empty}
+ * [B]+ becomes X: B Y; Y: X | {empty}
+ * [B]* becomes X; X: B X | {empty}
+ * [B | C] becomes X; X: B | C
+ * [B | C]* becomes X; X: B X | C X | {empty} etc.
+ */
+
+
+# include "types.h"
+# include "extern.h"
+# include "io.h"
+# include "assert.h"
+# include "sets.h"
+
+#define LLALT 9999
+
+static int nt_highest;
+extern int nbytes;
+extern p_mem alloc();
+extern p_set start_firsts;
+extern p_set setalloc();
+extern p_gram search();
+
+STATIC save_rule();
+STATIC save_set();
+
+/* t_list will contain terms to be `flattened' */
+static struct t_list {
+ p_term term;
+ int t_nt_num;
+} *t_list;
+
+/* Subparse list will contain symbols in %substart */
+static struct subparse_list {
+ p_gram sub_action;
+ int sub_nt_num;
+} *sub_list;
+
+/* Index in t_list */
+static int t_list_index;
+
+/* Index in subparse_list */;
+static int sub_list_index;
+
+/* File to save grammar to */
+static FILE *fgram;
+
+/* Nonterminal number to simulate parsers that get called in actions
+ used when LLgen called with -n -s options */
+int act_nt;
+
+save_grammar(f) FILE *f; {
+ /*
+ * Save the grammar
+ */
+ register p_nont p;
+ register p_start st;
+ register int nt_nr;
+
+ fgram = f;
+
+ /* Compute highest nonterminal nr. */
+ nt_highest = nnonterms + assval - 1;
+
+
+ /* Generate some constants in the grammar file */
+
+ /* Allocate terms list */
+ t_list = (struct t_list *) alloc((unsigned) nterms * sizeof(struct t_list));
+ t_list_index = 0;
+
+ sub_list = (struct subparse_list *) alloc(nsubstarts * sizeof(struct subparse_list));
+
+ fputs("static ", fgram);
+ fputs((prefix ? prefix : "LL"), fgram);
+ fputs("grammar[] = {\n", fgram);
+
+ /* Check if -n -s option is on */
+ if (subpars_sim) {
+
+ /* Allocate action simulation nt */
+
+ act_nt = ++nt_highest;
+
+ /* write simualtion rule */
+ fprintf(fgram, "/* Simulation rule */\n");
+ fprintf(fgram, "%d,\n", act_nt);
+
+ /* Put a firstset and a fake followset */
+ /* Followset optimization is not implemented for
+ -s because it would be hard, and does not
+ bring enough improvement to jutify the effort
+ */
+ save_set(start_firsts);
+ save_set(start_firsts);
+ /* Simulation rule procudes empty */
+ fprintf(fgram, "%d,\n", 1);
+ for (st = start; st; st = st->ff_next)
+ {
+ fprintf(fgram, "%d, %d, %d, \n", st->ff_nont + assval,
+ act_nt, LLALT);
+ }
+ fprintf(fgram, "%d, \n", 0);
+
+ }
+
+ /* Now process all rules */
+ for (p = nonterms, nt_nr = assval; p < maxnt; p++, nt_nr++) {
+ fprintf(fgram, "/* nr. %d %s */\n", nt_nr, p->n_name);
+ fprintf(fgram, "%d, ",nt_nr);
+ if (! p->n_rule) { /* undefined */
+ f_input = p->n_string;
+ error(p->n_lineno,"Nonterminal %s not defined",
+ p->n_name);
+ }
+
+ /* Save the first_set and follow set */
+ save_set(p->n_nc_first);
+ save_set(p->n_nc_follow);
+
+ if (p->n_flags & EMPTY)
+ fprintf(fgram, "%d,\n", 1);
+ else
+ fprintf(fgram, "%d,\n", 0);
+
+ save_rule(p->n_rule, 0);
+
+ fprintf(fgram, "%d,\n", 0);
+ }
+
+ /* Resolve terms, they are on t_list */
+
+ fprintf(fgram, "/* Fresh nonterminals */\n");
+
+ { int i;
+ for (i = 0; i < t_list_index; i++)
+ {
+
+ /* Terms of the form [] without + ? * or number produce
+ a NIL pointer in the term-list */
+ if ((t_list + i)->term == (struct term *) 0) {
+ continue;
+ }
+
+ fprintf(fgram, "%d, ", (t_list + i)->t_nt_num);
+
+ /* Save the first and follow sets */
+
+ save_set((t_list + i)->term->t_nc_first);
+ save_set((t_list + i)->term->t_nc_follow);
+
+ /* NOTE: A VARIABLE REPETITION COUNT TERMS RULE IS NOT
+ ALLOWED TO PRODUCE EMPTY IN LLGEN
+ */
+
+ switch(r_getkind((t_list + i)->term)) {
+ case FIXED:
+ /* Already done by repeating new nonterminal */
+
+ /* FIXED term-rule may produce empty */
+ if (empty((t_list +i)->term->t_rule))
+ fprintf(fgram, "%d,\n", 1);
+ else
+ fprintf(fgram, "%d,\n", 0);
+
+ save_rule((t_list + i)->term->t_rule, 0);
+ fprintf(fgram, "%d,\n", 0);
+ break;
+ case STAR:
+ /* Save the rule, appending the new lhs for this rule */
+
+ /* Star rules always produce empty */
+ fprintf(fgram, "1,\n");
+
+ save_rule((t_list + i)->term->t_rule,
+ (t_list + i)->t_nt_num);
+ fprintf(fgram, "%d,\n%d,\n", LLALT, 0);
+ /* ALT EMPTY*/
+ break;
+ case PLUS:
+ /* Save the rule appending a fresh nonterminal */
+
+ fprintf(fgram, "%d,\n", 0);
+
+ save_rule((t_list + i)->term->t_rule, ++nt_highest);
+ fprintf(fgram, "%d,\n", 0); /* EOR */
+ fprintf(fgram, "%d, ", nt_highest);
+ /* First set of the extra nonterm is same as
+ for the term */
+ /* Except that the new nonterm also produces empty ! */
+ save_set((t_list + i)->term->t_nc_first);
+ save_set((t_list + i)->term->t_nc_follow);
+ fprintf(fgram, "1,\n");
+ fprintf(fgram, "%d, ", (t_list+i)->t_nt_num);
+ fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
+ break;
+ case OPT:
+ fprintf(fgram, "1,\n");
+ save_rule((t_list + i)->term->t_rule, 0);
+ fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
+ break;
+ }
+ }
+ }
+
+ /* Resolve %substarts */
+ if (!subpars_sim) {
+ int i,s,check;
+ p_start ff, gg;
+ p_set temp_set;
+
+ for (i = 0; i < sub_list_index; i++) {
+ fprintf(fgram, "%d, ", (sub_list + i)->sub_nt_num);
+ /* Compute the first set */
+ temp_set = setalloc();
+ for (ff = g_getsubparse((sub_list + i)->sub_action);
+ ff; ff = ff->ff_next){
+ s = setunion(temp_set,
+ (&nonterms[ff->ff_nont])->n_first);
+ check = 0;
+ for (gg =start; gg; gg = gg->ff_next)
+ if (ff->ff_nont == gg->ff_nont)
+ check = 1;
+ if (check == 0)
+ warning((sub_list + i)->sub_action->g_lineno,
+ "\"%s\" is not a startsymbol",
+ (&nonterms[ff->ff_nont])->n_name);
+ }
+ save_set(temp_set);
+ save_set(temp_set);
+ free(temp_set);
+
+ /* Produces empty */
+ fprintf(fgram, "1,\n");
+
+ ff = g_getsubparse((sub_list + i)->sub_action);
+
+ for (; ff; ff = ff->ff_next)
+ fprintf(fgram, "%d, %d, %d, \n", ff->ff_nont + assval,
+ (sub_list + i)->sub_nt_num,
+ LLALT);
+ fprintf(fgram, "%d, \n", 0);
+ }
+ }
+
+ fprintf(fgram, "%d\n};\n", 0);
+ fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1);
+}
+
+STATIC
+save_rule(p, tail) register p_gram p; int tail; {
+/*
+ Walk through rule p, saving it. The non-terminal tail is
+ appended to the rule. It needs to be appended in this function
+ to process alt-rules correctly. Tail == 0 means don't append.
+ */
+
+ int in_alt;
+ int illegal_num;
+ /* Processing an alt needs some special care. When processing the
+ first alternative, we don't want to write the alt-code;
+ When appending something to the alt, it needs to be appended to
+ every alternative and not at the end of the rule.
+ */
+
+ /* Look up the ILLEGAL token number */
+ illegal_num = tokens[g_getcont(illegal_gram)].t_tokno;
+
+ in_alt = 0;
+ for (;;) {
+ switch(g_gettype(p)) {
+ case ALTERNATION :
+ if (in_alt)
+ fprintf(fgram, "%d,\n", LLALT);
+ else
+ in_alt = 1;
+ save_rule(g_getlink(p)->l_rule, tail);
+ break;
+ case TERM :
+ /* Make entry in term list */
+ (t_list + t_list_index)->term = g_getterm(p);
+ /* Test for [] without specifier */
+ if (g_getterm(p) == (struct term *) 0) {
+ t_list_index++;
+ break;
+ }
+ (t_list + t_list_index++)->t_nt_num = ++nt_highest;
+ fprintf(fgram, "%d, ", nt_highest);
+ /* Check if repetition, if so handle here */
+ if (r_getkind(g_getterm(p)) == FIXED)
+ {
+ int k;
+ for (k = 1; k < r_getnum(g_getterm(p)); k++)
+ fprintf(fgram, "%d, ", nt_highest);
+ }
+ break;
+ case NONTERM :
+ fprintf(fgram, "%d, ", g_getcont(p) + assval);
+ break;
+ case TERMINAL:
+ if (g_getcont(p) == g_getcont(illegal_gram)) {
+ /* %illegal. Ignore. */
+ break;
+ }
+ if (p->g_erroneous)
+ fprintf(fgram, "%d, ", illegal_num);
+ else
+ fprintf(fgram, "%d, ",
+ tokens[g_getcont(p)].t_tokno);
+ break;
+ case LITERAL:
+ if (p->g_erroneous)
+ fprintf(fgram, "%d, ", illegal_num);
+ else
+ fprintf(fgram, "%d, ",
+ tokens[g_getcont(p)].t_tokno);
+ break;
+ case ACTION:
+ if (subpars_sim) {
+ fprintf(fgram, "%d, ", act_nt);
+ }
+ else if (g_getsubparse(p)) {
+ /* Allocate nonterminal that will simulate
+ subparser
+ */
+ (sub_list + sub_list_index)->sub_nt_num =
+ ++nt_highest;
+ (sub_list + sub_list_index++)->sub_action = p;
+
+ fprintf(fgram, "%d, ", nt_highest);
+ }
+ break;
+ case EORULE :
+ if ((! in_alt) && tail )
+ /* If this rule is not an alt, append tail now.
+ If it is an alt, the recursive call of this function
+ has appended tail to each alternative
+ */
+ fprintf(fgram, "%d, ", tail);
+ return;
+ }
+ p++;
+ }
+}
+
+STATIC
+save_set(p) p_set p; {
+ register int k;
+ register unsigned i;
+ int j;
+
+ j = nbytes;
+ for (;;) {
+ i = (unsigned) *p++;
+ for (k = 0; k < sizeof(int); k++) {
+ fprintf(fgram,"0%o,",(int)(i & 0377));
+ i >>= 8;
+ if (--j == 0) {
+ fputs("\n",fgram);
+ return;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+#endif
extern p_set get_set();
extern int setunion();
extern int setintersect();
-extern setminus();
+extern setminus();
extern int setempty();
extern int findindex();
extern int setcount();
/*
* tokens.g
* Defines the tokens for the grammar of LLgen.
- * The lexical analyser and LLmessage are also included here.
+ * The lexical analyser and LLmessage are also included here.
*/
{
/* Here are defined : */
extern int scanner();
-extern LLmessage();
+extern LLmessage();
extern int input();
extern unput();
extern skipcomment();
# endif
STATIC string cpy();
STATIC string vallookup();
+STATIC copyact();
+
+static int nparams;
}
/* Classes */
-%token C_IDENT ; /* lextoken.t_string contains the identifier read */
+%token C_IDENT ; /* lextoken.t_string contains the identifier read */
%token C_NUMBER ; /* lextoken.t_num contains the number read */
%token C_LITERAL ; /* lextoken.t_string contains the literal read */
+%token C_EXPR ; /* A C expression (%if or %while) */
+%token C_PARAMS ; /* formal or actual parameters */
+%token C_ACTION ; /* a C action */
/* Keywords */
%token C_AVOID ;
%token C_PREFER ;
%token C_DEFAULT ;
+%token C_SUBSTART ;
+%token C_ERRONEOUS ;
+%token C_ILLEGAL ;
%lexical scanner ;
*/
static t_keyw resword[] = {
- { "token", C_TOKEN },
- { "avoid", C_AVOID },
+ { "token", C_TOKEN },
+ { "avoid", C_AVOID },
{ "prefer", C_PREFER },
{ "persistent", C_PERSISTENT },
{ "default", C_DEFAULT },
- { "if", C_IF },
- { "while", C_WHILE },
- { "first", C_FIRST },
- { "start", C_START },
+ { "if", C_IF },
+ { "while", C_WHILE },
+ { "first", C_FIRST },
+ { "start", C_START },
{ "lexical", C_LEXICAL },
{ "onerror", C_ONERROR },
{ "prefix", C_PREFIX },
- { 0, 0 }
+#ifdef NON_CORRECTING
+ { "substart", C_SUBSTART },
+ { "erroneous", C_ERRONEOUS },
+ { "illegal", C_ILLEGAL },
+#endif
+ { 0, 0 }
};
static t_token savedtok; /* to save lextoken in case of an insertion */
# ifdef LINE_DIRECTIVE
-static int nostartline; /* = 0 if at the start of a line */
+static int nostartline; /* = 0 if at the start of a line */
# endif
+STATIC
+copyact(ch1,ch2,flag,level) char ch1,ch2; {
+ /*
+ * Copy an action to file f. Opening bracket is ch1, closing bracket
+ * is ch2.
+ * If flag & 1, copy opening and closing parameters too.
+ * If flag & 2, don't allow ','.
+ */
+ static int text_seen = 0;
+ register FILE *f;
+ register ch; /* Current char */
+ register match; /* used to read strings */
+ int saved = linecount;
+ /* save linecount */
+ int sav_strip = strip_grammar;
+
+ f = fact;
+ if (ch1 == '{' || flag != 1) strip_grammar = 0;
+ if (!level) {
+ text_seen = 0;
+ nparams = 0; /* count comma's */
+ putc('\0',f);
+ fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
+ }
+ if (level || (flag & 1)) putc(ch1,f);
+ for (;;) {
+ ch = input();
+ if (ch == ch2) {
+ if (!level) {
+ if (text_seen) nparams++;
+ }
+ if (level || (flag & 1)) putc(ch,f);
+ if (strip_grammar != sav_strip) {
+ if (ch1 == '{' || flag != 1) putchar(ch);
+ }
+ strip_grammar = sav_strip;
+ return;
+ }
+ switch(ch) {
+ case ')':
+ case '}':
+ case ']':
+ error(linecount,"Parentheses mismatch");
+ break;
+ case '(':
+ text_seen = 1;
+ copyact('(',')',flag,level+1);
+ continue;
+ case '{':
+ text_seen = 1;
+ copyact('{','}',flag,level+1);
+ continue;
+ case '[':
+ text_seen = 1;
+ copyact('[',']',flag,level+1);
+ continue;
+ case '/':
+ ch = input();
+ unput(ch);
+ if (ch == '*') {
+ putc('/', f);
+ skipcomment(1);
+ continue;
+ }
+ ch = '/';
+ text_seen = 1;
+ break;
+ case ';':
+ case ',':
+ if (! level && text_seen) {
+ text_seen = 0;
+ nparams++;
+ if (ch == ',' && (flag & 2)) {
+ warning(linecount, "Parameters may not be separated with a ','");
+ ch = ';';
+ }
+ }
+ break;
+ case '\'':
+ case '"' :
+ /*
+ * watch out for brackets in strings, they do not
+ * count !
+ */
+ text_seen = 1;
+ match = ch;
+ putc(ch,f);
+ while((ch = input())) {
+ if (ch == match) break;
+ if (ch == '\\') {
+ putc(ch,f);
+ ch = input();
+ }
+ if (ch == '\n') {
+ error(linecount,"Newline in string");
+ unput(match);
+ }
+ putc(ch,f);
+ }
+ if (ch == match) break;
+ /* Fall through */
+ case EOF :
+ if (!level) error(saved,"Action does not terminate");
+ strip_grammar = sav_strip;
+ return;
+ default:
+ if (c_class[ch] != ISSPA) text_seen = 1;
+ }
+ putc(ch,f);
+ }
+}
+
scanner() {
/*
* Lexical analyser, what else
register char *p = ltext;
int reserved = 0; /* reserved word? */
char *max = <ext[LTEXTSZ - 1];
+ static int nextexpr;
+ int expect_expr = nextexpr;
+ long off;
+ nextexpr = 0;
if (savedtok.t_tokno) {
/* A token has been inserted.
* Now deliver the last lextoken again
}
# endif
switch(c_class[ch]) {
+ case ISACT :
+ if (ch == '{') {
+ copyact('{', '}', in_production, 0);
+ return C_ACTION;
+ }
+ assert(ch == '(');
+ if (expect_expr) {
+ copyact('(', ')', 1, 0);
+ return C_EXPR;
+ }
+ off = ftell(fact);
+ copyact('(', ')', in_production != 0 ? 0 : 2, 0);
+ if (nparams == 0) fseek(fact, off, 0);
+ lextoken.t_num = nparams;
+ return C_PARAMS;
case ISLIT :
for (;;) {
ch = input();
unput(ch);
*p = '\0';
if (reserved) { /*
- * Now search for the keyword
+ * Now search for the keyword
*/
register p_keyw w;
/*
* Return token number.
*/
+ if (w->w_value == C_IF ||
+ w->w_value == C_WHILE) {
+ nextexpr = 1;
+ }
return w->w_value;
}
w++;
*/
register c;
- if (c = backupc) {
+ if (c = backupc) {
/* Last char was "unput()". Deliver it again
*/
backupc = 0;
- return c;
+ return c;
}
if ((c = getc(finput)) == EOF) {
nonline = 0;
register string t = 0;
switch(s) {
- case C_IDENT :
+ case C_IDENT :
if (!inserted) t = lextoken.t_string;
else t = "identifier";
break;
t = "literal";
break;
case EOFILE :
- t = "endoffile";
+ t = "end-of-file";
break;
}
if (!t && (t = vallookup(s))) {
case '\r' : *p++ = 'r'; break;
case '\t' : *p++ = 't'; break;
default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07);
- *p++='0'+(s&07);
+ *p++='0'+(s&07);
}
}
*p++ = '\'';
return p;
}
+string strcpy();
+
LLmessage(d) {
/*
* d is either 0, in which case the current token has been deleted,
nerrors++;
s = buf;
- if (d == 0) {
- s = cpy(LLsymb,s,0);
+ if (d < 0) {
+ strcpy(buf, "end-of-file expected");
+ }
+ else if (d == 0) {
+#ifdef LLNONCORR
+ t = " unexpected";
+#else
t = " deleted";
+#endif
+ s = cpy(LLsymb,s,0);
do *s++ = *t; while (*t++);
} else {
s = cpy(d,s,1);
s = cpy(LLsymb,s,0);
*s = '\0';
}
- error(linecount, "%s", buf);
- /* Don't change this line to
- * error(linecount, buf).
- * The string in "buf" might contain '%' ...
- */
- if (d) { /*
+ if (d > 0) { /*
* Save the current token and make up some
* attributes for the inserted token
*/
else if (d == C_LITERAL) lextoken.t_string = "dummy_literal";
else if (d == C_NUMBER) lextoken.t_num = 1;
}
+#ifdef LLNONCORR
+ else
+#endif
+ error(linecount, "%s", buf);
+ /* Don't change this line to
+ * error(linecount, buf).
+ * The string in "buf" might contain '%' ...
+ */
+#ifdef LLNONCORR
+ in_production = 1;
+ /* To prevent warnings from copyact */
+#endif
}
}
* structure for the grammar elements
*/
typedef struct gram {
- short x; /* for lay-out see comment below */
- short g_lineno; /* element found on this line number */
+ int x; /* for lay-out see comment below */
+ int g_lineno; /* element found on this line number */
+#ifdef NON_CORRECTING
+ int g_erroneous; /* 1 if element declared erroneous */
+#endif
union {
int g_index;
struct term * g_term;
struct link * g_link;
+#ifdef NON_CORRECTING
+ /* If this is an action with a %substart g_subparse
+ points to the list of startsymbols of the subparser */
+ struct ff_firsts *g_subparse;
+#endif
} g_i;
} t_gram,*p_gram;
# define g_setterm(p,s) ((p)->g_i.g_term = (s))
# define g_setlink(p,s) ((p)->g_i.g_link = (s))
# define g_setnpar(p,s) { assert(((unsigned)(s))<=017);(p)->x=((p)->x&~0170)|((s)<<3);}
-
+#ifdef NON_CORRECTING
+# define g_getsubparse(p) ((p)->g_i.g_subparse)
+# define g_setsubparse(p,s) ((p)->g_i.g_subparse = (s))
+#endif
/*
* Some constants to communicate with the symbol table search routine
*/
* nonterminal structure
*/
typedef struct {
- short n_flags; /* low order four bits are reserved
+ int n_flags; /* low order four bits are reserved
* the parameter count
*/
# define getntparams(p) ((p)->n_flags&017)
# define RECURSIVE 02000 /* Set if the default rule is recursive */
# define PARAMS 04000 /* tells if a nonterminal has parameters */
# define EMPTY 010000 /* tells if a nonterminal produces empty */
-# define LOCALS 020000 /* local declarations ? */
+# define LOCALS 020000 /* local declarations ? */
# define REACHABLE 040000 /* can this nonterminal be reached ? */
# define VERBOSE 0100000 /* Set if in LL.output file */
char n_insafety;
# define setntsafe(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_insafety=(i);}
# define getntout(p) ((p)->n_outsafety)
# define setntout(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_outsafety=(i);}
- short n_count; /* pieces of code before this rule */
- short n_lineno; /* declared on line ... */
+ int n_count; /* pieces of code before this rule */
+ int n_lineno; /* declared on line ... */
p_gram n_rule; /* pointer to right hand side of rule */
union {
p_set n_f; /* ptr to "first" set */
} n_x;
# define n_first n_x.n_f
# define n_string n_x.n_s
+#ifdef NON_CORRECTING
+ p_set n_nc_first; /* Pointer to non-corr first set */
+ p_set n_nc_follow; /* Pointer to non-corr follow set */
+#endif
p_set n_follow; /* pointer to the "follow" set */
p_set n_contains; /* pointer to symbols that can be produced */
string n_name; /* name of nonterminal */
long n_off; /* index of parameters in action file */
} t_nont, *p_nont;
-/*
+/*
* hash table structure
*/
typedef struct h_entry {
*/
p_gram l_rule; /* pointer to this rule */
p_set l_symbs; /* set, when to take this rule */
+#ifdef NON_CORRECTING
+ p_set l_nc_symbs;
+#endif
p_set l_others; /* set, when to take another rule */
} t_link, *p_link;
/*
* Structure for a repitition specification
*/
-typedef short t_reps,*p_reps;
+typedef int t_reps,*p_reps;
# define FIXED 00 /* a fixed number */
# define STAR 01 /* 0 or more times */
*/
typedef struct term {
t_reps t_repeats;
- short t_flags; /* Low order three bits for safety */
+ int t_flags; /* Low order three bits for safety */
# define gettout(q) ((q)->t_flags&07)
# define settout(q,i) {assert(((unsigned)(i))<=NOSAFETY);(q)->t_flags&=~07;(q)->t_flags|=i;}
# define PERSISTENT 010 /* Set if this term has %persistent */
p_gram t_rule; /* pointer to this term */
p_set t_follow; /* set of followers */
p_set t_first; /* set of firsts */
+#ifdef NON_CORRECTING
+ p_set t_nc_first; /* set of non corr firsts */
+ p_set t_nc_follow; /* set of non corr followers */
+#endif
p_set t_contains; /* contains set */
} t_term, *p_term;