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