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