1984-10-08 14:14:53 +00:00
|
|
|
/*
|
1987-03-10 01:26:51 +00:00
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
1984-10-08 14:14:53 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* L L G E N
|
|
|
|
*
|
|
|
|
* An Extended LL(1) Parser Generator
|
|
|
|
*
|
|
|
|
* Author : Ceriel J.H. Jacobs
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* reach.c
|
|
|
|
* Determine which nonterminals are reachable, and also check that they
|
|
|
|
* are all defined.
|
|
|
|
*/
|
|
|
|
|
|
|
|
# include "types.h"
|
|
|
|
# include "extern.h"
|
|
|
|
# include "io.h"
|
|
|
|
# include "assert.h"
|
|
|
|
|
1984-10-08 17:11:03 +00:00
|
|
|
# ifndef NORCSID
|
|
|
|
static string rcsid8 = "$Header$";
|
|
|
|
# endif
|
1984-10-08 14:14:53 +00:00
|
|
|
|
|
|
|
/* In this file the following routines are defined: */
|
|
|
|
extern co_reach();
|
|
|
|
STATIC reachable();
|
|
|
|
STATIC reachwalk();
|
|
|
|
|
|
|
|
co_reach() {
|
|
|
|
/*
|
|
|
|
* Check for undefined or unreachable nonterminals.
|
|
|
|
* An undefined nonterminal is a fatal error!
|
|
|
|
*/
|
|
|
|
register p_nont p;
|
|
|
|
register p_start st;
|
1985-11-25 15:47:51 +00:00
|
|
|
register p_file x;
|
|
|
|
register p_order s;
|
1984-10-08 14:14:53 +00:00
|
|
|
|
|
|
|
/* Check for undefined nonterminals */
|
|
|
|
for (p = nonterms; p < maxnt; p++) {
|
1985-11-25 15:47:51 +00:00
|
|
|
if (! p->n_rule) { /* undefined */
|
1984-10-08 14:14:53 +00:00
|
|
|
f_input = p->n_string;
|
1984-10-11 10:35:01 +00:00
|
|
|
error(p->n_lineno,"nonterminal %s not defined",
|
1985-11-25 15:47:51 +00:00
|
|
|
p->n_name);
|
1984-10-08 14:14:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Walk the grammar rules, starting with the startsymbols
|
|
|
|
* Mark the nonterminals that are encountered with the flag
|
|
|
|
* REACHABLE, and walk their rules, if not done before
|
|
|
|
*/
|
1985-11-25 15:47:51 +00:00
|
|
|
for (st = start; st; st = st->ff_next) {
|
|
|
|
reachable(&nonterms[st->ff_nont]);
|
|
|
|
}
|
1984-10-08 14:14:53 +00:00
|
|
|
/*
|
|
|
|
* Now check for unreachable nonterminals
|
|
|
|
*/
|
1985-11-25 15:47:51 +00:00
|
|
|
for (x = files; x < maxfiles; x++) {
|
1984-10-08 14:14:53 +00:00
|
|
|
f_input = x->f_name;
|
1985-11-25 15:47:51 +00:00
|
|
|
for (s = x->f_list; s; s = s->o_next) {
|
|
|
|
p = &nonterms[s->o_index];
|
1984-10-08 14:14:53 +00:00
|
|
|
if (! (p->n_flags & REACHABLE)) {
|
|
|
|
error(p->n_lineno,"nonterminal %s unreachable",
|
1985-11-25 15:47:51 +00:00
|
|
|
p->n_name);
|
1984-10-08 14:14:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
reachable(p) register p_nont p; {
|
|
|
|
/*
|
|
|
|
* Enter the fact that p is reachable, and look for implications
|
|
|
|
*/
|
|
|
|
if (! (p->n_flags & REACHABLE)) {
|
|
|
|
p->n_flags |= REACHABLE;
|
|
|
|
/*
|
|
|
|
* Now walk its grammar rule
|
|
|
|
*/
|
1984-10-11 10:35:01 +00:00
|
|
|
if (p->n_rule) reachwalk(p->n_rule);
|
1984-10-08 14:14:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
reachwalk(p) register p_gram p; {
|
|
|
|
/*
|
|
|
|
* Walk through rule p, looking for nonterminals.
|
|
|
|
* The nonterminals found are entered as reachable
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
switch(g_gettype(p)) {
|
|
|
|
case ALTERNATION :
|
1985-11-25 15:47:51 +00:00
|
|
|
reachwalk(links[g_getcont(p)].l_rule);
|
1984-10-08 14:14:53 +00:00
|
|
|
break;
|
|
|
|
case TERM :
|
1985-11-25 15:47:51 +00:00
|
|
|
reachwalk(terms[g_getcont(p)].t_rule);
|
1984-10-08 14:14:53 +00:00
|
|
|
break;
|
|
|
|
case NONTERM :
|
|
|
|
reachable(&nonterms[g_getnont(p)]);
|
|
|
|
break;
|
|
|
|
case EORULE :
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|