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