1 /* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
2 * For full copyright and restrictions on use see the file COPYING in the top
3 * level of the LLgen tree.
9 * An Extended LL(1) Parser Generator
11 * Author : Ceriel J.H. Jacobs
16 * Several routines to perform checks and printouts
26 static string rcsid1 = "$Id: check.c,v 2.14 1997/02/21 11:27:45 ceriel Exp $";
29 static string c_first = "> firstset ";
30 static string c_contains = "> containset ";
31 static string c_follow = "> followset ";
35 /* In this file are defined : */
49 * Check for conflicts, that is,
50 * in a repeating term, the FIRST and FOLLOW must be disjunct,
51 * unless there is a disambiguating condition.
52 * in an alternation, the sets that determine the direction to take,
61 for (p = nonterms; p < maxnt; p++) p->n_flags |= VERBOSE;
64 if ((fout = fopen(f_out,"w")) == NULL) fatal(1,e_noopen,f_out);
67 * Check the rules in the order in which they are declared,
68 * and input file by input file, to give proper error messages
70 for (; x < maxfiles; x++) {
72 for (s = x->f_nonterminals; s != -1; s = p->n_next) {
74 if (check(p->n_rule)) p->n_flags |= VERBOSE;
77 for (x = files; x < maxfiles; x++) {
79 for (s = x->f_nonterminals; s != -1; s = p->n_next) {
81 if (p->n_flags & RECURSIVE) {
83 "Recursion in default for nonterminal %s",
87 * If a printout is needed for this rule in
88 * LL.output, just do it
90 if (verbose && (p->n_flags & VERBOSE)) {
91 fprintf(fout,"\n%s :\n",p->n_name);
92 printset(p->n_first,c_first);
93 printset(p->n_contains,c_contains);
94 printset(p->n_follow,c_follow);
95 fprintf(fout,"> rule%s\n\t",
96 p->n_flags&EMPTY ? "\t(EMPTY producing)" : "");
103 * Now, the conflicts may be resolved
108 if (verbose) fclose(fout);
118 printset(p,s) register p_set p; string s; {
120 * Print the elements of a set
129 k = strlen(s) + 2 + level;
131 * k contains relative level of indentation
133 fprintf(fout,"%s{ ",s);
136 * j will gather the total length of the line
138 for (i = 0, pt = tokens; i < ntokens; i++,pt++) {
140 hulp = strlen(pt->t_string)+1;
141 if (pt->t_tokno < 0400) hulp += 2;
142 if ((j += hulp) >= 78) {
144 * Line becoming too long
148 fprintf(fout,">%*c",k - level - 1,' ');
150 fprintf(fout, pt->t_tokno<0400 ? "'%s' " : "%s ",pt->t_string);
153 if (ntprint) for (i = 0; i < nnonterms; i++) {
155 * Nonterminals in the set must also be printed
158 name = nonterms[i].n_name;
159 hulp = strlen(name) + 3;
160 if ((j += hulp) >= 78) {
163 fprintf(fout,">%*c",k - level - 1,' ');
165 fprintf(fout,"<%s> ",name);
172 check(p) register p_gram p; {
174 * Search for conflicts in a grammar rule.
181 switch (g_gettype(p)) {
187 n = &nonterms[g_getcont(p)];
188 if (g_getnpar(p) != getntparams(n)) {
190 "Call of %s: parameter count mismatch",
198 retval |= check(q->t_rule);
199 if (r_getkind(q) == FIXED) break;
200 if (setempty(q->t_first)) {
201 q->t_flags |= EMPTYFIRST;
203 error(p->g_lineno, "No symbols in term");
205 if (empty(q->t_rule)) {
206 q->t_flags |= EMPTYTERM;
208 error(p->g_lineno, "Term with variable repetition count produces empty");
211 setunion(temp,q->t_first);
212 if (!setintersect(temp,q->t_follow)) {
214 * q->t_first * q->t_follow != EMPTY
216 if (!(q->t_flags & RESOLVER)) {
218 * No conflict resolver
221 "Repetition conflict");
227 if (q->t_flags & RESOLVER) {
228 q->t_flags |= NOCONF;
230 "%%while without conflict");
240 setunion(temp,l->l_symbs);
241 if(!setintersect(temp,l->l_others)) {
243 * temp now contains the conflicting
246 if (!(l->l_flag & (COND|PREFERING|AVOIDING))) {
248 "Alternation conflict");
253 if (l->l_flag & (COND|PREFERING|AVOIDING)) {
256 "Conflict resolver without conflict");
260 if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
261 retval |= check(l->l_rule);
269 moreverbose(t) register p_set t; {
271 * t points to a set containing conflicting symbols and pssibly
272 * also containing nonterminals.
273 * Take care that a printout will be prepared for these nonterminals
278 if (verbose == 2) for (i = 0, p = nonterms; i < nnonterms; i++, p++) {
279 if (NTIN(t,i)) p->n_flags |= VERBOSE;
284 prrule(p) register p_gram p; {
286 * Create a verbose printout of grammar rule p
294 switch (g_gettype(p)) {
303 if (present) prline("\n");
306 if (q->t_flags & RESOLVER) {
307 prline("%while (..)\n");
309 if (q->t_flags & PERSISTENT) {
310 prline("%persistent\n");
312 if (r_getkind(q) != FIXED) {
313 if (!(q->t_flags & PERSISTENT)) {
314 prline("> continue repetition on the\n");
316 printset(q->t_first, c_first);
317 if (q->t_flags & PERSISTENT) {
318 prline("> continue repetition on the\n");
320 printset(q->t_contains, c_contains);
321 prline("> terminate repetition on the\n");
322 printset(q->t_follow,c_follow);
323 if (q->t_flags & EMPTYFIRST) {
324 prline(">>> empty first\n");
326 if (q->t_flags & EMPTYTERM) {
327 prline(">>> term produces empty\n");
329 cfcheck(q->t_first,q->t_follow,
330 q->t_flags & RESOLVER);
336 fputs(c == STAR ? "]*" : c == PLUS ? "]+" :
337 c == OPT ? "]?" : "]", f);
338 if (c = r_getnum(q)) {
354 printset(l->l_symbs,"> alternative on ");
357 (int)(l->l_flag&(COND|PREFERING|AVOIDING)));
360 if (l->l_flag & DEF) {
361 prline("%default\n");
363 if (l->l_flag & AVOIDING) {
366 if (l->l_flag & PREFERING) {
369 if (l->l_flag & COND) {
370 prline("%if ( ... )\n");
374 if (g_gettype(p+1) == EORULE) {
381 register p_token pt = &tokens[g_getcont(p)];
383 fprintf(f,pt->t_tokno<0400 ?
384 "'%s' " : "%s ", pt->t_string);
387 fprintf(f,"%s ",nonterms[g_getcont(p)].n_name);
396 cfcheck(s1,s2,flag) p_set s1,s2; {
398 * Check if s1 and s2 have elements in common.
399 * If so, flag must be non-zero, indicating that there is a
400 * conflict resolver, otherwise, flag must be zero, indicating
407 if (!setintersect(temp,s2)) {
409 printset(temp,">>> conflict on ");
414 prline(">>> %if/%while, no conflict\n");
421 resolve(p) register p_gram p; {
423 * resolve conflicts, as specified by the user
426 switch (g_gettype(p)) {
430 resolve(g_getterm(p)->t_rule);
436 if (l->l_flag & AVOIDING) {
438 * On conflicting symbols, this rule
441 setminus(l->l_symbs,l->l_others);
443 if (setempty(l->l_symbs)) {
445 * This may be caused by the statement above
447 error(p->g_lineno,"Alternative never chosen");
457 propagate(set,p) p_set set; register p_gram p; {
459 * Propagate the fact that on the elements of set the grammar rule
460 * p will not be chosen.
462 while (g_gettype(p) != EORULE) {
463 setminus(g_getlink(p)->l_symbs,set);
471 if (level > 0) fprintf(fout,"%*c",level,' ');