xref: /csrg-svn/usr.bin/pascal/src/yyrecover.c (revision 15022)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 #ifndef lint
4 static char sccsid[] = "@(#)yyrecover.c 1.5 09/19/83";
5 #endif
6 
7 #include "whoami.h"
8 #include "0.h"
9 #include "tree_ty.h"	/* must be included for yy.h */
10 #include "yy.h"
11 
12 /*
13  * Very simplified version of Graham-Rhodes error recovery
14  * method for LALR parsers.  Backward move is embodied in
15  * default reductions of the yacc parser until an error condition
16  * is reached.  Forward move is over a small number of input tokens
17  * and cannot "condense".  The basic corrections are:
18  *
19  *	1) Delete the input token.
20  *
21  *	2) Replace the current input with a legal input.
22  *
23  *	3) Insert a legal token.
24  *
25  * All corrections are weighted, considered only if they allow
26  * at least two shifts, and the cost of a correction increases if
27  * it allows shifting over only a part of the lookahead.
28  *
29  * Another error situation is that which occurs when an identifier "fails"
30  * a reduction because it is not the required "class".
31  * In this case, we also consider replacing this identifier, which has
32  * already been shifted over, with an identifier of the correct class.
33  *
34  * Another correction performed here is unique symbol insertion.
35  * If the current state admits only one input, and no other alternative
36  * correction presents itself, then that symbol will be inserted.
37  * There is a danger in this of looping, and it is handled
38  * by counting true shifts over input (see below).
39  *
40  *
41  * A final class of corrections, considered only when the error
42  * occurred immediately after a shift over a terminal, involves
43  * the three basic corrections above, but with the point of error
44  * considered to be before this terminal was shifted over, effectively
45  * "unreading" this terminal.  This is a feeble attempt at elimination
46  * of the left-right bias and because "if" has a low weight and some
47  * statements are quite simple i.e.
48  *
49  *	cse ch of ...
50  *
51  * we can get a small number of errors.  The major deficiency of
52  * this is that we back up only one token, and that the forward
53  * move is over a small number of tokens, often not enough to really
54  * tell what the input should be, e.g. in
55  *
56  *	a[i] > a[i - 1] ...
57  *
58  * In such cases a bad identifier (misspelled keyword) or omitted
59  * keyword will be change or inserted as "if" as it has the lowest cost.
60  * This is not terribly bad, as "if"s are most common.
61  * This also allows the correction of other errors.
62  *
63  * This recovery depends on the default reductions which delay
64  * noticing the error until the parse reaches a state where the
65  * relevant "alternatives" are visible.  Note that it does not
66  * consider tokens which will cause reductions before being
67  * shifted over.  This requires the grammar to be written in a
68  * certain way for the recovery to work correctly.
69  * In some sense, also, the recovery suffers because we have
70  * LALR(1) tables rather than LR(1) tables, e.g. in
71  *
72  *	if rec.field < rec2,field2 then
73  */
74 
75 /*
76  * Definitions of possible corrective actions
77  */
78 #define	CPANIC		0
79 #define	CDELETE		1
80 #define	CREPLACE	2
81 #define	CINSERT		3
82 #define	CUNIQUE		4
83 #define	CCHIDENT	5
84 
85 /*
86  * Multiplicative cost factors for corrective actions.
87  *
88  * When an error occurs we take YCSIZ - 1 look-ahead tokens.
89  * If a correction being considered will shift over only part of
90  * that look-ahead, it is not completely discarded, but rather
91  * "weighted", its cost being multiplied by a weighting factor.
92  * For a correction to be considered its weighted cost must be less
93  * than CLIMIT.
94  *
95  * Non-weighted costs are considered:
96  *
97  *	LOW	<= 3
98  *	MEDIUM	4,5
99  *	HIGH	>= 6
100  *
101  * CURRENT WEIGHTING STRATEGY: Aug 20, 1977
102  *
103  * For all kinds of corrections we demand shifts over two symbols.
104  * Corrections have high weight even after two symbol
105  * shifts because the costs for deleting and inserting symbols are actually
106  * quite low; we do not want to change weighty symbols
107  * on inconclusive evidence.
108  *
109  * The weights are the same after the third look ahead.
110  * This prevents later, unrelated errors from causing "funny"
111  * biases of the weights toward one type of correction.
112  *
113  * Current look ahead is 5 symbols.
114  */
115 
116 /*** CLIMIT is defined in yy.h for yycosts ***/
117 #define	CPRLIMIT	50
118 #define	CCHIDCOST	3
119 
120 char	insmult[8]	= {INFINITY, INFINITY, INFINITY, 15, 8, 6, 3, 1};
121 char	repmult[7]	= {INFINITY, INFINITY, INFINITY, 8, 6, 3, 1};
122 char	delmult[6]	= {INFINITY, INFINITY, INFINITY, 6, 3, 1};
123 
124 #define	NOCHAR	-1
125 
126 #define	Eprintf	if (errtrace) printf
127 #define	Tprintf	if (testtrace) printf
128 
129 /*
130  * Action arrays of the parser needed here
131  */
132 union semstack *yypv;
133 int		yyact[], yypact[];
134 
135 /*
136  * Yytips is the tip of the stack when using
137  * the function loccor to check for local
138  * syntactic correctness. As we don't want
139  * to copy the whole parser stack, but want
140  * to simulate parser moves, we "split"
141  * the parser stack and keep the tip here.
142  */
143 #define	YYTIPSIZ 16
144 int	yytips[YYTIPSIZ], yytipct;
145 int	yytipv[YYTIPSIZ];
146 
147 /*
148  * The array YC saves the lookahead tokens for the
149  * forward moves.
150  * Yccnt is the number of tokens in the YC array.
151  */
152 #define	YCSIZ	6
153 
154 int	yCcnt;
155 struct	yytok YC0[YCSIZ + 1];
156 struct	yytok *YC;
157 
158 /*
159  * YCps gives the top of stack at
160  * the point of error.
161  */
162 
163 bool	yyunique = TRUE;
164 
165 STATIC	unsigned yyTshifts;
166 
167 /*
168  * Cact is the corrective action we have decided on
169  * so far, ccost its cost, and cchar the associated token.
170  * Cflag tells if the correction is over the previous input token.
171  */
172 int	cact, ccost, cchar, cflag;
173 
174 /*
175  * ACtok holds the token under
176  * consideration when examining
177  * the lookaheads in a state.
178  */
179 struct	yytok ACtok;
180 
181 #define acchar	ACtok.Yychar
182 #define aclval	ACtok.Yylval
183 
184 /*
185  * Make a correction to the current stack which has
186  * top of stack pointer Ps.
187  */
188 yyrecover(Ps0, idfail)
189 	int *Ps0, idfail;
190 {
191 	register int c, i;
192 	int yyrwant, yyrhave;
193 
194 #ifdef PI
195 	Recovery = TRUE;
196 #endif
197 
198 	YC = &YC0[1];
199 #ifdef DEBUG
200 	if (errtrace) {
201 		setpfx('p');
202 		yerror("Point of error");
203 		printf("States %d %d ...", Ps0[0], Ps0[-1]);
204 		if (idfail)
205 			printf(" [Idfail]");
206 #ifdef PXP
207 		putchar('\n');
208 #else
209 		pchr('\n');
210 #endif
211 		printf("Input %s%s", tokname(&Y , 0)
212 				   , tokname(&Y , 1));
213 	}
214 
215 #endif
216 	/*
217 	 * We first save the current input token
218 	 * and its associated semantic information.
219 	 */
220 	if (yychar < 0)
221 		yychar = yylex();
222 	copy((char *) (&YC[0]), (char *) (&Y), sizeof Y);
223 
224 	/*
225 	 * Set the default action and cost
226 	 */
227 	cact = CPANIC, ccost = CLIMIT, cflag = 0;
228 
229 	/*
230 	 * Peek ahead
231 	 */
232 	for (yCcnt = 1; yCcnt < YCSIZ; yCcnt++) {
233 		yychar = yylex();
234 		copy((char *) (&YC[yCcnt]), (char *) (&Y), sizeof YC[0]);
235 #ifdef DEBUG
236 		Eprintf(" | %s%s", tokname(&YC[yCcnt] , 0 )
237 				 , tokname(&YC[yCcnt] , 1 ));
238 #endif
239 	}
240 #ifdef DEBUG
241 	Eprintf("\n");
242 #endif
243 
244 	/*
245 	 * If we are here because a reduction failed, try
246 	 * correcting that.
247 	 */
248 	if (idfail) {
249 		/*
250 		 * Save the particulars about
251 		 * the kind of identifier we want/have.
252 		 */
253 		yyrwant = yyidwant;
254 		yyrhave = yyidhave;
255 #ifdef DEBUG
256 		Tprintf("  Try Replace %s identifier with %s identifier cost=%d\n",
257 		    classes[yyidhave], classes[yyidwant], CCHIDCOST);
258 #endif
259 
260 		/*
261 		 * Save the semantics of the ID on the
262 		 * stack, and null them out to free
263 		 * up the reduction in question.
264 		 */
265 		i = yypv[0].i_entry;
266 		yypv[0].i_entry = nullsem(YID);
267 		c = correct(NOCHAR, 0, CCHIDCOST, &repmult[2], Ps0,
268 				(int *) yypv);
269 		yypv[0].i_entry = i;
270 #ifdef DEBUG
271 		if (c < CPRLIMIT || fulltrace)
272 			Eprintf("Cost %2d Replace %s identifier with %s identifier\n", c, classes[yyrhave], classes[yyrwant]);
273 #endif
274 		if (c < ccost)
275 			cact = CCHIDENT, ccost = c, cchar = YID;
276 	}
277 
278 	/*
279 	 * First try correcting the state we are in
280 	 */
281 	trystate(Ps0, (int *) yypv, 0, &insmult[1], &delmult[1], &repmult[1]);
282 
283 	/*
284 	 * Now, if we just shifted over a terminal, try
285 	 * correcting it.
286 	 */
287 	if (OY.Yychar != -1 && OY.Yylval != nullsem(OY.Yychar)) {
288 		YC--;
289 		copy((char *) (&YC[0]), (char *) (&OY), sizeof YC[0]);
290 		trystate(Ps0 - 1, (int *) (yypv - 1), 1, insmult, delmult,
291 				repmult);
292 		if (cflag == 0)
293 			YC++;
294 		else {
295 			yypv--;
296 #ifdef PXP
297 			yypw--;
298 #endif
299 			Ps0--;
300 			yCcnt++;
301 		}
302 	}
303 
304 	/*
305 	 * Restoring the first look ahead into
306 	 * the scanner token allows the error message
307 	 * routine to print the error message with the text
308 	 * of the correct line.
309 	 */
310 	copy((char *) (&Y), (char *) (&YC[0]), sizeof Y);
311 
312 	/*
313 	 * Unique symbol insertion.
314 	 *
315 	 * If there was no reasonable correction found,
316 	 * but only one input to the parser is acceptable
317 	 * we report that, and try it.
318 	 *
319 	 * Special precautions here to prevent looping.
320 	 * The number of true inputs shifted over at the point
321 	 * of the last unique insertion is recorded in the
322 	 * variable yyTshifts.  If this is not less than
323 	 * the current number in yytshifts, we do not insert.
324 	 * Thus, after one unique insertion, no more unique
325 	 * insertions will be made until an input is shifted
326 	 * over.  This guarantees termination.
327 	 */
328 	if (cact == CPANIC && !idfail) {
329 		register int *ap;
330 
331 		ap = &yyact[yypact[*Ps0 + 1]];
332 		if (*ap == -ERROR)
333 			ap += 2;
334 		if (ap[0] <= 0 && ap[2] > 0) {
335 			cchar = -ap[0];
336 			if (cchar == YEOF)
337 				yyexeof();
338 			if (cchar != ERROR && yyTshifts < yytshifts) {
339 				cact = CUNIQUE;
340 #ifdef DEBUG
341 				Eprintf("Unique symbol %s%s\n"
342 					, charname(cchar , 0 )
343 					, charname(cchar , 1 ));
344 #endif
345 				/*
346 				 * Note that the inserted symbol
347 				 * will not be counted as a true input
348 				 * (i.e. the "yytshifts--" below)
349 				 * so that a true shift will be needed
350 				 * to make yytshifts > yyTshifts.
351 				 */
352 				yyTshifts = yytshifts;
353 			}
354 		}
355 	}
356 
357 	/*
358 	 * Set up to perform the correction.
359 	 * Build a token appropriate for replacement
360 	 * or insertion in the yytok structure ACchar
361 	 * having the attributes of the input at the
362 	 * point of error.
363 	 */
364 	copy((char *) (&ACtok), (char *) (&YC[0]), sizeof ACtok);
365 	acchar = cchar;
366 	aclval = nullsem(acchar);
367 	if (aclval != NIL)
368 		recovered();
369 	switch (cact) {
370 		/*
371 		 * Panic, just restore the
372 		 * lookahead and return.
373 		 */
374 		case CPANIC:
375 			setpfx('E');
376 			if (idfail) {
377 				copy((char *) (&Y), (char *) (&OY), sizeof Y);
378 				if (yyrhave == NIL) {
379 #ifdef PI
380 					if (yybaduse(yypv[0].cptr, yyeline, ISUNDEF) == NIL)
381 #endif
382 						yerror("Undefined identifier");
383 				} else {
384 					yerror("Improper %s identifier", classes[yyrhave]);
385 #ifdef PI
386 					(void) yybaduse(yypv[0].cptr, yyeline, NIL);
387 #endif
388 				}
389 				/*
390 				 * Suppress message from panic routine
391 				 */
392 				yyshifts = 1;
393 			}
394 			i = 0;
395 			/* Note that on one path we dont touch yyshifts ! */
396 			break;
397 		/*
398 		 * Delete the input.
399 		 * Mark this as a shift over true input.
400 		 * Restore the lookahead starting at
401 		 * the second token.
402 		 */
403 		case CDELETE:
404 			if (ccost != 0)
405 				yerror("Deleted %s%s", tokname(&YC[0] , 0 )
406 						     , tokname(&YC[0] , 1 ));
407 			yytshifts++;
408 			i = 1;
409 			yyshifts = 0;
410 			break;
411 		/*
412 		 * Replace the input with a new token.
413 		 */
414 		case CREPLACE:
415 			if (acchar == YEOF)
416 				yyexeof();
417 			if (acchar == YEND)
418 				aclval = NIL;
419 			yerror("Replaced %s%s with a %s%s",
420 			    tokname(&YC[0] , 0 ),
421 			    tokname(&YC[0] , 1 ),
422 			    tokname(&ACtok , 0 ),
423 			    tokname(&ACtok , 1 ));
424 			copy((char *) (&YC[0]), (char *) (&ACtok), sizeof YC[0]);
425 			i = 0;
426 			yyshifts = 0;
427 			break;
428 		/*
429 		 * Insert a token.
430 		 * Don't count this token as a true input shift.
431 		 * For inserted "end"s pas.y is responsible
432 		 * for the error message later so suppress it.
433 		 * Restore all the lookahead.
434 		 */
435 		case CINSERT:
436 			if (acchar == YEOF)
437 				yyexeof();
438 			if (acchar != YEND)
439 				yerror("Inserted %s%s",
440 					tokname(&ACtok , 0 ),
441 					tokname(&ACtok , 1 ));
442 			yytshifts--;
443 			i = 0;
444 			yyshifts = 0;
445 			break;
446 		/*
447 		 * Make a unique symbol correction.
448 		 * Like an insertion but a different message.
449 		 */
450 		case CUNIQUE:
451 			setpfx('E');
452 			yerror("Expected %s%s",
453 				tokname(&ACtok , 0 ),
454 				tokname(&ACtok , 1 ));
455 			yytshifts--;
456 			i = 0;
457 			if (ccost == 0 || yyunique)
458 				yyshifts = 0;
459 			else
460 				yyshifts = -1;
461 			break;
462 		/*
463 		 * Change an identifier's type
464 		 * to make it work.
465 		 */
466 		case CCHIDENT:
467 			copy((char *) (&Y), (char *) (&OY), sizeof Y);
468 #ifdef PI
469 			i = 1 << yyrwant;
470 #endif
471 			if (yyrhave == NIL) {
472 				yerror("Undefined %s", classes[yyrwant]);
473 #ifdef PI
474 				i |= ISUNDEF;
475 #endif
476 			} else
477 				yerror("Replaced %s id with a %s id", classes[yyrhave], classes[yyrwant]);
478 #ifdef PI
479 			(void) yybaduse(yypv[0].cptr, yyeline, i);
480 #endif
481 			yypv[0].i_entry = nullsem(YID);
482 			i = 0;
483 			yyshifts = 0;
484 			break;
485 	}
486 
487 	/*
488 	 * Restore the desired portion of the lookahead,
489 	 * and possibly the inserted or unique inserted token.
490 	 */
491 	for (yCcnt--; yCcnt >= i; yCcnt--)
492 		unyylex(&YC[yCcnt]);
493 	if (cact == CINSERT || cact == CUNIQUE)
494 		unyylex(&ACtok);
495 
496 	/*
497 	 * Put the scanner back in sync.
498 	 */
499 	yychar = yylex();
500 
501 	/*
502 	 * We succeeded if we didn't "panic".
503 	 */
504 	Recovery = FALSE;
505 	Ps = Ps0;
506 	return (cact != CPANIC);
507 }
508 
509 yyexeof()
510 {
511 
512 	yerror("End-of-file expected - QUIT");
513 	pexit(ERRS);
514 }
515 
516 yyunexeof()
517 {
518 
519 	yerror("Unexpected end-of-file - QUIT");
520 	pexit(ERRS);
521 }
522 
523 /*
524  * Try corrections with the state at Ps0.
525  * Flag is 0 if this is the top of stack state,
526  * 1 if it is the state below.
527  */
528 trystate(Ps0, Pv0, flag, insmult, delmult, repmult)
529 	int *Ps0, *Pv0, flag;
530 	char *insmult, *delmult, *repmult;
531 {
532 	/*
533 	 * C is a working cost, ap a pointer into the action
534 	 * table for looking at feasible alternatives.
535 	 */
536 	register int c, *ap;
537 
538 #ifdef DEBUG
539 	Eprintf("Trying state %d\n", *Ps0);
540 #endif
541 	/*
542 	 * Try deletion.
543 	 * Correct returns a cost.
544 	 */
545 #ifdef DEBUG
546 	Tprintf("  Try Delete %s%s cost=%d\n",
547 		tokname(&YC[0] , 0 ),
548 		tokname(&YC[0] , 1 ),
549 		delcost(YC[0].Yychar));
550 #endif
551 	c = delcost(YC[0].Yychar);
552 #ifndef DEBUG
553 	if (c < ccost) {
554 #endif
555 		c = correct(NOCHAR, 1, c, delmult, Ps0, Pv0);
556 #ifdef DEBUG
557 		if (c < CPRLIMIT || fulltrace)
558 			Eprintf("Cost %2d Delete %s%s\n", c,
559 				tokname(&YC[0] , 0 ),
560 				tokname(&YC[0] , 1 ));
561 #endif
562 		if (c < ccost)
563 			cact = CDELETE, ccost = c, cflag = flag;
564 #ifndef DEBUG
565 	}
566 #endif
567 
568 	/*
569 	 * Look at the inputs to this state
570 	 * which will cause parse action shift.
571 	 */
572 	aclval = NIL;
573 	ap = &yyact[yypact[*Ps0 + 1]];
574 
575 	/*
576 	 * Skip action on error to
577 	 * detect true unique inputs.
578 	 * Error action is always first.
579 	 */
580 	if (*ap == -ERROR)
581 		ap += 2;
582 
583 	/*
584 	 * Loop through the test actions
585 	 * for this state.
586 	 */
587 	for (; *ap <= 0; ap += 2) {
588 		/*
589 		 * Extract the token of this action
590 		 */
591 		acchar = -*ap;
592 
593 		/*
594 		 * Try insertion
595 		 */
596 #ifdef DEBUG
597 		Tprintf("  Try Insert %s%s cost=%d\n"
598 			, charname(acchar , 0 )
599 			, charname(acchar , 1 )
600 			, inscost(acchar, YC[0].Yychar));
601 #endif
602 		c = inscost(acchar, YC[0].Yychar);
603 #ifndef DEBUG
604 		if (c < ccost) {
605 #endif
606 			if (c == 0) {
607 				c = correct(acchar, 0, 1, insmult + 1, Ps0, Pv0);
608 #ifdef DEBUG
609 				Eprintf("Cost %2d Freebie %s%s\n", c
610 					, charname(acchar , 0 )
611 					, charname(acchar , 1 ));
612 #endif
613 				if (c < ccost)
614 					cact = CUNIQUE, ccost = 0, cchar = acchar, cflag = flag;
615 			} else {
616 				c = correct(acchar, 0, c, insmult, Ps0, Pv0);
617 #ifdef DEBUG
618 				if (c < CPRLIMIT || fulltrace)
619 					Eprintf("Cost %2d Insert %s%s\n", c
620 						, charname(acchar , 0 )
621 						, charname(acchar , 1 ));
622 #endif
623 				if (c < ccost)
624 					cact = CINSERT, ccost = c, cchar = acchar, cflag = flag;
625 			}
626 #ifndef DEBUG
627 		}
628 #endif
629 
630 		/*
631 		 * Try replacement
632 		 */
633 #ifdef DEBUG
634 		Tprintf("  Try Replace %s%s with %s%s cost=%d\n",
635 		    tokname(&YC[0] , 0 ),
636 		    tokname(&YC[0] , 1 ),
637 		    charname(acchar , 0 ),
638 		    charname(acchar , 1 ),
639 		    repcost(YC[0].Yychar, acchar));
640 #endif
641 		c = repcost(YC[0].Yychar, acchar);
642 #ifndef DEBUG
643 		if (c < ccost) {
644 #endif
645 			c = correct(acchar, 1, repcost(YC[0].Yychar, acchar), repmult, Ps0, Pv0);
646 #ifdef DEBUG
647 			if (c < CPRLIMIT || fulltrace)
648 				Eprintf("Cost %2d Replace %s%s with %s%s\n",
649 					c,
650 					tokname(&YC[0] , 0 ),
651 					tokname(&YC[0] , 1 ),
652 					tokname(&ACtok , 0 ),
653 					tokname(&ACtok , 1 ));
654 #endif
655 			if (c < ccost)
656 				cact = CREPLACE, ccost = c, cchar = acchar, cflag = flag;
657 #ifndef DEBUG
658 		}
659 #endif
660 	}
661 }
662 
663 int	*yCpv;
664 char	yyredfail;
665 
666 /*
667  * The ntok structure is used to build a
668  * scanner structure for tokens inserted
669  * from the argument "fchar" to "correct" below.
670  */
671 static	struct yytok ntok;
672 
673 /*
674  * Compute the cost of a correction
675  * C is the base cost for it.
676  * Fchar is the first input character from
677  * the current state, NOCHAR if none.
678  * The rest of the inputs come from the array
679  * YC, starting at origin and continuing to the
680  * last character there, YC[yCcnt - 1].Yychar.
681  *
682  * The cost returned is INFINITE if this correction
683  * allows no shifts, otherwise is weighted based
684  * on the number of shifts this allows against the
685  * maximum number possible with the available lookahead.
686  */
687 correct(fchar, origin, c, multvec, Ps0, Pv0)
688 	register int fchar, c;
689 	int origin;
690 	char *multvec;
691 	int *Ps0, *Pv0;
692 {
693 	register char *mv;
694 	extern int *loccor();
695 
696 	/*
697 	 * Ps is the top of the parse stack after the most
698 	 * recent local correctness check.  Loccor returns
699 	 * NIL when we cannot shift.
700 	 */
701 	register int *ps;
702 
703 	yyredfail = 0;
704 	/*
705 	 * Initialize the tip parse and semantic stacks.
706 	 */
707 	ps = Ps0;
708 	yytips[0] = *ps;
709 	ps--;
710 	yytipv[0] = Pv0[0];
711 	yCpv = Pv0 - 1;
712 	yytipct = 1;
713 
714 	/*
715 	 * Shift while possible.
716 	 * Adjust cost as necessary.
717 	 */
718 	mv = multvec;
719 	do {
720 		if (fchar != NOCHAR) {
721 			copy((char *) (&ntok), (char *) (&YC[0]), sizeof ntok);
722 			ntok.Yychar = fchar, ntok.Yylval = nullsem(fchar);
723 			fchar = NOCHAR;
724 			ps = loccor(ps, &ntok);
725 		} else
726 			ps = loccor(ps, &YC[origin++]);
727 		if (ps == NIL) {
728 			if (yyredfail && mv > multvec)
729 				mv--;
730 			c *= *mv;
731 			break;
732 		}
733 		mv++;
734 	} while (*mv != 1);
735 	return (c);
736 }
737 
738 extern	int yygo[], yypgo[], yyr1[], yyr2[];
739 /*
740  * Local syntactic correctness check.
741  * The arguments to this routine are a
742  * top of stack pointer, ps, and an input
743  * token tok.  Also, implicitly, the contents
744  * of the yytips array which contains the tip
745  * of the stack, and into which the new top
746  * state on the stack will be placed if we shift.
747  *
748  * If we succeed, we return a new top of stack
749  * pointer, else we return NIL.
750  */
751 int *
752 loccor(ps, ntok)
753 	int *ps;
754 	struct yytok *ntok;
755 {
756 	register int *p, n;
757 	register int nchar;
758 	int i;
759 
760 	if (ps == NIL)
761 		return (NIL);
762 	nchar = ntok->Yychar;
763 	yyeline = ntok->Yyeline;
764 #ifdef DEBUG
765 	Tprintf("    Stack ");
766 	for (i = yytipct - 1; i >= 0; i--)
767 		Tprintf("%d ", yytips[i]);
768 	Tprintf("| %d, Input %s%s\n", *ps
769 		, charname(nchar , 0 )
770 		, charname(nchar , 1 ));
771 #endif
772 	/*
773 	 * As in the yacc parser yyparse,
774 	 * p traces through the action list
775 	 * and "n" is the information associated
776 	 * with the action.
777 	 */
778 newstate:
779 	p = &yyact[ yypact[yytips[yytipct - 1]+1] ];
780 
781 	/*
782 	 * Search the parse actions table
783 	 * for something useful to do.
784 	 * While n is non-positive, it is the
785 	 * arithmetic inverse of the token to be tested.
786 	 * This allows a fast check.
787 	 */
788 	while ((n = *p++) <= 0)
789 		if ((n += nchar) != 0)
790 			p++;
791 	switch (n >> 12) {
792 		/*
793 		 * SHIFT
794 		 */
795 		default:
796 			panic("loccor");
797 		case 2:
798 			n &= 07777;
799 			yyredfail = 0;
800 			if (nchar == YID)
801 				yyredfail++;
802 			if (yytipct == YYTIPSIZ) {
803 tipover:
804 #ifdef DEBUG
805 				Tprintf("\tTIP OVFLO\n");
806 #endif
807 				return (NIL);
808 			}
809 			yytips[yytipct] = n;
810 			yytipv[yytipct] = ntok->Yylval;
811 			yytipct++;
812 #ifdef DEBUG
813 			Tprintf("\tShift to state %d\n", n);
814 #endif
815 			return (ps);
816 		/*
817 		 * REDUCE
818 		 */
819 		case 3:
820 			n &= 07777;
821 			if (yyEactr(n, (char *) yytipv[yytipct - 1]) == 0) {
822 #ifdef DEBUG
823 				Tprintf("\tYyEactr objects: have %s id, want %s id\n", classes[yyidhave], classes[yyidwant]);
824 #endif
825 				return (NIL);
826 			}
827 			yyredfail = 0;
828 			i = yyr2[n];
829 #ifdef DEBUG
830 			Tprintf("\tReduce, length %d,", i);
831 #endif
832 			if (i > yytipct) {
833 				i -= yytipct;
834 				yytipct = 0;
835 				ps -= i;
836 				yCpv -= i;
837 			} else
838 				yytipct -= i;
839 			if (yytipct >= YYTIPSIZ)
840 				goto tipover;
841 			/*
842 			 * Use goto table to find next state
843 			 */
844 			p = &yygo[yypgo[yyr1[n]]];
845 			i = yytipct ? yytips[yytipct - 1] : *ps;
846 			while (*p != i && *p >= 0)
847 				p += 2;
848 #ifdef DEBUG
849 			Tprintf(" new state %d\n", p[1]);
850 #endif
851 			yytips[yytipct] = p[1];
852 			yytipct++;
853 			goto newstate;
854 		/*
855 		 * ACCEPT
856 		 */
857 		case 4:
858 #ifdef DEBUG
859 			Tprintf("\tAccept\n");
860 #endif
861 			return (ps);
862 		/*
863 		 * ERROR
864 		 */
865 		case 1:
866 #ifdef DEBUG
867 			Tprintf("\tError\n");
868 #endif
869 			return (0);
870 	}
871 }
872