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