1794Speter /* Copyright (c) 1979 Regents of the University of California */ 2794Speter 3*3088Smckusic static char sccsid[] = "@(#)yyrecover.c 1.2 03/08/81"; 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 159*3088Smckusic 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]"); 202794Speter pchr('\n'); 203794Speter printf("Input %s%s", tokname(&Y , 0) 204794Speter , tokname(&Y , 1)); 205794Speter } 206794Speter 207794Speter #endif 208794Speter /* 209794Speter * We first save the current input token 210794Speter * and its associated semantic information. 211794Speter */ 212794Speter if (yychar < 0) 213794Speter yychar = yylex(); 214794Speter copy(&YC[0], &Y, sizeof Y); 215794Speter 216794Speter /* 217794Speter * Set the default action and cost 218794Speter */ 219794Speter cact = CPANIC, ccost = CLIMIT, cflag = 0; 220794Speter 221794Speter /* 222794Speter * Peek ahead 223794Speter */ 224794Speter for (yCcnt = 1; yCcnt < YCSIZ; yCcnt++) { 225794Speter yychar = yylex(); 226794Speter copy(&YC[yCcnt], &Y, sizeof YC[0]); 227794Speter #ifdef DEBUG 228794Speter Eprintf(" | %s%s", tokname(&YC[yCcnt] , 0 ) 229794Speter , tokname(&YC[yCcnt] , 1 )); 230794Speter #endif 231794Speter } 232794Speter #ifdef DEBUG 233794Speter Eprintf("\n"); 234794Speter #endif 235794Speter 236794Speter /* 237794Speter * If we are here because a reduction failed, try 238794Speter * correcting that. 239794Speter */ 240794Speter if (idfail) { 241794Speter /* 242794Speter * Save the particulars about 243794Speter * the kind of identifier we want/have. 244794Speter */ 245794Speter yyrwant = yyidwant; 246794Speter yyrhave = yyidhave; 247794Speter #ifdef DEBUG 248794Speter Tprintf(" Try Replace %s identifier with %s identifier cost=%d\n", 249794Speter classes[yyidhave], classes[yyidwant], CCHIDCOST); 250794Speter #endif 251794Speter 252794Speter /* 253794Speter * Save the semantics of the ID on the 254794Speter * stack, and null them out to free 255794Speter * up the reduction in question. 256794Speter */ 257794Speter i = yypv[0]; 258794Speter yypv[0] = nullsem(YID); 259794Speter c = correct(NOCHAR, 0, CCHIDCOST, &repmult[2], Ps0, yypv); 260794Speter yypv[0] = i; 261794Speter #ifdef DEBUG 262794Speter if (c < CPRLIMIT || fulltrace) 263794Speter Eprintf("Cost %2d Replace %s identifier with %s identifier\n", c, classes[yyrhave], classes[yyrwant]); 264794Speter #endif 265794Speter if (c < ccost) 266794Speter cact = CCHIDENT, ccost = c, cchar = YID; 267794Speter } 268794Speter 269794Speter /* 270794Speter * First try correcting the state we are in 271794Speter */ 272794Speter trystate(Ps0, yypv, 0, &insmult[1], &delmult[1], &repmult[1]); 273794Speter 274794Speter /* 275794Speter * Now, if we just shifted over a terminal, try 276794Speter * correcting it. 277794Speter */ 278794Speter if (OY.Yychar != -1 && OY.Yylval != nullsem(OY.Yychar)) { 279794Speter YC--; 280794Speter copy(&YC[0], &OY, sizeof YC[0]); 281794Speter trystate(Ps0 - 1, yypv - 1, 1, insmult, delmult, repmult); 282794Speter if (cflag == 0) 283794Speter YC++; 284794Speter else { 285794Speter yypv--; 286794Speter #ifdef PXP 287794Speter yypw--; 288794Speter #endif 289794Speter Ps0--; 290794Speter yCcnt++; 291794Speter } 292794Speter } 293794Speter 294794Speter /* 295794Speter * Restoring the first look ahead into 296794Speter * the scanner token allows the error message 297794Speter * routine to print the error message with the text 298794Speter * of the correct line. 299794Speter */ 300794Speter copy(&Y, &YC[0], sizeof Y); 301794Speter 302794Speter /* 303794Speter * Unique symbol insertion. 304794Speter * 305794Speter * If there was no reasonable correction found, 306794Speter * but only one input to the parser is acceptable 307794Speter * we report that, and try it. 308794Speter * 309794Speter * Special precautions here to prevent looping. 310794Speter * The number of true inputs shifted over at the point 311794Speter * of the last unique insertion is recorded in the 312794Speter * variable yyTshifts. If this is not less than 313794Speter * the current number in yytshifts, we do not insert. 314794Speter * Thus, after one unique insertion, no more unique 315794Speter * insertions will be made until an input is shifted 316794Speter * over. This guarantees termination. 317794Speter */ 318794Speter if (cact == CPANIC && !idfail) { 319794Speter register int *ap; 320794Speter 321794Speter ap = &yyact[yypact[*Ps0 + 1]]; 322794Speter if (*ap == -ERROR) 323*3088Smckusic ap += 2; 324794Speter if (ap[0] <= 0 && ap[2] > 0) { 325794Speter cchar = -ap[0]; 326794Speter if (cchar == YEOF) 327794Speter yyexeof(); 328794Speter if (cchar != ERROR && yyTshifts < yytshifts) { 329794Speter cact = CUNIQUE; 330794Speter #ifdef DEBUG 331794Speter Eprintf("Unique symbol %s%s\n" 332794Speter , charname(cchar , 0 ) 333794Speter , charname(cchar , 1 )); 334794Speter #endif 335794Speter /* 336794Speter * Note that the inserted symbol 337794Speter * will not be counted as a true input 338794Speter * (i.e. the "yytshifts--" below) 339794Speter * so that a true shift will be needed 340794Speter * to make yytshifts > yyTshifts. 341794Speter */ 342794Speter yyTshifts = yytshifts; 343794Speter } 344794Speter } 345794Speter } 346794Speter 347794Speter /* 348794Speter * Set up to perform the correction. 349794Speter * Build a token appropriate for replacement 350794Speter * or insertion in the yytok structure ACchar 351794Speter * having the attributes of the input at the 352794Speter * point of error. 353794Speter */ 354794Speter copy(&ACtok, &YC[0], sizeof ACtok); 355794Speter acchar = cchar; 356794Speter aclval = nullsem(acchar); 357794Speter if (aclval != NIL) 358794Speter recovered(); 359794Speter switch (cact) { 360794Speter /* 361794Speter * Panic, just restore the 362794Speter * lookahead and return. 363794Speter */ 364794Speter case CPANIC: 365794Speter setpfx('E'); 366794Speter if (idfail) { 367794Speter copy(&Y, &OY, sizeof Y); 368794Speter if (yyrhave == NIL) { 369794Speter #ifdef PI 370794Speter if (yybaduse(yypv[0], yyeline, ISUNDEF) == NIL) 371794Speter #endif 372794Speter yerror("Undefined identifier"); 373794Speter } else { 374794Speter yerror("Improper %s identifier", classes[yyrhave]); 375794Speter #ifdef PI 376794Speter yybaduse(yypv[0], yyeline, NIL); 377794Speter #endif 378794Speter } 379794Speter /* 380794Speter * Suppress message from panic routine 381794Speter */ 382794Speter yyshifts = 1; 383794Speter } 384794Speter i = 0; 385794Speter /* Note that on one path we dont touch yyshifts ! */ 386794Speter break; 387794Speter /* 388794Speter * Delete the input. 389794Speter * Mark this as a shift over true input. 390794Speter * Restore the lookahead starting at 391794Speter * the second token. 392794Speter */ 393794Speter case CDELETE: 394794Speter if (ccost != 0) 395794Speter yerror("Deleted %s%s", tokname(&YC[0] , 0 ) 396794Speter , tokname(&YC[0] , 1 )); 397794Speter yytshifts++; 398794Speter i = 1; 399794Speter yyshifts = 0; 400794Speter break; 401794Speter /* 402794Speter * Replace the input with a new token. 403794Speter */ 404794Speter case CREPLACE: 405794Speter if (acchar == YEOF) 406794Speter yyexeof(); 407794Speter if (acchar == YEND) 408794Speter aclval = NIL; 409794Speter yerror("Replaced %s%s with a %s%s", 410794Speter tokname(&YC[0] , 0 ), 411794Speter tokname(&YC[0] , 1 ), 412794Speter tokname(&ACtok , 0 ), 413794Speter tokname(&ACtok , 1 )); 414794Speter copy(&YC[0], &ACtok, sizeof YC[0]); 415794Speter i = 0; 416794Speter yyshifts = 0; 417794Speter break; 418794Speter /* 419794Speter * Insert a token. 420794Speter * Don't count this token as a true input shift. 421794Speter * For inserted "end"s pas.y is responsible 422794Speter * for the error message later so suppress it. 423794Speter * Restore all the lookahead. 424794Speter */ 425794Speter case CINSERT: 426794Speter if (acchar == YEOF) 427794Speter yyexeof(); 428794Speter if (acchar != YEND) 429794Speter yerror("Inserted %s%s", 430794Speter tokname(&ACtok , 0 ), 431794Speter tokname(&ACtok , 1 )); 432794Speter yytshifts--; 433794Speter i = 0; 434794Speter yyshifts = 0; 435794Speter break; 436794Speter /* 437794Speter * Make a unique symbol correction. 438794Speter * Like an insertion but a different message. 439794Speter */ 440794Speter case CUNIQUE: 441794Speter setpfx('E'); 442794Speter yerror("Expected %s%s", 443794Speter tokname(&ACtok , 0 ), 444794Speter tokname(&ACtok , 1 )); 445794Speter yytshifts--; 446794Speter i = 0; 447794Speter if (ccost == 0 || yyunique) 448794Speter yyshifts = 0; 449794Speter else 450794Speter yyshifts = -1; 451794Speter break; 452794Speter /* 453794Speter * Change an identifier's type 454794Speter * to make it work. 455794Speter */ 456794Speter case CCHIDENT: 457794Speter copy(&Y, &OY, sizeof Y); 458794Speter #ifdef PI 459794Speter i = 1 << yyrwant; 460794Speter #endif 461794Speter if (yyrhave == NIL) { 462794Speter yerror("Undefined %s", classes[yyrwant]); 463794Speter #ifdef PI 464*3088Smckusic i |= ISUNDEF; 465794Speter #endif 466794Speter } else 467794Speter yerror("Replaced %s id with a %s id", classes[yyrhave], classes[yyrwant]); 468794Speter #ifdef PI 469794Speter yybaduse(yypv[0], yyeline, i); 470794Speter #endif 471794Speter yypv[0] = nullsem(YID); 472794Speter i = 0; 473794Speter yyshifts = 0; 474794Speter break; 475794Speter } 476794Speter 477794Speter /* 478794Speter * Restore the desired portion of the lookahead, 479794Speter * and possibly the inserted or unique inserted token. 480794Speter */ 481794Speter for (yCcnt--; yCcnt >= i; yCcnt--) 482794Speter unyylex(&YC[yCcnt]); 483794Speter if (cact == CINSERT || cact == CUNIQUE) 484794Speter unyylex(&ACtok); 485794Speter 486794Speter /* 487794Speter * Put the scanner back in sync. 488794Speter */ 489794Speter yychar = yylex(); 490794Speter 491794Speter /* 492794Speter * We succeeded if we didn't "panic". 493794Speter */ 494794Speter Recovery = 0; 495794Speter Ps = Ps0; 496794Speter return (cact != CPANIC); 497794Speter } 498794Speter 499794Speter yyexeof() 500794Speter { 501794Speter 502794Speter yerror("End-of-file expected - QUIT"); 503794Speter pexit(ERRS); 504794Speter } 505794Speter 506794Speter yyunexeof() 507794Speter { 508794Speter 509794Speter yerror("Unexpected end-of-file - QUIT"); 510794Speter pexit(ERRS); 511794Speter } 512794Speter 513794Speter /* 514794Speter * Try corrections with the state at Ps0. 515794Speter * Flag is 0 if this is the top of stack state, 516794Speter * 1 if it is the state below. 517794Speter */ 518794Speter trystate(Ps0, Pv0, flag, insmult, delmult, repmult) 519794Speter int *Ps0, *Pv0, flag; 520794Speter char *insmult, *delmult, *repmult; 521794Speter { 522794Speter /* 523794Speter * C is a working cost, ap a pointer into the action 524794Speter * table for looking at feasible alternatives. 525794Speter */ 526794Speter register int c, *ap; 527794Speter int i, *actions; 528794Speter 529794Speter #ifdef DEBUG 530794Speter Eprintf("Trying state %d\n", *Ps0); 531794Speter #endif 532794Speter /* 533794Speter * Try deletion. 534794Speter * Correct returns a cost. 535794Speter */ 536794Speter #ifdef DEBUG 537794Speter Tprintf(" Try Delete %s%s cost=%d\n", 538794Speter tokname(&YC[0] , 0 ), 539794Speter tokname(&YC[0] , 1 ), 540794Speter delcost(YC[0].Yychar)); 541794Speter #endif 542794Speter c = delcost(YC[0].Yychar); 543794Speter #ifndef DEBUG 544794Speter if (c < ccost) { 545794Speter #endif 546794Speter c = correct(NOCHAR, 1, c, delmult, Ps0, Pv0); 547794Speter #ifdef DEBUG 548794Speter if (c < CPRLIMIT || fulltrace) 549794Speter Eprintf("Cost %2d Delete %s%s\n", c, 550794Speter tokname(&YC[0] , 0 ), 551794Speter tokname(&YC[0] , 1 )); 552794Speter #endif 553794Speter if (c < ccost) 554794Speter cact = CDELETE, ccost = c, cflag = flag; 555794Speter #ifndef DEBUG 556794Speter } 557794Speter #endif 558794Speter 559794Speter /* 560794Speter * Look at the inputs to this state 561794Speter * which will cause parse action shift. 562794Speter */ 563794Speter aclval = NIL; 564794Speter ap = &yyact[yypact[*Ps0 + 1]]; 565794Speter 566794Speter /* 567794Speter * Skip action on error to 568794Speter * detect true unique inputs. 569794Speter * Error action is always first. 570794Speter */ 571794Speter if (*ap == -ERROR) 572*3088Smckusic ap += 2; 573794Speter 574794Speter /* 575794Speter * Loop through the test actions 576794Speter * for this state. 577794Speter */ 578*3088Smckusic for (actions = ap; *ap <= 0; ap += 2) { 579794Speter /* 580794Speter * Extract the token of this action 581794Speter */ 582794Speter acchar = -*ap; 583794Speter 584794Speter /* 585794Speter * Try insertion 586794Speter */ 587794Speter #ifdef DEBUG 588794Speter Tprintf(" Try Insert %s%s cost=%d\n" 589794Speter , charname(acchar , 0 ) 590794Speter , charname(acchar , 1 ) 591794Speter , inscost(acchar)); 592794Speter #endif 593794Speter c = inscost(acchar, YC[0].Yychar); 594794Speter #ifndef DEBUG 595794Speter if (c < ccost) { 596794Speter #endif 597794Speter if (c == 0) { 598794Speter c = correct(acchar, 0, 1, insmult + 1, Ps0, Pv0); 599794Speter #ifdef DEBUG 600794Speter Eprintf("Cost %2d Freebie %s%s\n", c 601794Speter , charname(acchar , 0 ) 602794Speter , charname(acchar , 1 )); 603794Speter #endif 604794Speter if (c < ccost) 605794Speter cact = CUNIQUE, ccost = 0, cchar = acchar, cflag = flag; 606794Speter } else { 607794Speter c = correct(acchar, 0, c, insmult, Ps0, Pv0); 608794Speter #ifdef DEBUG 609794Speter if (c < CPRLIMIT || fulltrace) 610794Speter Eprintf("Cost %2d Insert %s%s\n", c 611794Speter , charname(acchar , 0 ) 612794Speter , charname(acchar , 1 )); 613794Speter #endif 614794Speter if (c < ccost) 615794Speter cact = CINSERT, ccost = c, cchar = acchar, cflag = flag; 616794Speter } 617794Speter #ifndef DEBUG 618794Speter } 619794Speter #endif 620794Speter 621794Speter /* 622794Speter * Try replacement 623794Speter */ 624794Speter #ifdef DEBUG 625794Speter Tprintf(" Try Replace %s%s with %s%s cost=%d\n", 626794Speter tokname(&YC[0] , 0 ), 627794Speter tokname(&YC[0] , 1 ), 628794Speter charname(acchar , 0 ), 629794Speter charname(acchar , 1 ), 630794Speter repcost(YC[0].Yychar, acchar)); 631794Speter #endif 632794Speter c = repcost(YC[0].Yychar, acchar); 633794Speter #ifndef DEBUG 634794Speter if (c < ccost) { 635794Speter #endif 636794Speter c = correct(acchar, 1, repcost(YC[0].Yychar, acchar), repmult, Ps0, Pv0); 637794Speter #ifdef DEBUG 638794Speter if (c < CPRLIMIT || fulltrace) 639794Speter Eprintf("Cost %2d Replace %s%s with %s%s\n", 640794Speter c, 641794Speter tokname(&YC[0] , 0 ), 642794Speter tokname(&YC[0] , 1 ), 643794Speter tokname(&ACtok , 0 ), 644794Speter tokname(&ACtok , 1 )); 645794Speter #endif 646794Speter if (c < ccost) 647794Speter cact = CREPLACE, ccost = c, cchar = acchar, cflag = flag; 648794Speter #ifndef DEBUG 649794Speter } 650794Speter #endif 651794Speter } 652794Speter } 653794Speter 654794Speter int *yCpv; 655794Speter char yyredfail; 656794Speter 657794Speter /* 658794Speter * The ntok structure is used to build a 659794Speter * scanner structure for tokens inserted 660794Speter * from the argument "fchar" to "correct" below. 661794Speter */ 662794Speter static struct yytok ntok; 663794Speter 664794Speter /* 665794Speter * Compute the cost of a correction 666794Speter * C is the base cost for it. 667794Speter * Fchar is the first input character from 668794Speter * the current state, NOCHAR if none. 669794Speter * The rest of the inputs come from the array 670794Speter * YC, starting at origin and continuing to the 671794Speter * last character there, YC[yCcnt - 1].Yychar. 672794Speter * 673794Speter * The cost returned is INFINITE if this correction 674794Speter * allows no shifts, otherwise is weighted based 675794Speter * on the number of shifts this allows against the 676794Speter * maximum number possible with the available lookahead. 677794Speter */ 678794Speter correct(fchar, origin, c, multvec, Ps0, Pv0) 679794Speter register int fchar, c; 680794Speter int origin; 681794Speter char *multvec; 682794Speter int *Ps0, *Pv0; 683794Speter { 684794Speter register char *mv; 685794Speter 686794Speter /* 687794Speter * Ps is the top of the parse stack after the most 688794Speter * recent local correctness check. Loccor returns 689794Speter * NIL when we cannot shift. 690794Speter */ 691794Speter register int *ps; 692794Speter 693794Speter yyredfail = 0; 694794Speter /* 695794Speter * Initialize the tip parse and semantic stacks. 696794Speter */ 697794Speter ps = Ps0; 698794Speter yytips[0] = *ps; 699794Speter ps--; 700794Speter yytipv[0] = Pv0[0]; 701794Speter yCpv = Pv0 - 1; 702794Speter yytipct = 1; 703794Speter 704794Speter /* 705794Speter * Shift while possible. 706794Speter * Adjust cost as necessary. 707794Speter */ 708794Speter mv = multvec; 709794Speter do { 710794Speter if (fchar != NOCHAR) { 711794Speter copy(&ntok, &YC[0], sizeof ntok); 712794Speter ntok.Yychar = fchar, ntok.Yylval = nullsem(fchar); 713794Speter fchar = NOCHAR; 714794Speter ps = loccor(ps, &ntok); 715794Speter } else 716794Speter ps = loccor(ps, &YC[origin++]); 717794Speter if (ps == NIL) { 718794Speter if (yyredfail && mv > multvec) 719794Speter mv--; 720*3088Smckusic c *= *mv; 721794Speter break; 722794Speter } 723794Speter mv++; 724794Speter } while (*mv != 1); 725794Speter return (c); 726794Speter } 727794Speter 728794Speter extern int yygo[], yypgo[], yyr1[], yyr2[]; 729794Speter /* 730794Speter * Local syntactic correctness check. 731794Speter * The arguments to this routine are a 732794Speter * top of stack pointer, ps, and an input 733794Speter * token tok. Also, implicitly, the contents 734794Speter * of the yytips array which contains the tip 735794Speter * of the stack, and into which the new top 736794Speter * state on the stack will be placed if we shift. 737794Speter * 738794Speter * If we succeed, we return a new top of stack 739794Speter * pointer, else we return NIL. 740794Speter */ 741794Speter loccor(ps, ntok) 742794Speter int *ps; 743794Speter struct yytok *ntok; 744794Speter { 745794Speter register int *p, n; 746794Speter register int nchar; 747794Speter int i; 748794Speter 749794Speter if (ps == NIL) 750794Speter return (NIL); 751794Speter nchar = ntok->Yychar; 752794Speter yyeline = ntok->Yyeline; 753794Speter #ifdef DEBUG 754794Speter Tprintf(" Stack "); 755794Speter for (i = yytipct - 1; i >= 0; i--) 756794Speter Tprintf("%d ", yytips[i]); 757794Speter Tprintf("| %d, Input %s%s\n", *ps 758794Speter , charname(nchar , 0 ) 759794Speter , charname(nchar , 1 )); 760794Speter #endif 761794Speter /* 762794Speter * As in the yacc parser yyparse, 763794Speter * p traces through the action list 764794Speter * and "n" is the information associated 765794Speter * with the action. 766794Speter */ 767794Speter newstate: 768794Speter p = &yyact[ yypact[yytips[yytipct - 1]+1] ]; 769794Speter 770794Speter actn: 771794Speter /* 772794Speter * Search the parse actions table 773794Speter * for something useful to do. 774794Speter * While n is non-positive, it is the 775794Speter * arithmetic inverse of the token to be tested. 776794Speter * This allows a fast check. 777794Speter */ 778794Speter while ((n = *p++) <= 0) 779*3088Smckusic if ((n += nchar) != 0) 780794Speter p++; 781794Speter switch (n >> 12) { 782794Speter /* 783794Speter * SHIFT 784794Speter */ 785794Speter case 2: 786*3088Smckusic n &= 07777; 787794Speter yyredfail = 0; 788794Speter if (nchar == YID) 789794Speter yyredfail++; 790794Speter if (yytipct == YYTIPSIZ) { 791794Speter tipover: 792794Speter #ifdef DEBUG 793794Speter Tprintf("\tTIP OVFLO\n"); 794794Speter #endif 795794Speter return (NIL); 796794Speter } 797794Speter yytips[yytipct] = n; 798794Speter yytipv[yytipct] = ntok->Yylval; 799794Speter yytipct++; 800794Speter #ifdef DEBUG 801794Speter Tprintf("\tShift to state %d\n", n); 802794Speter #endif 803794Speter return (ps); 804794Speter /* 805794Speter * REDUCE 806794Speter */ 807794Speter case 3: 808*3088Smckusic n &= 07777; 809794Speter if (yyEactr(n, yytipv[yytipct - 1]) == 0) { 810794Speter #ifdef DEBUG 811794Speter Tprintf("\tYyEactr objects: have %s id, want %s id\n", classes[yyidhave], classes[yyidwant]); 812794Speter #endif 813794Speter return (NIL); 814794Speter } 815794Speter yyredfail = 0; 816794Speter i = yyr2[n]; 817794Speter #ifdef DEBUG 818794Speter Tprintf("\tReduce, length %d,", i); 819794Speter #endif 820794Speter if (i > yytipct) { 821*3088Smckusic i -= yytipct; 822794Speter yytipct = 0; 823*3088Smckusic ps -= i; 824*3088Smckusic yCpv -= i; 825794Speter } else 826*3088Smckusic yytipct -= i; 827794Speter if (yytipct >= YYTIPSIZ) 828794Speter goto tipover; 829794Speter /* 830794Speter * Use goto table to find next state 831794Speter */ 832794Speter p = &yygo[yypgo[yyr1[n]]]; 833794Speter i = yytipct ? yytips[yytipct - 1] : *ps; 834794Speter while (*p != i && *p >= 0) 835*3088Smckusic p += 2; 836794Speter #ifdef DEBUG 837794Speter Tprintf(" new state %d\n", p[1]); 838794Speter #endif 839794Speter yytips[yytipct] = p[1]; 840794Speter yytipct++; 841794Speter goto newstate; 842794Speter /* 843794Speter * ACCEPT 844794Speter */ 845794Speter case 4: 846794Speter #ifdef DEBUG 847794Speter Tprintf("\tAccept\n"); 848794Speter #endif 849794Speter return (ps); 850794Speter /* 851794Speter * ERROR 852794Speter */ 853794Speter case 1: 854794Speter #ifdef DEBUG 855794Speter Tprintf("\tError\n"); 856794Speter #endif 857794Speter return (0); 858794Speter } 859794Speter panic("loccor"); 860794Speter } 861