xref: /csrg-svn/usr.bin/pascal/src/yyrecover.c (revision 22214)
1*22214Sdist /*
2*22214Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22214Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22214Sdist  * specifies the terms and conditions for redistribution.
5*22214Sdist  */
6794Speter 
714748Sthien #ifndef lint
8*22214Sdist static char sccsid[] = "@(#)yyrecover.c	5.1 (Berkeley) 06/05/85";
9*22214Sdist #endif not lint
10794Speter 
11794Speter #include "whoami.h"
12794Speter #include "0.h"
1314748Sthien #include "tree_ty.h"	/* must be included for yy.h */
14794Speter #include "yy.h"
15794Speter 
16794Speter /*
17794Speter  * Very simplified version of Graham-Rhodes error recovery
18794Speter  * method for LALR parsers.  Backward move is embodied in
19794Speter  * default reductions of the yacc parser until an error condition
20794Speter  * is reached.  Forward move is over a small number of input tokens
21794Speter  * and cannot "condense".  The basic corrections are:
22794Speter  *
23794Speter  *	1) Delete the input token.
24794Speter  *
25794Speter  *	2) Replace the current input with a legal input.
26794Speter  *
27794Speter  *	3) Insert a legal token.
28794Speter  *
29794Speter  * All corrections are weighted, considered only if they allow
30794Speter  * at least two shifts, and the cost of a correction increases if
31794Speter  * it allows shifting over only a part of the lookahead.
32794Speter  *
33794Speter  * Another error situation is that which occurs when an identifier "fails"
34794Speter  * a reduction because it is not the required "class".
35794Speter  * In this case, we also consider replacing this identifier, which has
36794Speter  * already been shifted over, with an identifier of the correct class.
37794Speter  *
38794Speter  * Another correction performed here is unique symbol insertion.
39794Speter  * If the current state admits only one input, and no other alternative
40794Speter  * correction presents itself, then that symbol will be inserted.
41794Speter  * There is a danger in this of looping, and it is handled
42794Speter  * by counting true shifts over input (see below).
43794Speter  *
44794Speter  *
45794Speter  * A final class of corrections, considered only when the error
46794Speter  * occurred immediately after a shift over a terminal, involves
47794Speter  * the three basic corrections above, but with the point of error
48794Speter  * considered to be before this terminal was shifted over, effectively
49794Speter  * "unreading" this terminal.  This is a feeble attempt at elimination
50794Speter  * of the left-right bias and because "if" has a low weight and some
51794Speter  * statements are quite simple i.e.
52794Speter  *
53794Speter  *	cse ch of ...
54794Speter  *
55794Speter  * we can get a small number of errors.  The major deficiency of
56794Speter  * this is that we back up only one token, and that the forward
57794Speter  * move is over a small number of tokens, often not enough to really
58794Speter  * tell what the input should be, e.g. in
59794Speter  *
60794Speter  *	a[i] > a[i - 1] ...
61794Speter  *
62794Speter  * In such cases a bad identifier (misspelled keyword) or omitted
63794Speter  * keyword will be change or inserted as "if" as it has the lowest cost.
64794Speter  * This is not terribly bad, as "if"s are most common.
65794Speter  * This also allows the correction of other errors.
66794Speter  *
67794Speter  * This recovery depends on the default reductions which delay
68794Speter  * noticing the error until the parse reaches a state where the
69794Speter  * relevant "alternatives" are visible.  Note that it does not
70794Speter  * consider tokens which will cause reductions before being
71794Speter  * shifted over.  This requires the grammar to be written in a
72794Speter  * certain way for the recovery to work correctly.
73794Speter  * In some sense, also, the recovery suffers because we have
74794Speter  * LALR(1) tables rather than LR(1) tables, e.g. in
75794Speter  *
76794Speter  *	if rec.field < rec2,field2 then
77794Speter  */
78794Speter 
79794Speter /*
80794Speter  * Definitions of possible corrective actions
81794Speter  */
82794Speter #define	CPANIC		0
83794Speter #define	CDELETE		1
84794Speter #define	CREPLACE	2
85794Speter #define	CINSERT		3
86794Speter #define	CUNIQUE		4
87794Speter #define	CCHIDENT	5
88794Speter 
89794Speter /*
90794Speter  * Multiplicative cost factors for corrective actions.
91794Speter  *
92794Speter  * When an error occurs we take YCSIZ - 1 look-ahead tokens.
93794Speter  * If a correction being considered will shift over only part of
94794Speter  * that look-ahead, it is not completely discarded, but rather
95794Speter  * "weighted", its cost being multiplied by a weighting factor.
96794Speter  * For a correction to be considered its weighted cost must be less
97794Speter  * than CLIMIT.
98794Speter  *
99794Speter  * Non-weighted costs are considered:
100794Speter  *
101794Speter  *	LOW	<= 3
102794Speter  *	MEDIUM	4,5
103794Speter  *	HIGH	>= 6
104794Speter  *
105794Speter  * CURRENT WEIGHTING STRATEGY: Aug 20, 1977
106794Speter  *
107794Speter  * For all kinds of corrections we demand shifts over two symbols.
108794Speter  * Corrections have high weight even after two symbol
109794Speter  * shifts because the costs for deleting and inserting symbols are actually
110794Speter  * quite low; we do not want to change weighty symbols
111794Speter  * on inconclusive evidence.
112794Speter  *
113794Speter  * The weights are the same after the third look ahead.
114794Speter  * This prevents later, unrelated errors from causing "funny"
115794Speter  * biases of the weights toward one type of correction.
116794Speter  *
117794Speter  * Current look ahead is 5 symbols.
118794Speter  */
119794Speter 
120794Speter /*** CLIMIT is defined in yy.h for yycosts ***/
121794Speter #define	CPRLIMIT	50
122794Speter #define	CCHIDCOST	3
123794Speter 
124794Speter char	insmult[8]	= {INFINITY, INFINITY, INFINITY, 15, 8, 6, 3, 1};
125794Speter char	repmult[7]	= {INFINITY, INFINITY, INFINITY, 8, 6, 3, 1};
126794Speter char	delmult[6]	= {INFINITY, INFINITY, INFINITY, 6, 3, 1};
127794Speter 
128794Speter #define	NOCHAR	-1
129794Speter 
130794Speter #define	Eprintf	if (errtrace) printf
131794Speter #define	Tprintf	if (testtrace) printf
132794Speter 
133794Speter /*
134794Speter  * Action arrays of the parser needed here
135794Speter  */
13614748Sthien union semstack *yypv;
13714748Sthien int		yyact[], yypact[];
138794Speter 
139794Speter /*
140794Speter  * Yytips is the tip of the stack when using
141794Speter  * the function loccor to check for local
142794Speter  * syntactic correctness. As we don't want
143794Speter  * to copy the whole parser stack, but want
144794Speter  * to simulate parser moves, we "split"
145794Speter  * the parser stack and keep the tip here.
146794Speter  */
147794Speter #define	YYTIPSIZ 16
148794Speter int	yytips[YYTIPSIZ], yytipct;
149794Speter int	yytipv[YYTIPSIZ];
150794Speter 
151794Speter /*
152794Speter  * The array YC saves the lookahead tokens for the
153794Speter  * forward moves.
154794Speter  * Yccnt is the number of tokens in the YC array.
155794Speter  */
156794Speter #define	YCSIZ	6
157794Speter 
158794Speter int	yCcnt;
159794Speter struct	yytok YC0[YCSIZ + 1];
160794Speter struct	yytok *YC;
161794Speter 
162794Speter /*
163794Speter  * YCps gives the top of stack at
164794Speter  * the point of error.
165794Speter  */
166794Speter 
16714748Sthien bool	yyunique = TRUE;
168794Speter 
169794Speter STATIC	unsigned yyTshifts;
170794Speter 
171794Speter /*
172794Speter  * Cact is the corrective action we have decided on
173794Speter  * so far, ccost its cost, and cchar the associated token.
174794Speter  * Cflag tells if the correction is over the previous input token.
175794Speter  */
176794Speter int	cact, ccost, cchar, cflag;
177794Speter 
178794Speter /*
179794Speter  * ACtok holds the token under
180794Speter  * consideration when examining
181794Speter  * the lookaheads in a state.
182794Speter  */
183794Speter struct	yytok ACtok;
184794Speter 
185794Speter #define acchar	ACtok.Yychar
186794Speter #define aclval	ACtok.Yylval
187794Speter 
188794Speter /*
189794Speter  * Make a correction to the current stack which has
190794Speter  * top of stack pointer Ps.
191794Speter  */
192794Speter yyrecover(Ps0, idfail)
193794Speter 	int *Ps0, idfail;
194794Speter {
195794Speter 	register int c, i;
196794Speter 	int yyrwant, yyrhave;
197794Speter 
198794Speter #ifdef PI
19914748Sthien 	Recovery = TRUE;
200794Speter #endif
201794Speter 
202794Speter 	YC = &YC0[1];
203794Speter #ifdef DEBUG
204794Speter 	if (errtrace) {
205794Speter 		setpfx('p');
206794Speter 		yerror("Point of error");
207794Speter 		printf("States %d %d ...", Ps0[0], Ps0[-1]);
208794Speter 		if (idfail)
209794Speter 			printf(" [Idfail]");
21010732Smckusick #ifdef PXP
21110732Smckusick 		putchar('\n');
21210732Smckusick #else
213794Speter 		pchr('\n');
21410732Smckusick #endif
215794Speter 		printf("Input %s%s", tokname(&Y , 0)
216794Speter 				   , tokname(&Y , 1));
217794Speter 	}
218794Speter 
219794Speter #endif
220794Speter 	/*
221794Speter 	 * We first save the current input token
222794Speter 	 * and its associated semantic information.
223794Speter 	 */
224794Speter 	if (yychar < 0)
225794Speter 		yychar = yylex();
22614748Sthien 	copy((char *) (&YC[0]), (char *) (&Y), sizeof Y);
227794Speter 
228794Speter 	/*
229794Speter 	 * Set the default action and cost
230794Speter 	 */
231794Speter 	cact = CPANIC, ccost = CLIMIT, cflag = 0;
232794Speter 
233794Speter 	/*
234794Speter 	 * Peek ahead
235794Speter 	 */
236794Speter 	for (yCcnt = 1; yCcnt < YCSIZ; yCcnt++) {
237794Speter 		yychar = yylex();
23814748Sthien 		copy((char *) (&YC[yCcnt]), (char *) (&Y), sizeof YC[0]);
239794Speter #ifdef DEBUG
240794Speter 		Eprintf(" | %s%s", tokname(&YC[yCcnt] , 0 )
241794Speter 				 , tokname(&YC[yCcnt] , 1 ));
242794Speter #endif
243794Speter 	}
244794Speter #ifdef DEBUG
245794Speter 	Eprintf("\n");
246794Speter #endif
247794Speter 
248794Speter 	/*
249794Speter 	 * If we are here because a reduction failed, try
250794Speter 	 * correcting that.
251794Speter 	 */
252794Speter 	if (idfail) {
253794Speter 		/*
254794Speter 		 * Save the particulars about
255794Speter 		 * the kind of identifier we want/have.
256794Speter 		 */
257794Speter 		yyrwant = yyidwant;
258794Speter 		yyrhave = yyidhave;
259794Speter #ifdef DEBUG
260794Speter 		Tprintf("  Try Replace %s identifier with %s identifier cost=%d\n",
261794Speter 		    classes[yyidhave], classes[yyidwant], CCHIDCOST);
262794Speter #endif
263794Speter 
264794Speter 		/*
265794Speter 		 * Save the semantics of the ID on the
266794Speter 		 * stack, and null them out to free
267794Speter 		 * up the reduction in question.
268794Speter 		 */
26914748Sthien 		i = yypv[0].i_entry;
27014748Sthien 		yypv[0].i_entry = nullsem(YID);
27114748Sthien 		c = correct(NOCHAR, 0, CCHIDCOST, &repmult[2], Ps0,
27214748Sthien 				(int *) yypv);
27314748Sthien 		yypv[0].i_entry = i;
274794Speter #ifdef DEBUG
275794Speter 		if (c < CPRLIMIT || fulltrace)
276794Speter 			Eprintf("Cost %2d Replace %s identifier with %s identifier\n", c, classes[yyrhave], classes[yyrwant]);
277794Speter #endif
278794Speter 		if (c < ccost)
279794Speter 			cact = CCHIDENT, ccost = c, cchar = YID;
280794Speter 	}
281794Speter 
282794Speter 	/*
283794Speter 	 * First try correcting the state we are in
284794Speter 	 */
28514748Sthien 	trystate(Ps0, (int *) yypv, 0, &insmult[1], &delmult[1], &repmult[1]);
286794Speter 
287794Speter 	/*
288794Speter 	 * Now, if we just shifted over a terminal, try
289794Speter 	 * correcting it.
290794Speter 	 */
291794Speter 	if (OY.Yychar != -1 && OY.Yylval != nullsem(OY.Yychar)) {
292794Speter 		YC--;
29314748Sthien 		copy((char *) (&YC[0]), (char *) (&OY), sizeof YC[0]);
29414748Sthien 		trystate(Ps0 - 1, (int *) (yypv - 1), 1, insmult, delmult,
29514748Sthien 				repmult);
296794Speter 		if (cflag == 0)
297794Speter 			YC++;
298794Speter 		else {
299794Speter 			yypv--;
300794Speter #ifdef PXP
301794Speter 			yypw--;
302794Speter #endif
303794Speter 			Ps0--;
304794Speter 			yCcnt++;
305794Speter 		}
306794Speter 	}
307794Speter 
308794Speter 	/*
309794Speter 	 * Restoring the first look ahead into
310794Speter 	 * the scanner token allows the error message
311794Speter 	 * routine to print the error message with the text
312794Speter 	 * of the correct line.
313794Speter 	 */
31414748Sthien 	copy((char *) (&Y), (char *) (&YC[0]), sizeof Y);
315794Speter 
316794Speter 	/*
317794Speter 	 * Unique symbol insertion.
318794Speter 	 *
319794Speter 	 * If there was no reasonable correction found,
320794Speter 	 * but only one input to the parser is acceptable
321794Speter 	 * we report that, and try it.
322794Speter 	 *
323794Speter 	 * Special precautions here to prevent looping.
324794Speter 	 * The number of true inputs shifted over at the point
325794Speter 	 * of the last unique insertion is recorded in the
326794Speter 	 * variable yyTshifts.  If this is not less than
327794Speter 	 * the current number in yytshifts, we do not insert.
328794Speter 	 * Thus, after one unique insertion, no more unique
329794Speter 	 * insertions will be made until an input is shifted
330794Speter 	 * over.  This guarantees termination.
331794Speter 	 */
332794Speter 	if (cact == CPANIC && !idfail) {
333794Speter 		register int *ap;
334794Speter 
335794Speter 		ap = &yyact[yypact[*Ps0 + 1]];
336794Speter 		if (*ap == -ERROR)
3373088Smckusic 			ap += 2;
338794Speter 		if (ap[0] <= 0 && ap[2] > 0) {
339794Speter 			cchar = -ap[0];
340794Speter 			if (cchar == YEOF)
341794Speter 				yyexeof();
342794Speter 			if (cchar != ERROR && yyTshifts < yytshifts) {
343794Speter 				cact = CUNIQUE;
344794Speter #ifdef DEBUG
345794Speter 				Eprintf("Unique symbol %s%s\n"
346794Speter 					, charname(cchar , 0 )
347794Speter 					, charname(cchar , 1 ));
348794Speter #endif
349794Speter 				/*
350794Speter 				 * Note that the inserted symbol
351794Speter 				 * will not be counted as a true input
352794Speter 				 * (i.e. the "yytshifts--" below)
353794Speter 				 * so that a true shift will be needed
354794Speter 				 * to make yytshifts > yyTshifts.
355794Speter 				 */
356794Speter 				yyTshifts = yytshifts;
357794Speter 			}
358794Speter 		}
359794Speter 	}
360794Speter 
361794Speter 	/*
362794Speter 	 * Set up to perform the correction.
363794Speter 	 * Build a token appropriate for replacement
364794Speter 	 * or insertion in the yytok structure ACchar
365794Speter 	 * having the attributes of the input at the
366794Speter 	 * point of error.
367794Speter 	 */
36814748Sthien 	copy((char *) (&ACtok), (char *) (&YC[0]), sizeof ACtok);
369794Speter 	acchar = cchar;
370794Speter 	aclval = nullsem(acchar);
371794Speter 	if (aclval != NIL)
372794Speter 		recovered();
373794Speter 	switch (cact) {
374794Speter 		/*
375794Speter 		 * Panic, just restore the
376794Speter 		 * lookahead and return.
377794Speter 		 */
378794Speter 		case CPANIC:
379794Speter 			setpfx('E');
380794Speter 			if (idfail) {
38114748Sthien 				copy((char *) (&Y), (char *) (&OY), sizeof Y);
382794Speter 				if (yyrhave == NIL) {
383794Speter #ifdef PI
38414748Sthien 					if (yybaduse(yypv[0].cptr, yyeline, ISUNDEF) == NIL)
385794Speter #endif
386794Speter 						yerror("Undefined identifier");
387794Speter 				} else {
388794Speter 					yerror("Improper %s identifier", classes[yyrhave]);
389794Speter #ifdef PI
39014748Sthien 					(void) yybaduse(yypv[0].cptr, yyeline, NIL);
391794Speter #endif
392794Speter 				}
393794Speter 				/*
394794Speter 				 * Suppress message from panic routine
395794Speter 				 */
396794Speter 				yyshifts = 1;
397794Speter 			}
398794Speter 			i = 0;
399794Speter 			/* Note that on one path we dont touch yyshifts ! */
400794Speter 			break;
401794Speter 		/*
402794Speter 		 * Delete the input.
403794Speter 		 * Mark this as a shift over true input.
404794Speter 		 * Restore the lookahead starting at
405794Speter 		 * the second token.
406794Speter 		 */
407794Speter 		case CDELETE:
408794Speter 			if (ccost != 0)
409794Speter 				yerror("Deleted %s%s", tokname(&YC[0] , 0 )
410794Speter 						     , tokname(&YC[0] , 1 ));
411794Speter 			yytshifts++;
412794Speter 			i = 1;
413794Speter 			yyshifts = 0;
414794Speter 			break;
415794Speter 		/*
416794Speter 		 * Replace the input with a new token.
417794Speter 		 */
418794Speter 		case CREPLACE:
419794Speter 			if (acchar == YEOF)
420794Speter 				yyexeof();
421794Speter 			if (acchar == YEND)
422794Speter 				aclval = NIL;
423794Speter 			yerror("Replaced %s%s with a %s%s",
424794Speter 			    tokname(&YC[0] , 0 ),
425794Speter 			    tokname(&YC[0] , 1 ),
426794Speter 			    tokname(&ACtok , 0 ),
427794Speter 			    tokname(&ACtok , 1 ));
42814748Sthien 			copy((char *) (&YC[0]), (char *) (&ACtok), sizeof YC[0]);
429794Speter 			i = 0;
430794Speter 			yyshifts = 0;
431794Speter 			break;
432794Speter 		/*
433794Speter 		 * Insert a token.
434794Speter 		 * Don't count this token as a true input shift.
435794Speter 		 * For inserted "end"s pas.y is responsible
436794Speter 		 * for the error message later so suppress it.
437794Speter 		 * Restore all the lookahead.
438794Speter 		 */
439794Speter 		case CINSERT:
440794Speter 			if (acchar == YEOF)
441794Speter 				yyexeof();
442794Speter 			if (acchar != YEND)
443794Speter 				yerror("Inserted %s%s",
444794Speter 					tokname(&ACtok , 0 ),
445794Speter 					tokname(&ACtok , 1 ));
446794Speter 			yytshifts--;
447794Speter 			i = 0;
448794Speter 			yyshifts = 0;
449794Speter 			break;
450794Speter 		/*
451794Speter 		 * Make a unique symbol correction.
452794Speter 		 * Like an insertion but a different message.
453794Speter 		 */
454794Speter 		case CUNIQUE:
455794Speter 			setpfx('E');
456794Speter 			yerror("Expected %s%s",
457794Speter 				tokname(&ACtok , 0 ),
458794Speter 				tokname(&ACtok , 1 ));
459794Speter 			yytshifts--;
460794Speter 			i = 0;
461794Speter 			if (ccost == 0 || yyunique)
462794Speter 				yyshifts = 0;
463794Speter 			else
464794Speter 				yyshifts = -1;
465794Speter 			break;
466794Speter 		/*
467794Speter 		 * Change an identifier's type
468794Speter 		 * to make it work.
469794Speter 		 */
470794Speter 		case CCHIDENT:
47114748Sthien 			copy((char *) (&Y), (char *) (&OY), sizeof Y);
472794Speter #ifdef PI
473794Speter 			i = 1 << yyrwant;
474794Speter #endif
475794Speter 			if (yyrhave == NIL) {
476794Speter 				yerror("Undefined %s", classes[yyrwant]);
477794Speter #ifdef PI
4783088Smckusic 				i |= ISUNDEF;
479794Speter #endif
480794Speter 			} else
481794Speter 				yerror("Replaced %s id with a %s id", classes[yyrhave], classes[yyrwant]);
482794Speter #ifdef PI
48314748Sthien 			(void) yybaduse(yypv[0].cptr, yyeline, i);
484794Speter #endif
48514748Sthien 			yypv[0].i_entry = nullsem(YID);
486794Speter 			i = 0;
487794Speter 			yyshifts = 0;
488794Speter 			break;
489794Speter 	}
490794Speter 
491794Speter 	/*
492794Speter 	 * Restore the desired portion of the lookahead,
493794Speter 	 * and possibly the inserted or unique inserted token.
494794Speter 	 */
495794Speter 	for (yCcnt--; yCcnt >= i; yCcnt--)
496794Speter 		unyylex(&YC[yCcnt]);
497794Speter 	if (cact == CINSERT || cact == CUNIQUE)
498794Speter 		unyylex(&ACtok);
499794Speter 
500794Speter 	/*
501794Speter 	 * Put the scanner back in sync.
502794Speter 	 */
503794Speter 	yychar = yylex();
504794Speter 
505794Speter 	/*
506794Speter 	 * We succeeded if we didn't "panic".
507794Speter 	 */
50814748Sthien 	Recovery = FALSE;
509794Speter 	Ps = Ps0;
510794Speter 	return (cact != CPANIC);
511794Speter }
512794Speter 
513794Speter yyexeof()
514794Speter {
515794Speter 
516794Speter 	yerror("End-of-file expected - QUIT");
517794Speter 	pexit(ERRS);
518794Speter }
519794Speter 
520794Speter yyunexeof()
521794Speter {
522794Speter 
523794Speter 	yerror("Unexpected end-of-file - QUIT");
524794Speter 	pexit(ERRS);
525794Speter }
526794Speter 
527794Speter /*
528794Speter  * Try corrections with the state at Ps0.
529794Speter  * Flag is 0 if this is the top of stack state,
530794Speter  * 1 if it is the state below.
531794Speter  */
532794Speter trystate(Ps0, Pv0, flag, insmult, delmult, repmult)
533794Speter 	int *Ps0, *Pv0, flag;
534794Speter 	char *insmult, *delmult, *repmult;
535794Speter {
536794Speter 	/*
537794Speter 	 * C is a working cost, ap a pointer into the action
538794Speter 	 * table for looking at feasible alternatives.
539794Speter 	 */
540794Speter 	register int c, *ap;
541794Speter 
542794Speter #ifdef DEBUG
543794Speter 	Eprintf("Trying state %d\n", *Ps0);
544794Speter #endif
545794Speter 	/*
546794Speter 	 * Try deletion.
547794Speter 	 * Correct returns a cost.
548794Speter 	 */
549794Speter #ifdef DEBUG
550794Speter 	Tprintf("  Try Delete %s%s cost=%d\n",
551794Speter 		tokname(&YC[0] , 0 ),
552794Speter 		tokname(&YC[0] , 1 ),
553794Speter 		delcost(YC[0].Yychar));
554794Speter #endif
555794Speter 	c = delcost(YC[0].Yychar);
556794Speter #ifndef DEBUG
557794Speter 	if (c < ccost) {
558794Speter #endif
559794Speter 		c = correct(NOCHAR, 1, c, delmult, Ps0, Pv0);
560794Speter #ifdef DEBUG
561794Speter 		if (c < CPRLIMIT || fulltrace)
562794Speter 			Eprintf("Cost %2d Delete %s%s\n", c,
563794Speter 				tokname(&YC[0] , 0 ),
564794Speter 				tokname(&YC[0] , 1 ));
565794Speter #endif
566794Speter 		if (c < ccost)
567794Speter 			cact = CDELETE, ccost = c, cflag = flag;
568794Speter #ifndef DEBUG
569794Speter 	}
570794Speter #endif
571794Speter 
572794Speter 	/*
573794Speter 	 * Look at the inputs to this state
574794Speter 	 * which will cause parse action shift.
575794Speter 	 */
576794Speter 	aclval = NIL;
577794Speter 	ap = &yyact[yypact[*Ps0 + 1]];
578794Speter 
579794Speter 	/*
580794Speter 	 * Skip action on error to
581794Speter 	 * detect true unique inputs.
582794Speter 	 * Error action is always first.
583794Speter 	 */
584794Speter 	if (*ap == -ERROR)
5853088Smckusic 		ap += 2;
586794Speter 
587794Speter 	/*
588794Speter 	 * Loop through the test actions
589794Speter 	 * for this state.
590794Speter 	 */
59114748Sthien 	for (; *ap <= 0; ap += 2) {
592794Speter 		/*
593794Speter 		 * Extract the token of this action
594794Speter 		 */
595794Speter 		acchar = -*ap;
596794Speter 
597794Speter 		/*
598794Speter 		 * Try insertion
599794Speter 		 */
600794Speter #ifdef DEBUG
601794Speter 		Tprintf("  Try Insert %s%s cost=%d\n"
602794Speter 			, charname(acchar , 0 )
603794Speter 			, charname(acchar , 1 )
60414748Sthien 			, inscost(acchar, YC[0].Yychar));
605794Speter #endif
606794Speter 		c = inscost(acchar, YC[0].Yychar);
607794Speter #ifndef DEBUG
608794Speter 		if (c < ccost) {
609794Speter #endif
610794Speter 			if (c == 0) {
611794Speter 				c = correct(acchar, 0, 1, insmult + 1, Ps0, Pv0);
612794Speter #ifdef DEBUG
613794Speter 				Eprintf("Cost %2d Freebie %s%s\n", c
614794Speter 					, charname(acchar , 0 )
615794Speter 					, charname(acchar , 1 ));
616794Speter #endif
617794Speter 				if (c < ccost)
618794Speter 					cact = CUNIQUE, ccost = 0, cchar = acchar, cflag = flag;
619794Speter 			} else {
620794Speter 				c = correct(acchar, 0, c, insmult, Ps0, Pv0);
621794Speter #ifdef DEBUG
622794Speter 				if (c < CPRLIMIT || fulltrace)
623794Speter 					Eprintf("Cost %2d Insert %s%s\n", c
624794Speter 						, charname(acchar , 0 )
625794Speter 						, charname(acchar , 1 ));
626794Speter #endif
627794Speter 				if (c < ccost)
628794Speter 					cact = CINSERT, ccost = c, cchar = acchar, cflag = flag;
629794Speter 			}
630794Speter #ifndef DEBUG
631794Speter 		}
632794Speter #endif
633794Speter 
634794Speter 		/*
635794Speter 		 * Try replacement
636794Speter 		 */
637794Speter #ifdef DEBUG
638794Speter 		Tprintf("  Try Replace %s%s with %s%s cost=%d\n",
639794Speter 		    tokname(&YC[0] , 0 ),
640794Speter 		    tokname(&YC[0] , 1 ),
641794Speter 		    charname(acchar , 0 ),
642794Speter 		    charname(acchar , 1 ),
643794Speter 		    repcost(YC[0].Yychar, acchar));
644794Speter #endif
645794Speter 		c = repcost(YC[0].Yychar, acchar);
646794Speter #ifndef DEBUG
647794Speter 		if (c < ccost) {
648794Speter #endif
649794Speter 			c = correct(acchar, 1, repcost(YC[0].Yychar, acchar), repmult, Ps0, Pv0);
650794Speter #ifdef DEBUG
651794Speter 			if (c < CPRLIMIT || fulltrace)
652794Speter 				Eprintf("Cost %2d Replace %s%s with %s%s\n",
653794Speter 					c,
654794Speter 					tokname(&YC[0] , 0 ),
655794Speter 					tokname(&YC[0] , 1 ),
656794Speter 					tokname(&ACtok , 0 ),
657794Speter 					tokname(&ACtok , 1 ));
658794Speter #endif
659794Speter 			if (c < ccost)
660794Speter 				cact = CREPLACE, ccost = c, cchar = acchar, cflag = flag;
661794Speter #ifndef DEBUG
662794Speter 		}
663794Speter #endif
664794Speter 	}
665794Speter }
666794Speter 
667794Speter int	*yCpv;
668794Speter char	yyredfail;
669794Speter 
670794Speter /*
671794Speter  * The ntok structure is used to build a
672794Speter  * scanner structure for tokens inserted
673794Speter  * from the argument "fchar" to "correct" below.
674794Speter  */
675794Speter static	struct yytok ntok;
676794Speter 
677794Speter /*
678794Speter  * Compute the cost of a correction
679794Speter  * C is the base cost for it.
680794Speter  * Fchar is the first input character from
681794Speter  * the current state, NOCHAR if none.
682794Speter  * The rest of the inputs come from the array
683794Speter  * YC, starting at origin and continuing to the
684794Speter  * last character there, YC[yCcnt - 1].Yychar.
685794Speter  *
686794Speter  * The cost returned is INFINITE if this correction
687794Speter  * allows no shifts, otherwise is weighted based
688794Speter  * on the number of shifts this allows against the
689794Speter  * maximum number possible with the available lookahead.
690794Speter  */
691794Speter correct(fchar, origin, c, multvec, Ps0, Pv0)
692794Speter 	register int fchar, c;
693794Speter 	int origin;
694794Speter 	char *multvec;
695794Speter 	int *Ps0, *Pv0;
696794Speter {
697794Speter 	register char *mv;
69814748Sthien 	extern int *loccor();
699794Speter 
700794Speter 	/*
701794Speter 	 * Ps is the top of the parse stack after the most
702794Speter 	 * recent local correctness check.  Loccor returns
703794Speter 	 * NIL when we cannot shift.
704794Speter 	 */
705794Speter 	register int *ps;
706794Speter 
707794Speter 	yyredfail = 0;
708794Speter 	/*
709794Speter 	 * Initialize the tip parse and semantic stacks.
710794Speter 	 */
711794Speter 	ps = Ps0;
712794Speter 	yytips[0] = *ps;
713794Speter 	ps--;
714794Speter 	yytipv[0] = Pv0[0];
715794Speter 	yCpv = Pv0 - 1;
716794Speter 	yytipct = 1;
717794Speter 
718794Speter 	/*
719794Speter 	 * Shift while possible.
720794Speter 	 * Adjust cost as necessary.
721794Speter 	 */
722794Speter 	mv = multvec;
723794Speter 	do {
724794Speter 		if (fchar != NOCHAR) {
72514748Sthien 			copy((char *) (&ntok), (char *) (&YC[0]), sizeof ntok);
726794Speter 			ntok.Yychar = fchar, ntok.Yylval = nullsem(fchar);
727794Speter 			fchar = NOCHAR;
728794Speter 			ps = loccor(ps, &ntok);
729794Speter 		} else
730794Speter 			ps = loccor(ps, &YC[origin++]);
731794Speter 		if (ps == NIL) {
732794Speter 			if (yyredfail && mv > multvec)
733794Speter 				mv--;
7343088Smckusic 			c *= *mv;
735794Speter 			break;
736794Speter 		}
737794Speter 		mv++;
738794Speter 	} while (*mv != 1);
739794Speter 	return (c);
740794Speter }
741794Speter 
742794Speter extern	int yygo[], yypgo[], yyr1[], yyr2[];
743794Speter /*
744794Speter  * Local syntactic correctness check.
745794Speter  * The arguments to this routine are a
746794Speter  * top of stack pointer, ps, and an input
747794Speter  * token tok.  Also, implicitly, the contents
748794Speter  * of the yytips array which contains the tip
749794Speter  * of the stack, and into which the new top
750794Speter  * state on the stack will be placed if we shift.
751794Speter  *
752794Speter  * If we succeed, we return a new top of stack
753794Speter  * pointer, else we return NIL.
754794Speter  */
75514748Sthien int *
756794Speter loccor(ps, ntok)
757794Speter 	int *ps;
758794Speter 	struct yytok *ntok;
759794Speter {
760794Speter 	register int *p, n;
761794Speter 	register int nchar;
762794Speter 	int i;
763794Speter 
764794Speter 	if (ps == NIL)
765794Speter 		return (NIL);
766794Speter 	nchar = ntok->Yychar;
767794Speter 	yyeline = ntok->Yyeline;
768794Speter #ifdef DEBUG
769794Speter 	Tprintf("    Stack ");
770794Speter 	for (i = yytipct - 1; i >= 0; i--)
771794Speter 		Tprintf("%d ", yytips[i]);
772794Speter 	Tprintf("| %d, Input %s%s\n", *ps
773794Speter 		, charname(nchar , 0 )
774794Speter 		, charname(nchar , 1 ));
775794Speter #endif
776794Speter 	/*
777794Speter 	 * As in the yacc parser yyparse,
778794Speter 	 * p traces through the action list
779794Speter 	 * and "n" is the information associated
780794Speter 	 * with the action.
781794Speter 	 */
782794Speter newstate:
783794Speter 	p = &yyact[ yypact[yytips[yytipct - 1]+1] ];
784794Speter 
785794Speter 	/*
786794Speter 	 * Search the parse actions table
787794Speter 	 * for something useful to do.
788794Speter 	 * While n is non-positive, it is the
789794Speter 	 * arithmetic inverse of the token to be tested.
790794Speter 	 * This allows a fast check.
791794Speter 	 */
792794Speter 	while ((n = *p++) <= 0)
7933088Smckusic 		if ((n += nchar) != 0)
794794Speter 			p++;
795794Speter 	switch (n >> 12) {
796794Speter 		/*
797794Speter 		 * SHIFT
798794Speter 		 */
79914748Sthien 		default:
80014748Sthien 			panic("loccor");
801794Speter 		case 2:
8023088Smckusic 			n &= 07777;
803794Speter 			yyredfail = 0;
804794Speter 			if (nchar == YID)
805794Speter 				yyredfail++;
806794Speter 			if (yytipct == YYTIPSIZ) {
807794Speter tipover:
808794Speter #ifdef DEBUG
809794Speter 				Tprintf("\tTIP OVFLO\n");
810794Speter #endif
811794Speter 				return (NIL);
812794Speter 			}
813794Speter 			yytips[yytipct] = n;
814794Speter 			yytipv[yytipct] = ntok->Yylval;
815794Speter 			yytipct++;
816794Speter #ifdef DEBUG
817794Speter 			Tprintf("\tShift to state %d\n", n);
818794Speter #endif
819794Speter 			return (ps);
820794Speter 		/*
821794Speter 		 * REDUCE
822794Speter 		 */
823794Speter 		case 3:
8243088Smckusic 			n &= 07777;
82514748Sthien 			if (yyEactr(n, (char *) yytipv[yytipct - 1]) == 0) {
826794Speter #ifdef DEBUG
827794Speter 				Tprintf("\tYyEactr objects: have %s id, want %s id\n", classes[yyidhave], classes[yyidwant]);
828794Speter #endif
829794Speter 				return (NIL);
830794Speter 			}
831794Speter 			yyredfail = 0;
832794Speter 			i = yyr2[n];
833794Speter #ifdef DEBUG
834794Speter 			Tprintf("\tReduce, length %d,", i);
835794Speter #endif
836794Speter 			if (i > yytipct) {
8373088Smckusic 				i -= yytipct;
838794Speter 				yytipct = 0;
8393088Smckusic 				ps -= i;
8403088Smckusic 				yCpv -= i;
841794Speter 			} else
8423088Smckusic 				yytipct -= i;
843794Speter 			if (yytipct >= YYTIPSIZ)
844794Speter 				goto tipover;
845794Speter 			/*
846794Speter 			 * Use goto table to find next state
847794Speter 			 */
848794Speter 			p = &yygo[yypgo[yyr1[n]]];
849794Speter 			i = yytipct ? yytips[yytipct - 1] : *ps;
850794Speter 			while (*p != i && *p >= 0)
8513088Smckusic 				p += 2;
852794Speter #ifdef DEBUG
853794Speter 			Tprintf(" new state %d\n", p[1]);
854794Speter #endif
855794Speter 			yytips[yytipct] = p[1];
856794Speter 			yytipct++;
857794Speter 			goto newstate;
858794Speter 		/*
859794Speter 		 * ACCEPT
860794Speter 		 */
861794Speter 		case 4:
862794Speter #ifdef DEBUG
863794Speter 			Tprintf("\tAccept\n");
864794Speter #endif
865794Speter 			return (ps);
866794Speter 		/*
867794Speter 		 * ERROR
868794Speter 		 */
869794Speter 		case 1:
870794Speter #ifdef DEBUG
871794Speter 			Tprintf("\tError\n");
872794Speter #endif
873794Speter 			return (0);
874794Speter 	}
875794Speter }
876