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