+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.compiler.parser.diagnose;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.parser.Parser;
-import org.eclipse.jdt.internal.compiler.parser.ParserBasicInformation;
-import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
-import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-
-public class DiagnoseParser implements ParserBasicInformation, TerminalTokens {
- private static final boolean DEBUG = false;
-
- private static final String EMPTY_STRING = ""; //$NON-NLS-1$
- private static final int STACK_INCREMENT = 256;
-
-// private static final int ERROR_CODE = 1;
- private static final int BEFORE_CODE = 2;
- private static final int INSERTION_CODE = 3;
- private static final int INVALID_CODE = 4;
- private static final int SUBSTITUTION_CODE = 5;
- private static final int DELETION_CODE = 6;
- private static final int MERGE_CODE = 7;
- private static final int MISPLACED_CODE = 8;
- private static final int SCOPE_CODE = 9;
- private static final int SECONDARY_CODE = 10;
- private static final int EOF_CODE = 11;
-
- private static final int BUFF_UBOUND = 31;
- private static final int BUFF_SIZE = 32;
- private static final int MAX_DISTANCE = 30;
- private static final int MIN_DISTANCE = 3;
-
- private LexStream lexStream;
- private int errorToken;
- private int errorTokenStart;
-
- private int currentToken = 0;
-
- private int stackLength;
- private int stateStackTop;
- private int[] stack;
-
- private int[] locationStack;
- private int[] locationStartStack;
-
- private int tempStackTop;
- private int[] tempStack;
-
- private int prevStackTop;
- private int[] prevStack;
- private int nextStackTop;
- private int[] nextStack;
-
- private int scopeStackTop;
- private int[] scopeIndex;
- private int[] scopePosition;
-
- int[] list = new int[NUM_SYMBOLS + 1];
- int[] buffer = new int[BUFF_SIZE];
-
- private static final int NIL = -1;
- int[] stateSeen;
-
- int statePoolTop;
- StateInfo[] statePool;
-
- private Parser parser;
-
- private class RepairCandidate {
- public int symbol;
- public int location;
-
- public RepairCandidate(){
- this.symbol = 0;
- this.location = 0;
- }
- }
-
- private class PrimaryRepairInfo {
- public int distance;
- public int misspellIndex;
- public int code;
- public int bufferPosition;
- public int symbol;
-
- public PrimaryRepairInfo(){
- this.distance = 0;
- this.misspellIndex = 0;
- this.code = 0;
- this.bufferPosition = 0;
- this.symbol = 0;
- }
-
- public PrimaryRepairInfo copy(){
- PrimaryRepairInfo c = new PrimaryRepairInfo();
- c.distance = this.distance;
- c.misspellIndex = this.misspellIndex;
- c.code = this.code;
- c.bufferPosition = this .bufferPosition;
- c.symbol = this.symbol;
- return c;
-
- }
- }
-
- private class SecondaryRepairInfo {
- public int code;
- public int distance;
- public int bufferPosition;
- public int stackPosition;
- public int numDeletions;
- public int symbol;
-
- boolean recoveryOnNextStack;
- }
-
- private class StateInfo {
- int state;
- int next;
-
- public StateInfo(int state, int next){
- this.state = state;
- this.next = next;
- }
- }
-
- public DiagnoseParser(Parser parser, int firstToken, int start, int end) {
- this(parser, firstToken, start, end, new int[0], new int[0], new int[0]);
- }
-
- public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip) {
- this.parser = parser;
- this.lexStream = new LexStream(BUFF_SIZE, parser.scanner, intervalStartToSkip, intervalEndToSkip, intervalFlagsToSkip, firstToken, start, end);
- }
-
- private ProblemReporter problemReporter(){
- return parser.problemReporter();
- }
-
- private void reallocateStacks() {
- int old_stack_length = stackLength;
-
- stackLength += STACK_INCREMENT;
-
- if(old_stack_length == 0){
- stack = new int[stackLength];
- locationStack = new int[stackLength];
- locationStartStack = new int[stackLength];
- tempStack = new int[stackLength];
- prevStack = new int[stackLength];
- nextStack = new int[stackLength];
- scopeIndex = new int[stackLength];
- scopePosition = new int[stackLength];
- } else {
- System.arraycopy(stack, 0, stack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(locationStack, 0, locationStack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(locationStartStack, 0, locationStartStack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(tempStack, 0, tempStack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(prevStack, 0, prevStack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(nextStack, 0, nextStack = new int[stackLength], 0, old_stack_length);
- System.arraycopy(scopeIndex, 0, scopeIndex = new int[stackLength], 0, old_stack_length);
- System.arraycopy(scopePosition, 0, scopePosition = new int[stackLength], 0, old_stack_length);
- }
- return;
- }
-
-
- public void diagnoseParse() {
- lexStream.reset();
-
- currentToken = lexStream.getToken();
-
- int prev_pos;
- int pos;
- int next_pos;
- int act = START_STATE;
-
- reallocateStacks();
-
- //
- // Start parsing
- //
- stateStackTop = 0;
- stack[stateStackTop] = act;
-
- int tok = lexStream.kind(currentToken);
- locationStack[stateStackTop] = currentToken;
- locationStartStack[stateStackTop] = lexStream.start(currentToken);
-
- boolean forceRecoveryAfterLBracketMissing = false;
-// int forceRecoveryToken = -1;
-
- //
- // Process a terminal
- //
- do {
- //
- // Synchronize state stacks and update the location stack
- //
- prev_pos = -1;
- prevStackTop = -1;
-
- next_pos = -1;
- nextStackTop = -1;
-
- pos = stateStackTop;
- tempStackTop = stateStackTop - 1;
- for (int i = 0; i <= stateStackTop; i++)
- tempStack[i] = stack[i];
-
- act = Parser.tAction(act, tok);
- //
- // When a reduce action is encountered, we compute all REDUCE
- // and associated goto actions induced by the current token.
- // Eventually, a SHIFT, SHIFT-REDUCE, ACCEPT or ERROR action is
- // computed...
- //
- while (act <= NUM_RULES) {
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
- } while(act <= NUM_RULES);
- //
- // ... Update the maximum useful position of the
- // (STATE_)STACK, push goto state into stack, and
- // compute next action on current symbol ...
- //
- if (tempStackTop + 1 >= stackLength)
- reallocateStacks();
- pos = pos < tempStackTop ? pos : tempStackTop;
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- //
- // At this point, we have a shift, shift-reduce, accept or error
- // action. STACK contains the configuration of the state stack
- // prior to executing any action on curtok. next_stack contains
- // the configuration of the state stack after executing all
- // reduce actions induced by curtok. The variable pos indicates
- // the highest position in STACK that is still useful after the
- // reductions are executed.
- //
- while(act > ERROR_ACTION || act < ACCEPT_ACTION) { // SHIFT-REDUCE action or SHIFT action ?
- nextStackTop = tempStackTop + 1;
- for (int i = next_pos + 1; i <= nextStackTop; i++)
- nextStack[i] = tempStack[i];
-
- for (int i = pos + 1; i <= nextStackTop; i++) {
- locationStack[i] = locationStack[stateStackTop];
- locationStartStack[i] = locationStartStack[stateStackTop];
- }
-
- //
- // If we have a shift-reduce, process it as well as
- // the goto-reduce actions that follow it.
- //
- if (act > ERROR_ACTION) {
- act -= ERROR_ACTION;
- do {
- nextStackTop -= (Parser.rhs[act]-1);
- act = Parser.ntAction(nextStack[nextStackTop], Parser.lhs[act]);
- } while(act <= NUM_RULES);
- pos = pos < nextStackTop ? pos : nextStackTop;
- }
-
- if (nextStackTop + 1 >= stackLength)
- reallocateStacks();
-
- tempStackTop = nextStackTop;
- nextStack[++nextStackTop] = act;
- next_pos = nextStackTop;
-
- //
- // Simulate the parser through the next token without
- // destroying STACK or next_stack.
- //
- currentToken = lexStream.getToken();
- tok = lexStream.kind(currentToken);
- act = Parser.tAction(act, tok);
- while(act <= NUM_RULES) {
- //
- // ... Process all goto-reduce actions following
- // reduction, until a goto action is computed ...
- //
- do {
- int lhs_symbol = Parser.lhs[act];
- if(DEBUG) {
- System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
- }
- tempStackTop -= (Parser.rhs[act]-1);
- act = (tempStackTop > next_pos
- ? tempStack[tempStackTop]
- : nextStack[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
-
- //
- // ... Update the maximum useful position of the
- // (STATE_)STACK, push GOTO state into stack, and
- // compute next action on current symbol ...
- //
- if (tempStackTop + 1 >= stackLength)
- reallocateStacks();
-
- next_pos = next_pos < tempStackTop ? next_pos : tempStackTop;
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
-// if((tok != TokenNameRBRACE || (forceRecoveryToken != currentToken && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0))
-// && (lexStream.flags(currentToken) & LexStream.IS_AFTER_JUMP) !=0) {
-// act = ERROR_ACTION;
-// if(forceRecoveryToken != currentToken
-// && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0) {
-// forceRecoveryAfterLBracketMissing = true;
-// forceRecoveryToken = currentToken;
-// }
-// }
-
- //
- // No error was detected, Read next token into
- // PREVTOK element, advance CURTOK pointer and
- // update stacks.
- //
- if (act != ERROR_ACTION) {
- prevStackTop = stateStackTop;
- for (int i = prev_pos + 1; i <= prevStackTop; i++)
- prevStack[i] = stack[i];
- prev_pos = pos;
-
- stateStackTop = nextStackTop;
- for (int i = pos + 1; i <= stateStackTop; i++)
- stack[i] = nextStack[i];
- locationStack[stateStackTop] = currentToken;
- locationStartStack[stateStackTop] = lexStream.start(currentToken);
- pos = next_pos;
- }
- }
-
- //
- // At this stage, either we have an ACCEPT or an ERROR
- // action.
- //
- if (act == ERROR_ACTION) {
- //
- // An error was detected.
- //
- RepairCandidate candidate = errorRecovery(currentToken, forceRecoveryAfterLBracketMissing);
-
- forceRecoveryAfterLBracketMissing = false;
-
- if(parser.reportOnlyOneSyntaxError) {
- return;
- }
-
- if(this.parser.problemReporter().options.maxProblemsPerUnit < this.parser.compilationUnit.compilationResult.problemCount) {
- return;
- }
-
- act = stack[stateStackTop];
-
- //
- // If the recovery was successful on a nonterminal candidate,
- // parse through that candidate and "read" the next token.
- //
- if (candidate.symbol == 0) {
- break;
- } else if (candidate.symbol > NT_OFFSET) {
- int lhs_symbol = candidate.symbol - NT_OFFSET;
- if(DEBUG) {
- System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
- }
- act = Parser.ntAction(act, lhs_symbol);
- while(act <= NUM_RULES) {
- stateStackTop -= (Parser.rhs[act]-1);
- act = Parser.ntAction(stack[stateStackTop], Parser.lhs[act]);
- }
- stack[++stateStackTop] = act;
- currentToken = lexStream.getToken();
- tok = lexStream.kind(currentToken);
- locationStack[stateStackTop] = currentToken;
- locationStartStack[stateStackTop] = lexStream.start(currentToken);
- } else {
- tok = candidate.symbol;
- locationStack[stateStackTop] = candidate.location;
- locationStartStack[stateStackTop] = lexStream.start(candidate.location);
- }
- }
- } while (act != ACCEPT_ACTION);
-
- return;
- }
-
- //
-// This routine is invoked when an error is encountered. It
-// tries to diagnose the error and recover from it. If it is
-// successful, the state stack, the current token and the buffer
-// are readjusted; i.e., after a successful recovery,
-// state_stack_top points to the location in the state stack
-// that contains the state on which to recover; curtok
-// identifies the symbol on which to recover.
-//
-// Up to three configurations may be available when this routine
-// is invoked. PREV_STACK may contain the sequence of states
-// preceding any action on prevtok, STACK always contains the
-// sequence of states preceding any action on curtok, and
-// NEXT_STACK may contain the sequence of states preceding any
-// action on the successor of curtok.
-//
- private RepairCandidate errorRecovery(int error_token, boolean forcedError) {
- this.errorToken = error_token;
- this.errorTokenStart = lexStream.start(error_token);
-
- int prevtok = lexStream.previous(error_token);
- int prevtokKind = lexStream.kind(prevtok);
-
- if(forcedError) {
- int name_index = Parser.terminal_index[TokenNameLBRACE];
-
- reportError(INSERTION_CODE, name_index, prevtok, prevtok);
-
- RepairCandidate candidate = new RepairCandidate();
- candidate.symbol = TokenNameLBRACE;
- candidate.location = error_token;
- lexStream.reset(error_token);
-
- stateStackTop = nextStackTop;
- for (int j = 0; j <= stateStackTop; j++) {
- stack[j] = nextStack[j];
- }
- locationStack[stateStackTop] = error_token;
- locationStartStack[stateStackTop] = lexStream.start(error_token);
-
- return candidate;
- }
-
- //
- // Try primary phase recoveries. If not successful, try secondary
- // phase recoveries. If not successful and we are at end of the
- // file, we issue the end-of-file error and quit. Otherwise, ...
- //
- RepairCandidate candidate = primaryPhase(error_token);
- if (candidate.symbol != 0) {
- return candidate;
- }
-
- candidate = secondaryPhase(error_token);
- if (candidate.symbol != 0) {
- return candidate;
- }
-
- if (lexStream.kind(error_token) == EOFT_SYMBOL) {
- reportError(EOF_CODE,
- Parser.terminal_index[EOFT_SYMBOL],
- prevtok,
- prevtok);
- candidate.symbol = 0;
- candidate.location = error_token;
- return candidate;
- }
-
- //
- // At this point, primary and (initial attempt at) secondary
- // recovery did not work. We will now get into "panic mode" and
- // keep trying secondary phase recoveries until we either find
- // a successful recovery or have consumed the remaining input
- // tokens.
- //
- while(lexStream.kind(buffer[BUFF_UBOUND]) != EOFT_SYMBOL) {
- candidate = secondaryPhase(buffer[MAX_DISTANCE - MIN_DISTANCE + 2]);
- if (candidate.symbol != 0) {
- return candidate;
- }
- }
-
- //
- // We reached the end of the file while panicking. Delete all
- // remaining tokens in the input.
- //
- int i;
- for (i = BUFF_UBOUND; lexStream.kind(buffer[i]) == EOFT_SYMBOL; i--){/*empty*/}
-
- reportError(DELETION_CODE,
- Parser.terminal_index[prevtokKind],//Parser.terminal_index[lexStream.kind(prevtok)],
- error_token,
- buffer[i]);
-
- candidate.symbol = 0;
- candidate.location = buffer[i];
-
- return candidate;
- }
-
-//
-// This function tries primary and scope recovery on each
-// available configuration. If a successful recovery is found
-// and no secondary phase recovery can do better, a diagnosis is
-// issued, the configuration is updated and the function returns
-// "true". Otherwise, it returns "false".
-//
- private RepairCandidate primaryPhase(int error_token) {
- PrimaryRepairInfo repair = new PrimaryRepairInfo();
- RepairCandidate candidate = new RepairCandidate();
-
- //
- // Initialize the buffer.
- //
- int i = (nextStackTop >= 0 ? 3 : 2);
- buffer[i] = error_token;
-
- for (int j = i; j > 0; j--)
- buffer[j - 1] = lexStream.previous(buffer[j]);
-
- for (int k = i + 1; k < BUFF_SIZE; k++)
- buffer[k] = lexStream.next(buffer[k - 1]);
-
- //
- // If NEXT_STACK_TOP > 0 then the parse was successful on CURTOK
- // and the error was detected on the successor of CURTOK. In
- // that case, first check whether or not primary recovery is
- // possible on next_stack ...
- //
- if (nextStackTop >= 0) {
- repair.bufferPosition = 3;
- repair = checkPrimaryDistance(nextStack, nextStackTop, repair);
- }
-
- //
- // ... Next, try primary recovery on the current token...
- //
- PrimaryRepairInfo new_repair = repair.copy();
-
- new_repair.bufferPosition = 2;
- new_repair = checkPrimaryDistance(stack, stateStackTop, new_repair);
- if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
- repair = new_repair;
- }
-
- //
- // Finally, if prev_stack_top >= 0 then try primary recovery on
- // the prev_stack configuration.
- //
-
- if (prevStackTop >= 0) {
- new_repair = repair.copy();
- new_repair.bufferPosition = 1;
- new_repair = checkPrimaryDistance(prevStack,prevStackTop, new_repair);
- if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
- repair = new_repair;
- }
- }
-
- //
- // Before accepting the best primary phase recovery obtained,
- // ensure that we cannot do better with a similar secondary
- // phase recovery.
- //
- if (nextStackTop >= 0) {// next_stack available
- if (secondaryCheck(nextStack,nextStackTop,3,repair.distance)) {
- return candidate;
- }
- }
- else if (secondaryCheck(stack, stateStackTop, 2, repair.distance)) {
- return candidate;
- }
-
- //
- // First, adjust distance if the recovery is on the error token;
- // it is important that the adjustment be made here and not at
- // each primary trial to prevent the distance tests from being
- // biased in favor of deferred recoveries which have access to
- // more input tokens...
- //
- repair.distance = repair.distance - repair.bufferPosition + 1;
-
- //
- // ...Next, adjust the distance if the recovery is a deletion or
- // (some form of) substitution...
- //
- if (repair.code == INVALID_CODE ||
- repair.code == DELETION_CODE ||
- repair.code == SUBSTITUTION_CODE ||
- repair.code == MERGE_CODE) {
- repair.distance--;
- }
-
- //
- // ... After adjustment, check if the most successful primary
- // recovery can be applied. If not, continue with more radical
- // recoveries...
- //
- if (repair.distance < MIN_DISTANCE) {
- return candidate;
- }
-
- //
- // When processing an insertion error, if the token preceeding
- // the error token is not available, we change the repair code
- // into a BEFORE_CODE to instruct the reporting routine that it
- // indicates that the repair symbol should be inserted before
- // the error token.
- //
- if (repair.code == INSERTION_CODE) {
- if (buffer[repair.bufferPosition - 1] == 0) {
- repair.code = BEFORE_CODE;
- }
- }
-
- //
- // Select the proper sequence of states on which to recover,
- // update stack accordingly and call diagnostic routine.
- //
- if (repair.bufferPosition == 1) {
- stateStackTop = prevStackTop;
- for (int j = 0; j <= stateStackTop; j++) {
- stack[j] = prevStack[j];
- }
- } else if (nextStackTop >= 0 && repair.bufferPosition >= 3) {
- stateStackTop = nextStackTop;
- for (int j = 0; j <= stateStackTop; j++) {
- stack[j] = nextStack[j];
- }
- locationStack[stateStackTop] = buffer[3];
- locationStartStack[stateStackTop] = lexStream.start(buffer[3]);
- }
-
- return primaryDiagnosis(repair);
- }
-
-
-//
-// This function checks whether or not a given state has a
-// candidate, whose string representaion is a merging of the two
-// tokens at positions buffer_position and buffer_position+1 in
-// the buffer. If so, it returns the candidate in question;
-// otherwise it returns 0.
-//
- private int mergeCandidate(int state, int buffer_position) {
- char[] name1 = lexStream.name(buffer[buffer_position]);
- char[] name2 = lexStream.name(buffer[buffer_position + 1]);
-
- int len = name1.length + name2.length;
-
- char[] str = CharOperation.concat(name1, name2);
-
- for (int k = Parser.asi(state); Parser.asr[k] != 0; k++) {
- int l = Parser.terminal_index[Parser.asr[k]];
-
- if (len == Parser.name[l].length()) {
- char[] name = Parser.name[l].toCharArray();
-
- if (CharOperation.equals(str, name, false)) {
- return Parser.asr[k];
- }
- }
- }
-
- return 0;
- }
-
-
-//
-// This procedure takes as arguments a parsing configuration
-// consisting of a state stack (stack and stack_top) and a fixed
-// number of input tokens (starting at buffer_position) in the
-// input BUFFER; and some reference arguments: repair_code,
-// distance, misspell_index, candidate, and stack_position
-// which it sets based on the best possible recovery that it
-// finds in the given configuration. The effectiveness of a
-// a repair is judged based on two criteria:
-//
-// 1) the number of tokens that can be parsed after the repair
-// is applied: distance.
-// 2) how close to perfection is the candidate that is chosen:
-// misspell_index.
-// When this procedure is entered, distance, misspell_index and
-// repair_code are assumed to be initialized.
-//
- private PrimaryRepairInfo checkPrimaryDistance(int stck[], int stack_top, PrimaryRepairInfo repair) {
- int i, j, k, next_state, max_pos, act, root, symbol, tok;
-
- //
- // First, try scope and manual recovery.
- //
- PrimaryRepairInfo scope_repair = scopeTrial(stck, stack_top, repair.copy());
- if (scope_repair.distance > repair.distance)
- repair = scope_repair;
-
- //
- // Next, try merging the error token with its successor.
- //
- if(buffer[repair.bufferPosition] != 0 && buffer[repair.bufferPosition + 1] != 0) {// do not merge the first token
- symbol = mergeCandidate(stck[stack_top], repair.bufferPosition);
- if (symbol != 0) {
- j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+2);
- if ((j > repair.distance) || (j == repair.distance && repair.misspellIndex < 10)) {
- repair.misspellIndex = 10;
- repair.symbol = symbol;
- repair.distance = j;
- repair.code = MERGE_CODE;
- }
- }
- }
-
- //
- // Next, try deletion of the error token.
- //
- j = parseCheck(
- stck,
- stack_top,
- lexStream.kind(buffer[repair.bufferPosition + 1]),
- repair.bufferPosition + 2);
- if (lexStream.kind(buffer[repair.bufferPosition]) == EOLT_SYMBOL &&
- lexStream.afterEol(buffer[repair.bufferPosition+1])) {
- k = 10;
- } else {
- k = 0;
- }
- if (j > repair.distance || (j == repair.distance && k > repair.misspellIndex)) {
- repair.misspellIndex = k;
- repair.code = DELETION_CODE;
- repair.distance = j;
- }
-
- //
- // Update the error configuration by simulating all reduce and
- // goto actions induced by the error token. Then assign the top
- // most state of the new configuration to next_state.
- //
- next_state = stck[stack_top];
- max_pos = stack_top;
- tempStackTop = stack_top - 1;
-
- tok = lexStream.kind(buffer[repair.bufferPosition]);
- lexStream.reset(buffer[repair.bufferPosition + 1]);
- act = Parser.tAction(next_state, tok);
- while(act <= NUM_RULES) {
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- symbol = Parser.lhs[act];
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, symbol);
- } while(act <= NUM_RULES);
- max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
- tempStack[tempStackTop + 1] = act;
- next_state = act;
- act = Parser.tAction(next_state, tok);
- }
-
- //
- // Next, place the list of candidates in proper order.
- //
- root = 0;
- for (i = Parser.asi(next_state); Parser.asr[i] != 0; i++) {
- symbol = Parser.asr[i];
- if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL) {
- if (root == 0) {
- list[symbol] = symbol;
- } else {
- list[symbol] = list[root];
- list[root] = symbol;
- }
- root = symbol;
- }
- }
-
- if (stck[stack_top] != next_state) {
- for (i = Parser.asi(stck[stack_top]); Parser.asr[i] != 0; i++) {
- symbol = Parser.asr[i];
- if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL && list[symbol] == 0) {
- if (root == 0) {
- list[symbol] = symbol;
- } else {
- list[symbol] = list[root];
- list[root] = symbol;
- }
- root = symbol;
- }
- }
- }
-
- i = list[root];
- list[root] = 0;
- root = i;
-
- //
- // Next, try insertion for each possible candidate available in
- // the current state, except EOFT and ERROR_SYMBOL.
- //
- symbol = root;
- while(symbol != 0) {
- if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition])) {
- k = 10;
- } else {
- k = 0;
- }
- j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
- if (j > repair.distance) {
- repair.misspellIndex = k;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = INSERTION_CODE;
- } else if (j == repair.distance && k > repair.misspellIndex) {
- repair.misspellIndex = k;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = INSERTION_CODE;
- } else if (j == repair.distance && k == repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
- repair.misspellIndex = k;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = INSERTION_CODE;
- }
-
- symbol = list[symbol];
- }
-
- //
- // Next, Try substitution for each possible candidate available
- // in the current state, except EOFT and ERROR_SYMBOL.
- //
- symbol = root;
-
- if(buffer[repair.bufferPosition] != 0) {// do not replace the first token
- while(symbol != 0) {
- if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition+1])) {
- k = 10;
- } else {
- k = misspell(symbol, buffer[repair.bufferPosition]);
- }
- j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
- if (j > repair.distance) {
- repair.misspellIndex = k;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = SUBSTITUTION_CODE;
- } else if (j == repair.distance && k > repair.misspellIndex) {
- repair.misspellIndex = k;
- repair.symbol = symbol;
- repair.code = SUBSTITUTION_CODE;
- } else if (j == repair.distance && k > repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
- repair.misspellIndex = k;
- repair.symbol = symbol;
- repair.code = SUBSTITUTION_CODE;
- }
- i = symbol;
- symbol = list[symbol];
- list[i] = 0; // reset element
- }
- }
-
-
- //
- // Next, we try to insert a nonterminal candidate in front of the
- // error token, or substituting a nonterminal candidate for the
- // error token. Precedence is given to insertion.
- //
- for (i = Parser.nasi(stck[stack_top]); Parser.nasr[i] != 0; i++) {
- symbol = Parser.nasr[i] + NT_OFFSET;
- j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
- if (j > repair.distance) {
- repair.misspellIndex = 0;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = INVALID_CODE;
- }
-
- j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
- if ((j > repair.distance) || (j == repair.distance && repair.code == INVALID_CODE)) {
- repair.misspellIndex = 0;
- repair.distance = j;
- repair.symbol = symbol;
- repair.code = INSERTION_CODE;
- }
- }
-
- return repair;
- }
-
-
-//
-// This procedure is invoked to issue a diagnostic message and
-// adjust the input buffer. The recovery in question is either
-// the insertion of one or more scopes, the merging of the error
-// token with its successor, the deletion of the error token,
-// the insertion of a single token in front of the error token
-// or the substitution of another token for the error token.
-//
- private RepairCandidate primaryDiagnosis(PrimaryRepairInfo repair) {
- int name_index;
-
- //
- // Issue diagnostic.
- //
- int prevtok = buffer[repair.bufferPosition - 1];
- int curtok = buffer[repair.bufferPosition];
-
- switch(repair.code) {
- case INSERTION_CODE:
- case BEFORE_CODE: {
- if (repair.symbol > NT_OFFSET)
- name_index = getNtermIndex(stack[stateStackTop],
- repair.symbol,
- repair.bufferPosition);
- else name_index = getTermIndex(stack,
- stateStackTop,
- repair.symbol,
- repair.bufferPosition);
-
- int t = (repair.code == INSERTION_CODE ? prevtok : curtok);
- reportError(repair.code, name_index, t, t);
- break;
- }
- case INVALID_CODE: {
- name_index = getNtermIndex(stack[stateStackTop],
- repair.symbol,
- repair.bufferPosition + 1);
- reportError(repair.code, name_index, curtok, curtok);
- break;
- }
- case SUBSTITUTION_CODE: {
- if (repair.misspellIndex >= 6)
- name_index = Parser.terminal_index[repair.symbol];
- else
- {
- name_index = getTermIndex(stack, stateStackTop,
- repair.symbol,
- repair.bufferPosition + 1);
- if (name_index != Parser.terminal_index[repair.symbol])
- repair.code = INVALID_CODE;
- }
- reportError(repair.code, name_index, curtok, curtok);
- break;
- }
- case MERGE_CODE: {
- reportError(repair.code,
- Parser.terminal_index[repair.symbol],
- curtok,
- lexStream.next(curtok));
- break;
- }
- case SCOPE_CODE: {
- for (int i = 0; i < scopeStackTop; i++) {
- reportError(repair.code,
- -scopeIndex[i],
- locationStack[scopePosition[i]],
- prevtok,
- Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
- }
-
- repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
- stateStackTop = scopePosition[scopeStackTop];
- reportError(repair.code,
- -scopeIndex[scopeStackTop],
- locationStack[scopePosition[scopeStackTop]],
- prevtok,
- getNtermIndex(stack[stateStackTop],
- repair.symbol,
- repair.bufferPosition)
- );
- break;
- }
- default: {// deletion
- reportError(repair.code, Parser.terminal_index[ERROR_SYMBOL], curtok, curtok);
- }
- }
-
- //
- // Update buffer.
- //
- RepairCandidate candidate = new RepairCandidate();
- switch (repair.code) {
- case INSERTION_CODE:
- case BEFORE_CODE:
- case SCOPE_CODE: {
- candidate.symbol = repair.symbol;
- candidate.location = buffer[repair.bufferPosition];
- lexStream.reset(buffer[repair.bufferPosition]);
- break;
- }
- case INVALID_CODE:
- case SUBSTITUTION_CODE: {
- candidate.symbol = repair.symbol;
- candidate.location = buffer[repair.bufferPosition];
- lexStream.reset(buffer[repair.bufferPosition + 1]);
- break;
- }
- case MERGE_CODE: {
- candidate.symbol = repair.symbol;
- candidate.location = buffer[repair.bufferPosition];
- lexStream.reset(buffer[repair.bufferPosition + 2]);
- break;
- }
- default: {// deletion
- candidate.location = buffer[repair.bufferPosition + 1];
- candidate.symbol =
- lexStream.kind(buffer[repair.bufferPosition + 1]);
- lexStream.reset(buffer[repair.bufferPosition + 2]);
- break;
- }
- }
-
- return candidate;
- }
-
-
-//
-// This function takes as parameter an integer STACK_TOP that
-// points to a STACK element containing the state on which a
-// primary recovery will be made; the terminal candidate on which
-// to recover; and an integer: buffer_position, which points to
-// the position of the next input token in the BUFFER. The
-// parser is simulated until a shift (or shift-reduce) action
-// is computed on the candidate. Then we proceed to compute the
-// the name index of the highest level nonterminal that can
-// directly or indirectly produce the candidate.
-//
- private int getTermIndex(int stck[], int stack_top, int tok, int buffer_position) {
- //
- // Initialize stack index of temp_stack and initialize maximum
- // position of state stack that is still useful.
- //
- int act = stck[stack_top],
- max_pos = stack_top,
- highest_symbol = tok;
-
- tempStackTop = stack_top - 1;
-
- //
- // Compute all reduce and associated actions induced by the
- // candidate until a SHIFT or SHIFT-REDUCE is computed. ERROR
- // and ACCEPT actions cannot be computed on the candidate in
- // this context, since we know that it is suitable for recovery.
- //
- lexStream.reset(buffer[buffer_position]);
- act = Parser.tAction(act, tok);
- while(act <= NUM_RULES) {
- //
- // Process all goto-reduce actions following reduction,
- // until a goto action is computed ...
- //
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- int lhs_symbol = Parser.lhs[act];
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
-
- //
- // Compute new maximum useful position of (STATE_)stack,
- // push goto state into the stack, and compute next
- // action on candidate ...
- //
- max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- //
- // At this stage, we have simulated all actions induced by the
- // candidate and we are ready to shift or shift-reduce it. First,
- // set tok and next_ptr appropriately and identify the candidate
- // as the initial highest_symbol. If a shift action was computed
- // on the candidate, update the stack and compute the next
- // action. Next, simulate all actions possible on the next input
- // token until we either have to shift it or are about to reduce
- // below the initial starting point in the stack (indicated by
- // max_pos as computed in the previous loop). At that point,
- // return the highest_symbol computed.
- //
- tempStackTop++; // adjust top of stack to reflect last goto
- // next move is shift or shift-reduce.
- int threshold = tempStackTop;
-
- tok = lexStream.kind(buffer[buffer_position]);
- lexStream.reset(buffer[buffer_position + 1]);
-
- if (act > ERROR_ACTION) { // shift-reduce on candidate?
- act -= ERROR_ACTION;
- } else {
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- while(act <= NUM_RULES) {
- //
- // Process all goto-reduce actions following reduction,
- // until a goto action is computed ...
- //
- do {
- tempStackTop -= (Parser.rhs[act]-1);
-
- if (tempStackTop < threshold) {
- return (highest_symbol > NT_OFFSET
- ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
- : Parser.terminal_index[highest_symbol]);
- }
-
- int lhs_symbol = Parser.lhs[act];
- if (tempStackTop == threshold)
- highest_symbol = lhs_symbol + NT_OFFSET;
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
-
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- return (highest_symbol > NT_OFFSET
- ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
- : Parser.terminal_index[highest_symbol]);
- }
-
-//
-// This function takes as parameter a starting state number:
-// start, a nonterminal symbol, A (candidate), and an integer,
-// buffer_position, which points to the position of the next
-// input token in the BUFFER.
-// It returns the highest level non-terminal B such that
-// B =>*rm A. I.e., there does not exists a nonterminal C such
-// that C =>+rm B. (Recall that for an LALR(k) grammar if
-// C =>+rm B, it cannot be the case that B =>+rm C)
-//
- private int getNtermIndex(int start, int sym, int buffer_position) {
- int highest_symbol = sym - NT_OFFSET,
- tok = lexStream.kind(buffer[buffer_position]);
- lexStream.reset(buffer[buffer_position + 1]);
-
- //
- // Initialize stack index of temp_stack and initialize maximum
- // position of state stack that is still useful.
- //
- tempStackTop = 0;
- tempStack[tempStackTop] = start;
-
- int act = Parser.ntAction(start, highest_symbol);
- if (act > NUM_RULES) { // goto action?
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- while(act <= NUM_RULES) {
- //
- // Process all goto-reduce actions following reduction,
- // until a goto action is computed ...
- //
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- if (tempStackTop < 0)
- return Parser.non_terminal_index[highest_symbol];
- if (tempStackTop == 0)
- highest_symbol = Parser.lhs[act];
- act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
- } while(act <= NUM_RULES);
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- return Parser.non_terminal_index[highest_symbol];
- }
-
- private boolean isBetterSymbol(int symbol, int actualSymbol) {
-// switch (actualSymbol) {
-// case TokenNameinterface :
-// if(symbol == TokenNameclass) {
-// return true;
-// }
-// break;
-// }
- return false;
- }
-
-//
-// Check whether or not there is a high probability that a
-// given string is a misspelling of another.
-// Certain singleton symbols (such as ":" and ";") are also
-// considered to be misspelling of each other.
-//
- private int misspell(int sym, int tok) {
-
-
- //
- //
- //
- char[] name = Parser.name[Parser.terminal_index[sym]].toCharArray();
- int n = name.length;
- char[] s1 = new char[n + 1];
- for (int k = 0; k < n; k++) {
- char c = name[k];
- s1[k] = Character.toLowerCase(c);
- }
- s1[n] = '\0';
-
- //
- //
- //
- char[] tokenName = lexStream.name(tok);
- int len = tokenName.length;
- int m = len < MAX_NAME_LENGTH ? len : MAX_NAME_LENGTH;
- char[] s2 = new char[m + 1];
- for (int k = 0; k < m; k++) {
- char c = tokenName[k];
- s2[k] = Character.toLowerCase(c);
- }
- s2[m] = '\0';
-
- //
- // Singleton mispellings:
- //
- // ; <----> ,
- //
- // ; <----> :
- //
- // . <----> ,
- //
- // ' <----> "
- //
- //
- if (n == 1 && m == 1) {
- if ((s1[0] == ';' && s2[0] == ',') ||
- (s1[0] == ',' && s2[0] == ';') ||
- (s1[0] == ';' && s2[0] == ':') ||
- (s1[0] == ':' && s2[0] == ';') ||
- (s1[0] == '.' && s2[0] == ',') ||
- (s1[0] == ',' && s2[0] == '.') ||
- (s1[0] == '\'' && s2[0] == '\"') ||
- (s1[0] == '\"' && s2[0] == '\'')) {
- return 3;
- }
- }
-
- //
- // Scan the two strings. Increment "match" count for each match.
- // When a transposition is encountered, increase "match" count
- // by two but count it as an error. When a typo is found, skip
- // it and count it as an error. Otherwise we have a mismatch; if
- // one of the strings is longer, increment its index, otherwise,
- // increment both indices and continue.
- //
- // This algorithm is an adaptation of a boolean misspelling
- // algorithm proposed by Juergen Uhl.
- //
- int count = 0;
- int prefix_length = 0;
- int num_errors = 0;
-
- int i = 0;
- int j = 0;
- while ((i < n) && (j < m)) {
- if (s1[i] == s2[j]) {
- count++;
- i++;
- j++;
- if (num_errors == 0) {
- prefix_length++;
- }
- } else if (s1[i+1] == s2[j] && s1[i] == s2[j+1]) {
- count += 2;
- i += 2;
- j += 2;
- num_errors++;
- } else if (s1[i+1] == s2[j+1]) {
- i++;
- j++;
- num_errors++;
- } else {
- if ((n - i) > (m - j)) {
- i++;
- } else if ((m - j) > (n - i)) {
- j++;
- } else {
- i++;
- j++;
- }
- num_errors++;
- }
- }
-
- if (i < n || j < m)
- num_errors++;
-
- if (num_errors > ((n < m ? n : m) / 6 + 1))
- count = prefix_length;
-
- return(count * 10 / ((n < len ? len : n) + num_errors));
- }
-
- private PrimaryRepairInfo scopeTrial(int stck[], int stack_top, PrimaryRepairInfo repair) {
- stateSeen = new int[stackLength];
- for (int i = 0; i < stackLength; i++)
- stateSeen[i] = NIL;
-
- statePoolTop = 0;
- statePool = new StateInfo[stackLength];
-
- scopeTrialCheck(stck, stack_top, repair, 0);
-
- stateSeen = null;
- statePoolTop = 0;
-
- repair.code = SCOPE_CODE;
- repair.misspellIndex = 10;
-
- return repair;
- }
-
- private void scopeTrialCheck(int stck[], int stack_top, PrimaryRepairInfo repair, int indx) {
- if(indx > 20) return; // avoid too much recursive call to improve performance
-
- int act = stck[stack_top];
-
- for (int i = stateSeen[stack_top]; i != NIL; i = statePool[i].next) {
- if (statePool[i].state == act) return;
- }
-
- int old_state_pool_top = statePoolTop++;
- if(statePoolTop >= statePool.length) {
- System.arraycopy(statePool, 0, statePool = new StateInfo[statePoolTop * 2], 0, statePoolTop);
- }
-
- statePool[old_state_pool_top] = new StateInfo(act, stateSeen[stack_top]);
- stateSeen[stack_top] = old_state_pool_top;
-
- for (int i = 0; i < SCOPE_SIZE; i++) {
- //
- // Use the scope lookahead symbol to force all reductions
- // inducible by that symbol.
- //
- act = stck[stack_top];
- tempStackTop = stack_top - 1;
- int max_pos = stack_top;
- int tok = Parser.scope_la[i];
- lexStream.reset(buffer[repair.bufferPosition]);
- act = Parser.tAction(act, tok);
- while(act <= NUM_RULES) {
- //
- // ... Process all goto-reduce actions following
- // reduction, until a goto action is computed ...
- //
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- int lhs_symbol = Parser.lhs[act];
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
- if (tempStackTop + 1 >= stackLength)
- return;
- max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
- tempStack[tempStackTop + 1] = act;
- act = Parser.tAction(act, tok);
- }
-
- //
- // If the lookahead symbol is parsable, then we check
- // whether or not we have a match between the scope
- // prefix and the transition symbols corresponding to
- // the states on top of the stack.
- //
- if (act != ERROR_ACTION) {
- int j, k;
- k = Parser.scope_prefix[i];
- for (j = tempStackTop + 1;
- j >= (max_pos + 1) &&
- Parser.in_symbol(tempStack[j]) == Parser.scope_rhs[k]; j--) {
- k++;
- }
- if (j == max_pos) {
- for (j = max_pos;
- j >= 1 && Parser.in_symbol(stck[j]) == Parser.scope_rhs[k];
- j--) {
- k++;
- }
- }
- //
- // If the prefix matches, check whether the state
- // newly exposed on top of the stack, (after the
- // corresponding prefix states are popped from the
- // stack), is in the set of "source states" for the
- // scope in question and that it is at a position
- // below the threshold indicated by MARKED_POS.
- //
- int marked_pos = (max_pos < stack_top ? max_pos + 1 : stack_top);
- if (Parser.scope_rhs[k] == 0 && j < marked_pos) { // match?
- int stack_position = j;
- for (j = Parser.scope_state_set[i];
- stck[stack_position] != Parser.scope_state[j] &&
- Parser.scope_state[j] != 0;
- j++){/*empty*/}
- //
- // If the top state is valid for scope recovery,
- // the left-hand side of the scope is used as
- // starting symbol and we calculate how far the
- // parser can advance within the forward context
- // after parsing the left-hand symbol.
- //
- if (Parser.scope_state[j] != 0) { // state was found
- int previous_distance = repair.distance;
- int distance = parseCheck(stck,
- stack_position,
- Parser.scope_lhs[i]+NT_OFFSET,
- repair.bufferPosition);
- //
- // if the recovery is not successful, we
- // update the stack with all actions induced
- // by the left-hand symbol, and recursively
- // call SCOPE_TRIAL_CHECK to try again.
- // Otherwise, the recovery is successful. If
- // the new distance is greater than the
- // initial SCOPE_DISTANCE, we update
- // SCOPE_DISTANCE and set scope_stack_top to INDX
- // to indicate the number of scopes that are
- // to be applied for a succesful recovery.
- // NOTE that this procedure cannot get into
- // an infinite loop, since each prefix match
- // is guaranteed to take us to a lower point
- // within the stack.
- //
- if ((distance - repair.bufferPosition + 1) < MIN_DISTANCE) {
- int top = stack_position;
- act = Parser.ntAction(stck[top], Parser.scope_lhs[i]);
- while(act <= NUM_RULES) {
- top -= (Parser.rhs[act]-1);
- act = Parser.ntAction(stck[top], Parser.lhs[act]);
- }
- top++;
-
- j = act;
- act = stck[top]; // save
- stck[top] = j; // swap
- scopeTrialCheck(stck, top, repair, indx+1);
- stck[top] = act; // restore
- } else if (distance > repair.distance) {
- scopeStackTop = indx;
- repair.distance = distance;
- }
-
- if (lexStream.kind(buffer[repair.bufferPosition]) == EOFT_SYMBOL &&
- repair.distance == previous_distance) {
- scopeStackTop = indx;
- repair.distance = MAX_DISTANCE;
- }
-
- //
- // If this scope recovery has beaten the
- // previous distance, then we have found a
- // better recovery (or this recovery is one
- // of a list of scope recoveries). Record
- // its information at the proper location
- // (INDX) in SCOPE_INDEX and SCOPE_STACK.
- //
- if (repair.distance > previous_distance) {
- scopeIndex[indx] = i;
- scopePosition[indx] = stack_position;
- return;
- }
- }
- }
- }
- }
- }
-//
-// This function computes the ParseCheck distance for the best
-// possible secondary recovery for a given configuration that
-// either deletes none or only one symbol in the forward context.
-// If the recovery found is more effective than the best primary
-// recovery previously computed, then the function returns true.
-// Only misplacement, scope and manual recoveries are attempted;
-// simple insertion or substitution of a nonterminal are tried
-// in CHECK_PRIMARY_DISTANCE as part of primary recovery.
-//
- private boolean secondaryCheck(int stck[], int stack_top, int buffer_position, int distance) {
- int top, j;
-
- for (top = stack_top - 1; top >= 0; top--) {
- j = parseCheck(stck, top,
- lexStream.kind(buffer[buffer_position]),
- buffer_position + 1);
- if (((j - buffer_position + 1) > MIN_DISTANCE) && (j > distance))
- return true;
- }
-
- PrimaryRepairInfo repair = new PrimaryRepairInfo();
- repair.bufferPosition = buffer_position + 1;
- repair.distance = distance;
- repair = scopeTrial(stck, stack_top, repair);
- if ((repair.distance - buffer_position) > MIN_DISTANCE && repair.distance > distance)
- return true;
- return false;
- }
-
-
-//
-// Secondary_phase is a boolean function that checks whether or
-// not some form of secondary recovery is applicable to one of
-// the error configurations. First, if "next_stack" is available,
-// misplacement and secondary recoveries are attempted on it.
-// Then, in any case, these recoveries are attempted on "stack".
-// If a successful recovery is found, a diagnosis is issued, the
-// configuration is updated and the function returns "true".
-// Otherwise, the function returns false.
-//
- private RepairCandidate secondaryPhase(int error_token) {
- SecondaryRepairInfo repair = new SecondaryRepairInfo();
- SecondaryRepairInfo misplaced = new SecondaryRepairInfo();
-
- RepairCandidate candidate = new RepairCandidate();
-
- int i, j, k, top;
- int next_last_index = 0;
- int last_index;
-
- candidate.symbol = 0;
-
- repair.code = 0;
- repair.distance = 0;
- repair.recoveryOnNextStack = false;
-
- misplaced.distance = 0;
- misplaced.recoveryOnNextStack = false;
-
- //
- // If the next_stack is available, try misplaced and secondary
- // recovery on it first.
- //
- if (nextStackTop >= 0) {
- int save_location;
-
- buffer[2] = error_token;
- buffer[1] = lexStream.previous(buffer[2]);
- buffer[0] = lexStream.previous(buffer[1]);
-
- for (k = 3; k < BUFF_UBOUND; k++)
- buffer[k] = lexStream.next(buffer[k - 1]);
-
- buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
-
- //
- // If we are at the end of the input stream, compute the
- // index position of the first EOFT symbol (last useful
- // index).
- //
- for (next_last_index = MAX_DISTANCE - 1;
- next_last_index >= 1 &&
- lexStream.kind(buffer[next_last_index]) == EOFT_SYMBOL;
- next_last_index--){/*empty*/}
- next_last_index = next_last_index + 1;
-
- save_location = locationStack[nextStackTop];
- int save_location_start = locationStartStack[nextStackTop];
- locationStack[nextStackTop] = buffer[2];
- locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
- misplaced.numDeletions = nextStackTop;
- misplaced = misplacementRecovery(nextStack, nextStackTop,
- next_last_index,
- misplaced, true);
- if (misplaced.recoveryOnNextStack)
- misplaced.distance++;
-
- repair.numDeletions = nextStackTop + BUFF_UBOUND;
- repair = secondaryRecovery(nextStack, nextStackTop,
- next_last_index,
- repair, true);
- if (repair.recoveryOnNextStack)
- repair.distance++;
-
- locationStack[nextStackTop] = save_location;
- locationStartStack[nextStackTop] = save_location_start;
- } else { // next_stack not available, initialize ...
- misplaced.numDeletions = stateStackTop;
- repair.numDeletions = stateStackTop + BUFF_UBOUND;
- }
-
- //
- // Try secondary recovery on the "stack" configuration.
- //
- buffer[3] = error_token;
-
- buffer[2] = lexStream.previous(buffer[3]);
- buffer[1] = lexStream.previous(buffer[2]);
- buffer[0] = lexStream.previous(buffer[1]);
-
- for (k = 4; k < BUFF_SIZE; k++)
- buffer[k] = lexStream.next(buffer[k - 1]);
-
- for (last_index = MAX_DISTANCE - 1;
- last_index >= 1 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL;
- last_index--){/*empty*/}
- last_index++;
-
- misplaced = misplacementRecovery(stack, stateStackTop,
- last_index,
- misplaced, false);
-
- repair = secondaryRecovery(stack, stateStackTop,
- last_index, repair, false);
-
- //
- // If a successful misplaced recovery was found, compare it with
- // the most successful secondary recovery. If the misplaced
- // recovery either deletes fewer symbols or parse-checks further
- // then it is chosen.
- //
- if (misplaced.distance > MIN_DISTANCE) {
- if (misplaced.numDeletions <= repair.numDeletions ||
- (misplaced.distance - misplaced.numDeletions) >=
- (repair.distance - repair.numDeletions)) {
- repair.code = MISPLACED_CODE;
- repair.stackPosition = misplaced.stackPosition;
- repair.bufferPosition = 2;
- repair.numDeletions = misplaced.numDeletions;
- repair.distance = misplaced.distance;
- repair.recoveryOnNextStack = misplaced.recoveryOnNextStack;
- }
- }
-
- //
- // If the successful recovery was on next_stack, update: stack,
- // buffer, location_stack and last_index.
- //
- if (repair.recoveryOnNextStack) {
- stateStackTop = nextStackTop;
- for (i = 0; i <= stateStackTop; i++)
- stack[i] = nextStack[i];
-
- buffer[2] = error_token;
- buffer[1] = lexStream.previous(buffer[2]);
- buffer[0] = lexStream.previous(buffer[1]);
-
- for (k = 3; k < BUFF_UBOUND; k++)
- buffer[k] = lexStream.next(buffer[k - 1]);
-
- buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
-
- locationStack[nextStackTop] = buffer[2];
- locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
- last_index = next_last_index;
- }
-
- //
- // Next, try scope recoveries after deletion of one, two, three,
- // four ... buffer_position tokens from the input stream.
- //
- if (repair.code == SECONDARY_CODE || repair.code == DELETION_CODE) {
- PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
-
- scope_repair.distance = 0;
- for (scope_repair.bufferPosition = 2;
- scope_repair.bufferPosition <= repair.bufferPosition &&
- repair.code != SCOPE_CODE; scope_repair.bufferPosition++) {
- scope_repair = scopeTrial(stack, stateStackTop, scope_repair);
- j = (scope_repair.distance == MAX_DISTANCE
- ? last_index
- : scope_repair.distance);
- k = scope_repair.bufferPosition - 1;
- if ((j - k) > MIN_DISTANCE && (j - k) > (repair.distance - repair.numDeletions)) {
- repair.code = SCOPE_CODE;
- i = scopeIndex[scopeStackTop]; // upper bound
- repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
- repair.stackPosition = stateStackTop;
- repair.bufferPosition = scope_repair.bufferPosition;
- }
- }
- }
-
- //
- // If no successful recovery is found and we have reached the
- // end of the file, check whether or not scope recovery is
- // applicable at the end of the file after discarding some
- // states.
- //
- if (repair.code == 0 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL) {
- PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
-
- scope_repair.bufferPosition = last_index;
- scope_repair.distance = 0;
- for (top = stateStackTop;
- top >= 0 && repair.code == 0; top--)
- {
- scope_repair = scopeTrial(stack, top, scope_repair);
- if (scope_repair.distance > 0)
- {
- repair.code = SCOPE_CODE;
- i = scopeIndex[scopeStackTop]; // upper bound
- repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
- repair.stackPosition = top;
- repair.bufferPosition = scope_repair.bufferPosition;
- }
- }
- }
-
- //
- // If a successful repair was not found, quit! Otherwise, issue
- // diagnosis and adjust configuration...
- //
- if (repair.code == 0)
- return candidate;
-
- secondaryDiagnosis(repair);
-
- //
- // Update buffer based on number of elements that are deleted.
- //
- switch(repair.code) {
- case MISPLACED_CODE:
- candidate.location = buffer[2];
- candidate.symbol = lexStream.kind(buffer[2]);
- lexStream.reset(lexStream.next(buffer[2]));
-
- break;
-
- case DELETION_CODE:
- candidate.location = buffer[repair.bufferPosition];
- candidate.symbol =
- lexStream.kind(buffer[repair.bufferPosition]);
- lexStream.reset(lexStream.next(buffer[repair.bufferPosition]));
-
- break;
-
- default: // SCOPE_CODE || SECONDARY_CODE
- candidate.symbol = repair.symbol;
- candidate.location = buffer[repair.bufferPosition];
- lexStream.reset(buffer[repair.bufferPosition]);
-
- break;
- }
-
- return candidate;
- }
-
-
-//
-// This boolean function checks whether or not a given
-// configuration yields a better misplacement recovery than
-// the best misplacement recovery computed previously.
-//
- private SecondaryRepairInfo misplacementRecovery(int stck[], int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
- int previous_loc = buffer[2];
- int stack_deletions = 0;
-
- for (int top = stack_top - 1; top >= 0; top--) {
- if (locationStack[top] < previous_loc) {
- stack_deletions++;
- }
- previous_loc = locationStack[top];
-
- int j = parseCheck(stck, top, lexStream.kind(buffer[2]), 3);
- if (j == MAX_DISTANCE) {
- j = last_index;
- }
- if ((j > MIN_DISTANCE) && (j - stack_deletions) > (repair.distance - repair.numDeletions)) {
- repair.stackPosition = top;
- repair.distance = j;
- repair.numDeletions = stack_deletions;
- repair.recoveryOnNextStack = stack_flag;
- }
- }
-
- return repair;
- }
-
-
-//
-// This boolean function checks whether or not a given
-// configuration yields a better secondary recovery than the
-// best misplacement recovery computed previously.
-//
- private SecondaryRepairInfo secondaryRecovery(int stck[],int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
- int previous_loc;
- int stack_deletions = 0;
-
- previous_loc = buffer[2];
- for (int top = stack_top; top >= 0 && repair.numDeletions >= stack_deletions; top--) {
- if (locationStack[top] < previous_loc) {
- stack_deletions++;
- }
- previous_loc = locationStack[top];
-
- for (int i = 2;
- i <= (last_index - MIN_DISTANCE + 1) &&
- (repair.numDeletions >= (stack_deletions + i - 1)); i++) {
- int j = parseCheck(stck, top, lexStream.kind(buffer[i]), i + 1);
-
- if (j == MAX_DISTANCE) {
- j = last_index;
- }
- if ((j - i + 1) > MIN_DISTANCE) {
- int k = stack_deletions + i - 1;
- if ((k < repair.numDeletions) ||
- (j - k) > (repair.distance - repair.numDeletions) ||
- ((repair.code == SECONDARY_CODE) && (j - k) == (repair.distance - repair.numDeletions))) {
- repair.code = DELETION_CODE;
- repair.distance = j;
- repair.stackPosition = top;
- repair.bufferPosition = i;
- repair.numDeletions = k;
- repair.recoveryOnNextStack = stack_flag;
- }
- }
-
- for (int l = Parser.nasi(stck[top]); l >= 0 && Parser.nasr[l] != 0; l++) {
- int symbol = Parser.nasr[l] + NT_OFFSET;
- j = parseCheck(stck, top, symbol, i);
- if (j == MAX_DISTANCE) {
- j = last_index;
- }
- if ((j - i + 1) > MIN_DISTANCE) {
- int k = stack_deletions + i - 1;
- if (k < repair.numDeletions || (j - k) > (repair.distance - repair.numDeletions)) {
- repair.code = SECONDARY_CODE;
- repair.symbol = symbol;
- repair.distance = j;
- repair.stackPosition = top;
- repair.bufferPosition = i;
- repair.numDeletions = k;
- repair.recoveryOnNextStack = stack_flag;
- }
- }
- }
- }
- }
-
- return repair;
- }
-
-
-//
-// This procedure is invoked to issue a secondary diagnosis and
-// adjust the input buffer. The recovery in question is either
-// an automatic scope recovery, a manual scope recovery, a
-// secondary substitution or a secondary deletion.
-//
- private void secondaryDiagnosis(SecondaryRepairInfo repair) {
- switch(repair.code) {
- case SCOPE_CODE: {
- if (repair.stackPosition < stateStackTop) {
- reportError(DELETION_CODE,
- Parser.terminal_index[ERROR_SYMBOL],
- locationStack[repair.stackPosition],
- buffer[1]);
- }
- for (int i = 0; i < scopeStackTop; i++) {
- reportError(SCOPE_CODE,
- -scopeIndex[i],
- locationStack[scopePosition[i]],
- buffer[1],
- Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
- }
-
- repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
- stateStackTop = scopePosition[scopeStackTop];
- reportError(SCOPE_CODE,
- -scopeIndex[scopeStackTop],
- locationStack[scopePosition[scopeStackTop]],
- buffer[1],
- getNtermIndex(stack[stateStackTop],
- repair.symbol,
- repair.bufferPosition)
- );
- break;
- }
- default: {
- reportError(repair.code,
- (repair.code == SECONDARY_CODE
- ? getNtermIndex(stack[repair.stackPosition],
- repair.symbol,
- repair.bufferPosition)
- : Parser.terminal_index[ERROR_SYMBOL]),
- locationStack[repair.stackPosition],
- buffer[repair.bufferPosition - 1]);
- stateStackTop = repair.stackPosition;
- }
- }
- }
-
-
-
-
-//
-// Try to parse until first_token and all tokens in BUFFER have
-// been consumed, or an error is encountered. Return the number
-// of tokens that were expended before the parse blocked.
-//
- private int parseCheck(int stck[], int stack_top, int first_token, int buffer_position) {
- int max_pos;
- int indx;
- int ct;
- int act;
-
- //
- // Initialize pointer for temp_stack and initialize maximum
- // position of state stack that is still useful.
- //
- act = stck[stack_top];
- if (first_token > NT_OFFSET) {
- tempStackTop = stack_top;
- max_pos = stack_top;
- indx = buffer_position;
- ct = lexStream.kind(buffer[indx]);
- lexStream.reset(lexStream.next(buffer[indx]));
- int lhs_symbol = first_token - NT_OFFSET;
- act = Parser.ntAction(act, lhs_symbol);
- if (act <= NUM_RULES) {
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- lhs_symbol = Parser.lhs[act];
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
-
- max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
- }
- } else {
- tempStackTop = stack_top - 1;
- max_pos = tempStackTop;
- indx = buffer_position - 1;
- ct = first_token;
- lexStream.reset(buffer[buffer_position]);
- }
-
- process_terminal: for (;;) {
- if (++tempStackTop >= stackLength) // Stack overflow!!!
- return indx;
- tempStack[tempStackTop] = act;
-
- act = Parser.tAction(act, ct);
-
- if (act <= NUM_RULES) { // reduce action
- tempStackTop--;
- } else if (act < ACCEPT_ACTION || // shift action
- act > ERROR_ACTION) { // shift-reduce action
- if (indx == MAX_DISTANCE)
- return indx;
- indx++;
- ct = lexStream.kind(buffer[indx]);
- lexStream.reset(lexStream.next(buffer[indx]));
- if (act > ERROR_ACTION) {
- act -= ERROR_ACTION;
- } else {
- continue process_terminal;
- }
- } else if (act == ACCEPT_ACTION) { // accept action
- return MAX_DISTANCE;
- } else {
- return indx; // error action
- }
-
- process_non_terminal:
- do {
- tempStackTop -= (Parser.rhs[act]-1);
- int lhs_symbol = Parser.lhs[act];
- act = (tempStackTop > max_pos
- ? tempStack[tempStackTop]
- : stck[tempStackTop]);
- act = Parser.ntAction(act, lhs_symbol);
- } while(act <= NUM_RULES);
-
- max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
- } // process_terminal;
- }
- private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken) {
- reportError(msgCode, nameIndex, leftToken, rightToken, 0);
- }
-
- private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
- int lToken = (leftToken > rightToken ? rightToken : leftToken);
-
- if (lToken < rightToken) {
- reportSecondaryError(msgCode, nameIndex, lToken, rightToken, scopeNameIndex);
- } else {
- reportPrimaryError(msgCode, nameIndex, rightToken, scopeNameIndex);
- }
- }
- private void reportPrimaryError(int msgCode, int nameIndex, int token, int scopeNameIndex) {
- String name;
- if (nameIndex >= 0) {
- name = Parser.readableName[nameIndex];
- } else {
- name = EMPTY_STRING;
- }
-
- int errorStart = lexStream.start(token);
- int errorEnd = lexStream.end(token);
- int currentKind = lexStream.kind(token);
- String errorTokenName = Parser.name[Parser.terminal_index[lexStream.kind(token)]];
- char[] errorTokenSource = lexStream.name(token);
-
- switch(msgCode) {
- case BEFORE_CODE:
- problemReporter().parseErrorInsertBeforeToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- break;
- case INSERTION_CODE:
- problemReporter().parseErrorInsertAfterToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- break;
- case DELETION_CODE:
- problemReporter().parseErrorDeleteToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName);
- break;
- case INVALID_CODE:
- if (name.length() == 0) {
- problemReporter().parseErrorReplaceToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- } else {
- problemReporter().parseErrorInvalidToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- }
- break;
- case SUBSTITUTION_CODE:
- problemReporter().parseErrorReplaceToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- break;
- case SCOPE_CODE:
- StringBuffer buf = new StringBuffer();
- for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
- buf.append(Parser.readableName[Parser.scope_rhs[i]]);
- if (Parser.scope_rhs[i + 1] != 0) // any more symbols to print?
- buf.append(' ');
-
- }
-
- if (scopeNameIndex != 0) {
- problemReporter().parseErrorInsertToComplete(
- errorStart,
- errorEnd,
- buf.toString(),
- Parser.readableName[scopeNameIndex]);
- } else {
- problemReporter().parseErrorInsertToCompleteScope(
- errorStart,
- errorEnd,
- buf.toString());
- }
-
- break;
- case EOF_CODE:
- problemReporter().parseErrorUnexpectedEnd(
- errorStart,
- errorEnd);
- break;
- case MERGE_CODE:
- problemReporter().parseErrorMergeTokens(
- errorStart,
- errorEnd,
- name);
- break;
- case MISPLACED_CODE:
- problemReporter().parseErrorMisplacedConstruct(
- errorStart,
- errorEnd);
- break;
- default:
- if (name.length() == 0) {
- problemReporter().parseErrorNoSuggestion(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName);
- } else {
- problemReporter().parseErrorReplaceToken(
- errorStart,
- errorEnd,
- currentKind,
- errorTokenSource,
- errorTokenName,
- name);
- }
- break;
- }
- }
-
- private void reportSecondaryError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
- String name;
- if (nameIndex >= 0) {
- name = Parser.readableName[nameIndex];
- } else {
- name = EMPTY_STRING;
- }
-
- int errorStart = -1;
- if(lexStream.isInsideStream(leftToken)) {
- if(leftToken == 0) {
- errorStart = lexStream.start(leftToken + 1);
- } else {
- errorStart = lexStream.start(leftToken);
- }
- } else {
- if(leftToken == errorToken) {
- errorStart = errorTokenStart;
- } else {
- for (int i = 0; i <= stateStackTop; i++) {
- if(locationStack[i] == leftToken) {
- errorStart = locationStartStack[i];
- }
- }
- }
- if(errorStart == -1) {
- errorStart = lexStream.start(rightToken);
- }
- }
- int errorEnd = lexStream.end(rightToken);
-
- switch(msgCode) {
- case MISPLACED_CODE:
- problemReporter().parseErrorMisplacedConstruct(
- errorStart,
- errorEnd);
- break;
- case SCOPE_CODE:
- // error start is on the last token start
- errorStart = lexStream.start(rightToken);
-
- StringBuffer buf = new StringBuffer();
- for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
- buf.append(Parser.readableName[Parser.scope_rhs[i]]);
- if (Parser.scope_rhs[i+1] != 0)
- buf.append(' ');
- }
- if (scopeNameIndex != 0) {
- problemReporter().parseErrorInsertToComplete(
- errorStart,
- errorEnd,
- buf.toString(),
- Parser.readableName[scopeNameIndex]);
- } else {
- problemReporter().parseErrorInsertToCompletePhrase(
- errorStart,
- errorEnd,
- buf.toString());
- }
- break;
- case MERGE_CODE:
- problemReporter().parseErrorMergeTokens(
- errorStart,
- errorEnd,
- name);
- break;
- case DELETION_CODE:
- problemReporter().parseErrorDeleteTokens(
- errorStart,
- errorEnd);
- break;
- default:
- if (name.length() == 0) {
- problemReporter().parseErrorNoSuggestionForTokens(
- errorStart,
- errorEnd);
- } else {
- problemReporter().parseErrorReplaceTokens(
- errorStart,
- errorEnd,
- name);
- }
- }
- return;
- }
-
- public String toString() {
- StringBuffer res = new StringBuffer();
-
- res.append(lexStream.toString());
-
- return res.toString();
- }
-}