This is prserr.c in view mode; [Download] [Up]
/* * Copyright (C) 1985-1992 New York University * * This file is part of the Ada/Ed-C system. See the Ada/Ed README file for * warranty (none) and distribution info and also the GNU General Public * License for more details. */ /******************************************************************** * * ***************** * * P R S E R R * ***************** * * Written by * Brian Siritzky * 1983 * ********************************************************************/ /********************************************************************/ /********************************************************************/ #include "ada.h" #include "adalexprots.h" #include "actionprots.h" #include "pspansprots.h" #include "errsprots.h" #include "lookupprots.h" #include "prsutilprots.h" #include "recoverprots.h" #include "makecorrprots.h" #include "prserrprots.h" static void get_poss_tok(); static void get_next(int); /* * Variables needed for scope and secondary recoveries */ struct two_pool *closer_toksyms ; struct two_pool *closer_bottom ; struct two_pool *POSS_TOK; /* struct prsstack **tokens; deleted on Sam's suggestion 12-11-84 */ int TOKSYMS[S_TOKSYMS], n_TOKSYMS; int BACKUPTOKS = 0; int MAX_CHECK = MIN_LEN ; PCAND next_c, y, next_cand, CANDIDATES[C_BOUND]; static PCAND tmp_cand,temp_cand; int n_CANDIDATES[C_BOUND] ; int nps; int n_open_seq; int *open_seq; int n_closer_toksyms; void prserr(struct prsstack *curtok) /*;prserr*/ { /******************************************************************** * * This routine is the syntactic error recovery routine. It at- * tempts to correct simple errors and when that is not possible, * deletes tokens possibly to the left and to the right of the error * point until the parse can safely resume. The process is thus di- * vided naturally into two parts, called primary and secondary * recovery. Both primary and secondary recovery include efforts at * "scope recovery": i.e. the closing of lexically open scopes * through the insertion of one or more closer token sequences. Ex- * amples of such sequences are right parentheses, "END ;", and "END * IF;". * * Primary recovery consists of the simple corrections - merging to- * kens, substituting a token (including a reserved word that is * misspelled as an identifier), inserting a token, and deleting a * token - along with scope recovery. * * An attempt at simple correction at either the error token or at * some parse stack element is called a trial. * * For the first trial simple corrections are attempted at the token * at which the error was detected (the error token), with the parse * in the configuration obtaining just after the shifting of the * previous token. In order to back up to the succeeding trial, the * top elements are peeled from the state and parse stacks, with the * top element of the parse stack appended to the front of the input * token sequence. Again attempts at simple correction are made. The * process is repeated until the determined extent of the backup * move has been accomplished. * * The criterion by which the effectiveness of a simple correction * candidate is measured is the distance it allows the parse to pro- * gress into the forward context (up to MAX_LOOK_AHEAD = 25 to- * kens). During the simple correction trials we gather together * the CANDIDATES that allow the parse to progress the furthest, * provided that an advance of at least MIN_CHECK is accomplished * (if not, then CANDIDATES is empty and simple correction fails). * If CANDIDATES is not empty, it is pruned in accordance with cer- * tain restrictions described below, and then one of them is chosen * as the appropriate correction provided that a condition described * below is satisfied. * * No attempt is made to delete or substitute for a nonterminal. * * If no simple correction is chosen, scope recovery is attempted at * each point at which simple recovery was attempted. The scope * recovery procedure determines whether the insertion of a sequence * of scope closers allows the parse to progress MIN_LEN distance * into the forward context. If so, this multiple insertion is * chosen as the correction candidate. * * If scope recovery also fails, then secondary recovery is invoked. * The parse is restored to the configuration obtaining upon en- * trance to PRSERR, and each parse stack element is tested - in se- * quence from the top - to see whether parsing can resume from that * point, perhaps with the inclusion of one or more closer token se- * quences. The extent of the advance required in order for the * parse to be regarded as successfully resumed depends upon the * current token, but is at least MIN_LEN. * * If secondary recovery at the current token does not succeed, it * is ignored and the next one obtained and the same check is re- * peated. Eventually, there must be an input for which the parse * can continue, because the end of file token, EOFT, is compatible * with a state on the state stack. * * When the recovery point is found, control is returned to the * parser. It is assured that parsing can continue beyond the error * token. * ********************************************************************/ /* PARSE STACK and BINARY TUPLE STRUCTURES */ typedef struct two_pool *TUPLE; struct prsstack *ERROR_TOKEN; struct prsstack *oldprevtok;/* Saved for scope and secondary recovery */ struct prsstack *tmp_ps; TUPLE STATE_STACK = NULL; TUPLE prs_toks = NULL; /* Used to determine the no of */ TUPLE tmp_tp; /* trials to be performed */ /* Used for freeing storage */ TUPLE prs_stack_syms = NULL; int pb; /* Used as a flag to check for a parse block */ int threshold, /* Used to prune candidates */ exists; /* Flag used in list searching */ short trials, /* Number of trials performed */ j, r, trial, i, /* Loop and auxilliary */ bk, cc, x, si ; int n_PARSE_STACK; int save_n_TOKSYMS ; struct two_pool *states; int n_single_cand_modes, total_CANDIDATES; int n_STATE_STACK, n_sta_stack; ERROR_TOKEN = copytoken (curtok); MAX_CHECK = MIN_LEN; /* ERR_MSGS = NULL ; CLOSER_TOKSYMS = NULL ; */ copystack (sta_stack, &STATE_STACK, &n_sta_stack); /* save for scope and secondary recovery */ if (PREVTOK != NULL) oldprevtok = copytoken (PREVTOK); n_STATE_STACK = n_sta_stack; BACKUPTOKS = 0; get_next (MAX_LOOK_AHEAD); /* prs_stack_syms := [r(1) : r in PRS_STACK]; * Loop over PRS_STACK, collecting the symbols in a list * headed by prs_stack_syms. While doing this, count up the * number of elements in the parse stack, keeping this in * n_PARSE_STACK and nps */ n_PARSE_STACK = 0; if ((tmp_ps= prs_stack) == NULL)/* Check for empty stacks */ prs_stack_syms = NULL; else { /* otherwise copy the list */ /* Treat the first element as a special case */ tmp_tp = prs_stack_syms = TALLOC (); tmp_tp -> link = NULL; tmp_tp -> val.state = tmp_ps -> symbol; n_PARSE_STACK = 1; /* Loop over the rest of the stack */ while (tmp_ps -> prev != NULL) { tmp_tp -> link = TALLOC (); tmp_tp = tmp_tp -> link; tmp_ps = tmp_ps -> prev; tmp_tp -> val.state = tmp_ps -> symbol; n_PARSE_STACK++; } /* while */ tmp_tp -> link = NULL; } /* else */ nps = n_PARSE_STACK; /* * TOKSYMS := [t(1) : t in TOKENS]; * Loop over TOKENS, collecting the symbols in a list * The integer tokind is a count of the number of * elements in the array tokens. * * Note that tokens[tokind] is the next token, so we must * reverse the order of TOKSYMS */ /* Put the current token at the top of the token stack */ tokens[tokind = (tokind + 1) % toksiz] = curtok; i = 0; j = tokbottom; for (;;) { TOKSYMS[i] = tokens[j]->symbol; if (j == tokind) break; j = (j + 1) % toksiz; i++; } save_n_TOKSYMS = n_TOKSYMS = (toksiz + tokind - tokbottom) % toksiz; /* for (i = 0; i <= tokind; i++) TOKSYMS[i] = tokens[i] -> symbol; n_TOKSYMS = tokind; */ dump_toksyms ("At creation"); /******************************************************************* * * S I M P L E R E C O V E R Y * *******************************************************************/ /* Simple Recovery begins here */ /* Determine number of trials to be performed. */ prs_toks = TALLOC (); prs_toks -> val.state = curtok -> symbol; prs_toks -> link = NULL; /* trials = (nps>0) ? nps : 1 ; */ trials = (n_sta_stack>0) ? n_sta_stack : 1 ; states = TALLOC (); states -> link = NULL; /* for (j = nps; j >= 1; j--) */ for (j = n_sta_stack; j >= 2; j--) { int jj; /* prs_stack_syms(j) is at position (nps - j) in the linked list. * For this reason we need to follow the links this many times */ /* jj = nps - j + 1; */ jj = n_sta_stack - j + 1; tmp_tp = prs_stack_syms; while (jj-- > 1) tmp_tp = tmp_tp -> link; r = tmp_tp -> val.state; /* r := prs_stack_syms(j) */ #ifdef DEBUG if (trcopt) { fprintf(errfile,"j = %d n_sta_stack = %d r = %d\n", j,n_sta_stack,r); } #endif /* dump_stack(prs_toks); */ /* Check whether it is possible to parse past symbol * and through the error token. * * if forall s in SHIFT_STATES(r) | prs_block(s, prs_toks) * then * trials := nps - j + (if is_terminal(r) then 2 else 1 end); * quit; * end if; */ pb = TRUE; /* Assume that the parse will block */ /* Loop through SHIFT_STATES(r). This is the array SHIFT_STATES from * position SHIFT_STATE_INDEX(r-1) to SHIFT_STATE_INDEX(r) - 1 * Each time check if the parse blocks, pb. If it does not then end the * testing. */ for (si = SHIFT_STATE_INDEX[r - 1]; ((si <= (SHIFT_STATE_INDEX[r] - 1)) && pb); si++) { states -> val.state = SHIFT_STATE[si]; pb = pb && prs_block (states, prs_toks); #ifdef DEBUG if (trcopt) fprintf(errfile,"state: %d prsblock: %d\n", states->val.state, prs_block(states,prs_toks) ); #endif } if (pb) { /* If the parse blocks then terminate */ /*trials = 1 + nps - j + (is_terminal (r - 1) ? 2 : 1);*/ trials = 1 + n_sta_stack - j + (is_terminal (r) ? 2 : 1); break; /* Outer loop */ } tmp_tp = TALLOC (); tmp_tp -> link = prs_toks; tmp_tp -> val.state = r; prs_toks = tmp_tp; } /* end for */ if (nps == 0) trials = 1; /* To deal with empty parse stacks */ #ifdef DEBUG if (trcopt) fprintf(errfile,"trials = %d\n",trials); #endif for (trial = 1; trial <= trials; trial++) { /* Attempt simple recovery at token backed up to. */ #ifdef DEBUG if (trcopt) { fprintf(errfile,"Backup Recovery, trial number is: %d\n",trial); fprintf(errfile,"STATE STACK:\n"); dump_stack(sta_stack); fprintf(errfile,"PARSE STACK:\n"); dump_prssyms(prs_stack_syms); fprintf(errfile,"TOKENS:\n"); dump_toksyms(""); } #endif /* Form set of candidates for insertion and substitution. */ get_poss_tok (); /* Make insertion test. */ try_insertion (); /* Attempt substitution for current token */ try_substitution (); /* Try merging tokens. */ if (trial == 1) try_merge (curtok, nexttok); else if (trial == 2) try_merge (PREVTOK, curtok); /* Check whether parsing can resume with the next token. */ try_deletion (); /* Now we peel off the top state and try again. * Put the "token" (terminal or nonterminal) for previous state on * the list of tokens, and increase backuptoks accordingly. */ tmp_tp = sta_stack; sta_stack = sta_stack -> link; n_sta_stack--; tmp_tp = prs_stack_syms; if (prs_stack != NULL) { TOKSYMS[++n_TOKSYMS] = prs_stack_syms -> val.state; prs_stack_syms = prs_stack_syms -> link; } BACKUPTOKS++; } /* for */ /* Form misspelling candidates by applying string distance test in cases * where a reserved word to be substituted for an identifier. */ if (0 && CANDIDATES[SUBST] != NULL) { #ifdef DEBUG if (trcopt) fprintf (errfile, "CANDIDATES[SUBST] != NULL, (#=%d)\n", n_CANDIDATES[SUBST]); #endif /* spell_substs := {[u, v, w] in CANDIDATES(SUBST) | * is_reserved(u) and v = ID_SYM * and spell(namelist(u), namelist( * (w = 0 ? curtok : PRS_STACK(nps - w + 1) )(2)))}; * * Note : u == token_sym, v == backup_toks, w == t3 * * Loop over the list headed by CANDIDATES[SUBST], selecting * all those elements which satisfy the above conditions * * The spell function used here is a less accurate measure than the * SETL version. It returns an integer value in the range [0,3], * where 0, 1 & 2 imply misspellings. */ nps = stack_count(prs_stack) ; next_c = CANDIDATES[SUBST]; while (next_c != NULL) { short symb; /* Utility variable */ PCAND follow_c ; follow_c = next_c-> next ; /* Calculate the word to be compared to according to * symb = (w==0)?curtok : prs_stack(nps -w + 1) */ if (next_c -> backup_toks == 0) symb = curtok -> symbol; else { /* PRSSTACK[nps-w-1].symbol */ int kk = nps - next_c->backup_toks ; tmp_ps = prs_stack; while(--kk) tmp_ps = tmp_ps -> prev; symb = tmp_ps -> symbol; } if ( (is_reserved (next_c -> token_sym)) && (next_c -> t3 == ID_SYM) && ((spell (TOKSTR (next_c -> token_sym), TOKSTR (symb))) < 3 ) ) { /* Add it to the list of SPELL_SUBSTs. */ next_c-> next = CANDIDATES[SPELL_SUBST] ; CANDIDATES[SPELL_SUBST] = next_c ; n_CANDIDATES[SPELL_SUBST]++; n_CANDIDATES[SUBST]--; } next_c = follow_c ; } } #ifdef DEBUG if (trcopt) { fprintf(errfile,"Candidates BEFORE pruning\n"); dump_cand(); } #endif /* The correction candidates now include only those that have checked * the furthest distance into the forward context. * Prune this set by applying the preferences and restrictions relevant * in each case. */ /* If a long parse check has been achieved, set threshold to true. */ threshold = (MAX_CHECK >= (MIN_LEN + 3)); /* (for y = CANDIDATES(x)) */ for (x = DELETE; x <= SPELL_SUBST; x++) { y = CANDIDATES[x]; if (y == NULL) /* Check for null candidate list */ continue; switch (x) { case DELETE: /* Remove all reserved word deletions if another deletion exists * and all such deletions if below the threshold */ next_cand = CANDIDATES[DELETE]; exists = FALSE; while ((next_cand != NULL) && (!exists)) { exists = exists && (next_cand -> token_sym > RESERVED_SYMS); next_cand = next_cand -> next; } if ((!threshold) || exists) { /* y -:= {[token_sym,-,-] in y | is_reserved(token_sym) } * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition */ next_cand = CANDIDATES[x]; n_CANDIDATES[x] = 0; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ tmp_cand = next_cand -> next; if (!is_reserved (next_cand -> token_sym)) { /* Add it to the front of the list */ n_CANDIDATES[x]++; next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; } next_cand = tmp_cand; } } /* Prefer deletion closest to error token. */ if (y != NULL) { /* bk := min/{t(2) : t in y}; */ next_cand = y; bk = next_cand -> backup_toks; next_cand = next_cand -> next; while (next_cand != NULL) { bk = MIN (bk, next_cand -> backup_toks); next_cand = next_cand -> next; } n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ tmp_cand = next_cand -> next; if (next_cand -> backup_toks == bk) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = tmp_cand; } } break; case INSERT: /* Remove all insertions of reserved words if below threshold */ if (!threshold) { /* y -:= {[token_sym,-,-] in y | is_reserved(token_sym) } * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition */ n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ tmp_cand = next_cand -> next; if (!is_reserved (next_cand -> token_sym)) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = tmp_cand; } } /* Prefer insertions closest to error token. */ if (CANDIDATES[x] != NULL) { /* bk := min/{t(3) : t in y}; */ next_cand = y; bk = next_cand -> backup_toks; next_cand = next_cand -> next; while (next_cand != NULL) { bk = MIN (bk, next_cand -> backup_toks); next_cand = next_cand -> next; } /* y := {[-,backup_toks,-] in y | backup_toks = bk) } * * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition * While doing this, check if there are any elements that * satisfy the condition * (token_sym in ALWAYS_PREFERRED_SYMS) * If there are any they can be used to further prune the * list. A flag 'exists' will be used for this purpose. */ n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; exists = FALSE; /* Assume none in ALWAYS_PREFERRED_SYMS */ while (next_cand != NULL) { /* there are more candidates */ tmp_cand = next_cand -> next; if (next_cand -> backup_toks == bk) { exists = exists || in_ALWAYS_PREFERRED_SYMS (next_cand -> token_sym); next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = tmp_cand; } } /* Apply preferred insertions (if any exist) * * pi := {[u, v, w] in y | u in ALWAYS_PREFERRED_SYMS}; * if (pi != {}) y = pi; */ if (exists) { /* then prune the list accordingly */ /* y := {[token_sym,-,-] in y | token_sym in * ALWAYS_PREFERRED_SYMS } * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition */ n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ tmp_cand = next_cand -> next; if (in_ALWAYS_PREFERRED_SYMS (next_cand -> token_sym)) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = tmp_cand; } } break; case SUBST: /* Apply preferred substitutions * * Check to see whether there are any elements which satisfy * either of the conditions * token_sym in PREFERRED_FOR_SYMS{v} * or token_sym = ID_SYM and is_reserved(v) * If at least one is found then set y to be ps, where ps is * * ps := {[u, v, w] in y | u in PREFERRED_FOR_SYMS{v} * or (u = ID_SYM and is_reserved(v))}; * * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition */ /* check for existence */ next_cand = CANDIDATES[x]; exists = FALSE; /* Assume none */ while ((next_cand != NULL) && (!exists)) { /* there are more candidates */ exists = exists || in_PREFERRED_FOR_SYMS( next_cand -> t3, next_cand -> token_sym) || ((next_cand -> token_sym == ID_SYM) && (is_reserved (next_cand -> t3))); next_cand = next_cand -> next; } /* If some exist then y is set to be those only */ if (exists) { n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ temp_cand = next_cand -> next; if ( in_PREFERRED_FOR_SYMS( next_cand -> t3, next_cand -> token_sym ) || ((next_cand -> token_sym == ID_SYM) && is_reserved (next_cand -> t3))) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = temp_cand; } } else if (!threshold) { /* None exist */ /* Remove all substitutions involving reserved words if below * the threshold. */ /* y -:= {[u, v, w] in y | * is_reserved(u) or is_reserved(v)}; */ n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { temp_cand = next_cand -> next; if (!((is_reserved (next_cand -> t3)) || (is_reserved (next_cand -> token_sym))) ) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = temp_cand; } } /* Prefer substitutions closest to error token. */ if (CANDIDATES[x] != NULL) { /* bk := min/{t(3) : t in y}; */ next_cand = y; bk = next_cand -> backup_toks; next_cand = next_cand -> next; while (next_cand != NULL) { bk = MIN (bk, next_cand -> backup_toks); next_cand = next_cand -> next; } n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ temp_cand = next_cand -> next; if (next_cand -> backup_toks == bk) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]++; } next_cand = temp_cand; } } break; case SPELL_SUBST: /* Prefer closest to error token. */ /* bk := min/{t(3) : t in y}; */ next_cand = y; bk = next_cand -> backup_toks; next_cand = next_cand -> next; while (next_cand != NULL) { bk = MIN (bk, next_cand -> backup_toks); next_cand = next_cand -> next; } /* y := {[-,-,t3] in y | t3=bk } * This is achieved by looping over the list headed by y * and deleting those elements which satisfy the condition */ if (CANDIDATES[x] != NULL) { n_CANDIDATES[x] = 0; next_cand = CANDIDATES[x]; CANDIDATES[x] = NULL; while (next_cand != NULL) { /* there are more candidates */ temp_cand = next_cand -> next; if (next_cand -> backup_toks == bk) { next_cand -> next = CANDIDATES[x]; CANDIDATES[x] = next_cand; n_CANDIDATES[x]--; } next_cand = temp_cand; } } break; case MERGE: break; } /* switch */ } /* for */ #ifdef DEBUG if (trcopt) { fprintf(errfile,"Candidates AFTER pruning:\n"); dump_cand(); } #endif /* For each mode - merge, spelling, insertion, substitution, deletion - * there are zero or more correction candidates. * If one or mode has exactly one correction candidate, then one of those * candidates is chosen. * * If no mode has a single candidate, then a simple correction candidate * is only chosen if the long check distance has been achieved * (MAX_CHECK >= MIN_LEN + 3). * * The preference order among the correction modes is : merge, spelling, * insertion, deletion, substitution. */ /* Calculate the number of single_cand_modes */ /* and the total number of CANDIDATES */ n_single_cand_modes = 0; total_CANDIDATES = 0; for (cc = DELETE; cc <= SPELL_SUBST; cc++) { if (n_CANDIDATES[cc] == 1) n_single_cand_modes++; total_CANDIDATES += n_CANDIDATES[cc]; } if (n_single_cand_modes > 0) { /* Apply one final preference rule where there remains a single * deletion and a single insertion candidate - prefer deletion of * operator or punctuation symbol to insertion of such a symbol. */ if ((n_CANDIDATES[DELETE] == 1) && ((n_CANDIDATES[INSERT]) == 1) && is_operator (CANDIDATES[DELETE] -> token_sym) && is_operator (CANDIDATES[INSERT] -> token_sym)) { /* Set CANDIDATES[INSERT] to NULL and dispose of the list */ CANDIDATES[INSERT] = NULL; n_CANDIDATES[INSERT] = 0; n_single_cand_modes--; total_CANDIDATES--; } /* Set all CANDIDATES which have more than 1 element to NULL * and dispose of their lists */ for (cc = DELETE; cc <= SPELL_SUBST; cc++) if (n_CANDIDATES[cc] > 1) { CANDIDATES[cc] = NULL; n_CANDIDATES[cc] = 0; } } /* if */ if ((n_single_cand_modes > 0) || ((total_CANDIDATES > 0) && threshold)) { make_correction (STATE_STACK); return; } /* Primary recovery has failed if we reach this point. * Reset parse configuration for scope recovery. */ copystack (STATE_STACK, &sta_stack, &n_STATE_STACK); /* TOKSYMS(n_TOKENS + 1 .. ) := []; */ n_TOKSYMS = save_n_TOKSYMS ; BACKUPTOKS = 0; /************************************************************************ * * E N D O F P R I M A R Y R E C O V E R Y * ************************************************************************/ /************************************************************************ * * Scope recovery * ************************************************************************/ /* SCOPE */ { int j; struct prsstack *prstmp; struct two_pool *tuptmp; struct two_pool *statmp; struct tok_loc *prev_tok_loc; /* struct tok_loc *prev_tok_loc = &PREVTOK->ptr.token->loc; */ if (PREVTOK != NULL) prev_tok_loc = &PREVTOK->ptr.token->loc; /* Allocate an array the size of the parse stack */ open_seq = (int *)malloc((unsigned) (nps * sizeof(int))); #ifdef DEBUG if (trcopt) fprintf(errfile,"SCOPE OPENERS = \n"); #endif for (n_open_seq = 0,j = nps, prstmp = prs_stack; prstmp != NULL; prstmp = prstmp->prev, j--) { if (is_opener(prstmp->symbol)) { open_seq[n_open_seq++] = j; #ifdef DEBUG if (trcopt) fprintf(errfile,"[ %s %d ] ",TOKSTR(prstmp->symbol),j); #endif } } #ifdef DEBUG if (trcopt) fprintf(errfile,"\n"); #endif /* for debugging purposes try one less trial */ trials-- ; closer_toksyms = NULL; closer_bottom = NULL; for (trial = 1 ; trial <= trials ; trial ++ ) { #ifdef DEBUG if (trcopt) fprintf(errfile,"Scope Recovery Trial = %d\n",trial); #endif if (scope_recovery(n_STATE_STACK,0,open_seq)) { for (tuptmp = closer_toksyms; tuptmp != NULL; tuptmp = tuptmp->link) { prstmp = PRSALLOC(); prstmp->ptr.token = TOKALLOC(); prstmp->symbol =prstmp->ptr.token->index =tuptmp->val.state; prstmp->ptr.token->loc.line = prev_tok_loc->line; prstmp->ptr.token->loc.col = prev_tok_loc->col; ADDTOTOP(prstmp); } /* if (closer_toksyms != NULL) * TFREE(closer_toksyms,closer_bottom); */ n_closer_toksyms = 0 ; return; } /* if (closer_toksyms != NULL) * TFREE(closer_toksyms,closer_bottom); */ n_closer_toksyms = 0 ; /* Back up for the next trial */ if (trial == trials) break; statmp = sta_stack; sta_stack = sta_stack->link; TFREE(statmp,statmp); n_STATE_STACK -- ; prstmp = prs_stack; prs_stack = prs_stack->prev; nps-- ; ADDTOTOP(prstmp); TOKSYMS[++n_TOKSYMS] = prstmp->symbol; BACKUPTOKS++; prev_tok_loc = RLOC(prs_stack); } /* To get here scope recovery has failed, try other recoveries */ /* First restore the parse configuration for secondary recovery */ copystack(STATE_STACK,&sta_stack,&n_sta_stack) ; for (trial = 1 ; trial < trials ; trial ++) { struct prsstack *tmp_ps ; tmp_ps = tokens[tokind]; n_TOKSYMS -- ; TOKMINUS ; tmp_ps->prev = prs_stack ; prs_stack = tmp_ps ; nps ++ ; } PREVTOK = oldprevtok ; BACKUPTOKS = 0 ; } /************************************************************************ * * Secondary recovery * ************************************************************************/ /*SEC*/ /* Now try secondary recoveries. * First try deleting the error token and some sequence of tokens in the * forward context - stop at a beacon symbol. */ { #define sec_check MIN_LEN char tmp_str[500], err_msgs[500]; int equal; int nst; int n_stack_del_syms; int t, kk, j, k; int *stack_delete_syms; struct tok_loc leftt, rightt; err_msgs[0] = '\0' ; /* initialize to null string */ for (k = 1; k <= MAX_LOOK_AHEAD - (MIN_LEN + 3); k++) { t = TOKSYMS[n_TOKSYMS--]; #ifdef DEBUG if (trcopt) fprintf (errfile, "take token off TOKSYMS (%s)\n", TOKSTR (t)); #endif if((kk=prs_check(sta_stack, TOKSYMS, n_TOKSYMS)) >= (MIN_LEN + 3)) { /* changed +2 to +3, gcs */ /* delete k tokens */ /* rightt := TOKENS(n_TOKENS - k + 1); * TOKENS(n_TOKENS - k + 1 ..) := []; */ for (i = 1; i < k; i++) TOKMINUS; rightt = r_span (tokens[tokind]); TOKMINUS; syntax_err (LLOC (ERROR_TOKEN), &rightt, "Unexpected input"); return; } /* For now, ignore to conform with SETL (BEACON_SYMS is empty) * if (in_BEACON_SYMS (t)) * break; */ } /* Try to resume the parse - perhaps with the inclusion of a sequence of * scope closers- from some state on the state stack. * After each attempt the current token is deleted. * To succeed on arbitrary input, some state must accept EOFT. */ #ifdef DEBUG if (trcopt) fprintf(errfile,"********** SECONDARY RECOVERY **********\n"); #endif nst = stack_size (sta_stack); while (1) { struct two_pool *sta_stack_copy; get_next(sec_check + 2); /* ensure that there are ample */ /* TOKSYMS := [t(1) : t in TOKENS]; */ i = 0; j = tokbottom; for (;;) { TOKSYMS[i] = tokens[j] -> symbol; if (j == tokind) break; j = (j + 1) % toksiz; i++; } n_TOKSYMS = (toksiz + tokind - tokbottom) % toksiz; curtok = tokens[tokind]; #ifdef DEBUG if (trcopt) { fprintf(errfile,"TRYING: %s\n",TOKSTR(TOKSYMS[n_TOKSYMS]) ); fprintf(errfile, "\ttoksize = %d tokbottom = %d tokind = %d curtok = %s\n", toksiz,tokbottom,tokind,find_name(curtok) ); } #endif copystack (sta_stack, &sta_stack_copy, &nst); for (k = nst; k >= 1; k--) { /* Try peeling stacks. */ /* Strip n_sta_stack - k - 1 elements off the state stack */ kk = stack_size (sta_stack_copy) - k; /* while (--kk > 0) * sta_stack_copy = sta_stack_copy -> link; */ if ( (kk=prs_check (sta_stack_copy, TOKSYMS, n_TOKSYMS)) >= (sec_check + 2)) { /* (sec_check + 1)) */ /* Form the error message and quit the outer loop */ sprintf (err_msgs, "%s", err_message (k,curtok)); #ifdef DEBUG if (trcopt) fprintf(errfile,"prs_check succeeded for k = %d\n",k); #endif goto quit_loop_do; } /* Try closer recovery. */ /* Make a copy of the state stack for later restoration */ if (scope_recovery (k, 0, open_seq)) { /* Form the error message and quit the outer loop */ sprintf (tmp_str, "%s", err_msgs); sprintf (err_msgs, "%s -- %s", err_message(k,curtok), tmp_str); #ifdef DEBUG if (trcopt) fprintf(errfile, "scope_recovery succeeded for k = %d\n",k); #endif goto quit_loop_do; } /* pop element of the state stack */ sta_stack_copy = sta_stack_copy -> link; closer_toksyms = NULL; } /* Get next token */ #ifdef IGNORE PREVTOK = tokens[tokind]; /* This is a fix proposed by Sam Chin for cases when the entire * text is garbage. If there are tokens on the list of lookahead * tokens then take the token, otherwise, if not then take it from * the input stream. If while deleting the tokens an end of file * is reached, output the appropriate message and quit the * secondary recovery */ curtok = NEXTTOK ; #ifdef DEBUG if (trcopt) fprintf(errfile,"curtok = %s\n",find_name(curtok)); #endif if (curtok->symbol == EOFT_SYM) { sprintf(err_msgs,"End-of-file reached while trying to recover"); goto quit_loop_do ; } if (tokind >= MAX_LOOK_AHEAD) { curtok = copytoken(tokens[tokind]) ; #ifdef DEBUG if (trcopt) fprintf(errfile,"curtok updated to %s\n", find_name(curtok)); #endif } #endif /* implement next_token macro (correctly), as done in SETL */ PREVTOK = curtok; TOKMINUS; if ((toksiz + tokind - tokbottom + 1) % toksiz == 0) tokens[tokbottom=(toksiz+tokbottom-1)%toksiz] = gettok(); /* NEXTTOK; */ /* copytoken (curtok, tokens[tokind]); */ } quit_loop_do: ; /* LABEL for goto */ /* At this point we have recovered. * Locate the range of the error. */ n_stack_del_syms = 0; if (nst > k && k > 0 && prs_stack != NULL) { /* check for empty parse stack and k not zero (i.e. end of file) */ /* stack_delete_syms := [PRS_STACK(t)(1) : t in [nps, nps - 1 .. k + 1]]; */ /* nps = stack_count (prs_stack); */ tmp_ps = prs_stack; stack_delete_syms = (int *) malloc ((unsigned) ((nst - k ) * sizeof (int))); /* stack_delete_syms = (int *) malloc ((k + 1) * sizeof (int)); */ for (t = nst; t >= k + 1; t--) { stack_delete_syms[n_stack_del_syms++] = tmp_ps -> symbol; tmp_ps = tmp_ps -> prev; } leftt = l_span (tmp_ps); /* PRS_STACK(k + 1 .. ) := []; * STA_STACK(k + 1 .. ) := []; */ kk = stack_size (sta_stack) - k; while ( kk-- > 0) { sta_stack = sta_stack -> link; prs_stack = prs_stack -> prev; } } else leftt = l_span (ERROR_TOKEN); /* Form error location. */ /* * Check whether * stack_delete_syms = * TOKSYMS(#TOKSYMS - #stack_del_syms + 1 .. #stack_del_syms) * * Assume equal and check element by element */ equal = 1; for (j = n_stack_del_syms - 1 , k = n_TOKSYMS ; ((j >= 0) && (equal)) ; k--, j--) equal = equal && (stack_delete_syms[j] == TOKSYMS[k]); if ((n_stack_del_syms != 0) && (n_stack_del_syms <= n_TOKSYMS) && equal) { /* PRSERR_LOC = loc_range(LLOC(ERROR_TOKEN), LLOC(TOKENS[(tokind - * n_stack_del_syms + 1) % toksiz] ), RLOC(ERROR_TOKEN)); * for now just print the spans */ syntax_err (LLOC (ERROR_TOKEN), RLOC (ERROR_TOKEN), err_msgs); } else { /* PRSERR_LOC = * loc_range(LLOC(leftt), LLOC(PREVTOK), RLOC(ERROR_TOKEN)); * for now just print the spans */ syntax_err (&leftt, RLOC (ERROR_TOKEN), err_msgs); } /* If the secondary recovery involves a scope recovery, insert the * closer tokens. */ if (closer_toksyms != NULL) { /* TOKENS +:= [[t, t, top(PREVTOK)] : t in CLOSER_TOKSYMS]; */ for(tmp_tp =closer_toksyms; tmp_tp != NULL; tmp_tp = tmp_tp -> link) { ADDTOTOP (PRSALLOC()); tokens[tokind] -> symbol = tmp_tp -> val.state; tokens[tokind] -> ptr.token = TOKALLOC (); tokens[tokind] -> ptr.token -> index = tmp_tp -> val.state; tokens[tokind] -> ptr.token -> loc = PREVTOK -> ptr.token ->loc; } } return; } } /* End of Procedure prserr */ static void get_poss_tok() /*;get_poss_tok*/ { struct two_pool *temp_sta_stack; /* Points to saved copy of state stack */ struct two_pool *act_sta = NULL ; /* Stored list of acceptable actions */ int ss = sta_stack->val.state ; /* The top of the state stack */ struct two_pool *tmp_tp ; /* utility variables */ struct two_pool *tmp ; short red,dr ; int n ,n_temp_sta_stack ; /* Get the tokens that are acceptable to the top state on the stack. */ copystack(sta_stack,&temp_sta_stack,&n_temp_sta_stack); while ((dr = def_action[ss - 1]) != 0) { tmp = TALLOC() ; /* act_sta with := ss */ tmp->val.state = ss ; tmp->link = act_sta ; act_sta = tmp ; red = dr - NUM_STATES - 1 ; /* Strip "rhslen[red]" elements from the temp_sta_stack */ n = rhslen[red] ; if(!n) { tmp = TALLOC() ; tmp->link = temp_sta_stack ; temp_sta_stack = tmp ; } else if( n > 1 ) { while( --n > 1 ) temp_sta_stack = temp_sta_stack->link ; tmp = temp_sta_stack ; temp_sta_stack = temp_sta_stack->link ; } else if (n < 0) break ; temp_sta_stack->val.state = action((int)(temp_sta_stack->link->val.state),lhs[red]); ss = temp_sta_stack->val.state ; } tmp = TALLOC() ; tmp->val.state = ss ; tmp->link = act_sta ; act_sta = tmp ; /* * POSS_TOK := +/{ACTION_TOKENS(s) : s in act_sta}; * Since ACTION_TOKENS(s) is a set of numbers, for each s we must * loop over the set, adding the values to the list POSS_TOK */ POSS_TOK = NULL ; while (act_sta != NULL) { int a ; for(a = ACTION_TOKENS_INDEX[(int)(act_sta->val.state) - 1] ; a <= (ACTION_TOKENS_INDEX[(int)(act_sta->val.state)] - 1) ; a ++ ) { /* Add ACTION_TOKENS(a) to the list */ tmp_tp = TALLOC() ; tmp_tp->link = POSS_TOK ; tmp_tp->val.state = ACTION_TOKENS[a] ; POSS_TOK = tmp_tp ; } act_sta = act_sta->link ; } } static void get_next(int k) /*;get_next*/ { /* This procedure ensures that tokens contains at least k tokens. * Note that tokind always points to the next token, so that the * array must be read in in reverse order */ int i; /* First check if this is the first time, and if so allocate space for * tokens. */ if (tokind == -1) { tokens = (struct prsstack **)malloc((unsigned)(2*k*sizeof(struct prsstack *))); toksiz = 2 * k; } /* for now only put in k-1 tokens, since the current token has to be * inserted. */ for (i = k - ((toksiz + (tokind - tokbottom + 1)) % toksiz); i>0 ; i--) { tokbottom = (toksiz + tokbottom - 1) % toksiz; tokens[tokbottom] = gettok(); } if (tokind == -1) tokind = toksiz - 1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.