| /******************************************************************************* |
| * 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 Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-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.impl.CompilerOptions; |
| 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 boolean DEBUG_PARSECHECK = 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 CompilerOptions options; |
| |
| 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, CompilerOptions options) { |
| this(parser, firstToken, start, end, new int[0], new int[0], new int[0], options); |
| } |
| |
| public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, CompilerOptions options) { |
| this.parser = parser; |
| this.options = options; |
| 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; |
| if(DEBUG_PARSECHECK) { |
| System.out.println(tempStackTop); |
| } |
| 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) { |
| // same loop as 'process_non_terminal' |
| do { |
| tempStackTop -= (Parser.rhs[act]-1); |
| |
| if(DEBUG_PARSECHECK) { |
| System.out.print(tempStackTop); |
| System.out.print(" ("); //$NON-NLS-1$ |
| System.out.print(-(Parser.rhs[act]-1)); |
| System.out.print(") [max:"); //$NON-NLS-1$ |
| System.out.print(max_pos); |
| System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$ |
| System.out.print(act); |
| System.out.print("\t"); //$NON-NLS-1$ |
| System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]); |
| System.out.println(); |
| } |
| |
| if(Parser.rules_compliance[act] > this.options.sourceLevel) { |
| return 0; |
| } |
| 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; |
| |
| if(DEBUG_PARSECHECK) { |
| System.out.println(tempStackTop); |
| } |
| |
| max_pos = tempStackTop; |
| indx = buffer_position - 1; |
| ct = first_token; |
| lexStream.reset(buffer[buffer_position]); |
| } |
| |
| process_terminal: for (;;) { |
| if(DEBUG_PARSECHECK) { |
| System.out.print(tempStackTop + 1); |
| System.out.print(" (+1) [max:"); //$NON-NLS-1$ |
| System.out.print(max_pos); |
| System.out.print("]\tprocess_terminal \t"); //$NON-NLS-1$ |
| System.out.print(ct); |
| System.out.print("\t"); //$NON-NLS-1$ |
| System.out.print(Parser.name[Parser.terminal_index[ct]]); |
| System.out.println(); |
| } |
| |
| if (++tempStackTop >= stackLength) // Stack overflow!!! |
| return indx; |
| tempStack[tempStackTop] = act; |
| |
| act = Parser.tAction(act, ct); |
| |
| if (act <= NUM_RULES) { // reduce action |
| tempStackTop--; |
| |
| if(DEBUG_PARSECHECK) { |
| System.out.print(tempStackTop); |
| System.out.print(" (-1) [max:"); //$NON-NLS-1$ |
| System.out.print(max_pos); |
| System.out.print("]\treduce"); //$NON-NLS-1$ |
| System.out.println(); |
| } |
| } 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; |
| |
| if(DEBUG_PARSECHECK) { |
| System.out.print(tempStackTop); |
| System.out.print("\tshift reduce"); //$NON-NLS-1$ |
| System.out.println(); |
| } |
| } else { |
| if(DEBUG_PARSECHECK) { |
| System.out.println("\tshift"); //$NON-NLS-1$ |
| } |
| continue process_terminal; |
| } |
| } else if (act == ACCEPT_ACTION) { // accept action |
| return MAX_DISTANCE; |
| } else { |
| return indx; // error action |
| } |
| |
| // same loop as first token initialization |
| process_non_terminal: |
| do { |
| tempStackTop -= (Parser.rhs[act]-1); |
| |
| if(DEBUG_PARSECHECK) { |
| System.out.print(tempStackTop); |
| System.out.print(" ("); //$NON-NLS-1$ |
| System.out.print(-(Parser.rhs[act]-1)); |
| System.out.print(") [max:"); //$NON-NLS-1$ |
| System.out.print(max_pos); |
| System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$ |
| System.out.print(act); |
| System.out.print("\t"); //$NON-NLS-1$ |
| System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]); |
| System.out.println(); |
| } |
| |
| if(act <= NUM_RULES) { |
| if(Parser.rules_compliance[act] > this.options.sourceLevel) { |
| return 0; |
| } |
| } |
| 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(); |
| } |
| } |