1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.parser.diagnose;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
15 import org.eclipse.jdt.internal.compiler.parser.Parser;
16 import org.eclipse.jdt.internal.compiler.parser.ParserBasicInformation;
17 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
18 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
20 public class DiagnoseParser implements ParserBasicInformation, TerminalTokens {
21 private static final boolean DEBUG = false;
22 private boolean DEBUG_PARSECHECK = false;
24 private static final String EMPTY_STRING = ""; //$NON-NLS-1$
25 private static final int STACK_INCREMENT = 256;
27 // private static final int ERROR_CODE = 1;
28 private static final int BEFORE_CODE = 2;
29 private static final int INSERTION_CODE = 3;
30 private static final int INVALID_CODE = 4;
31 private static final int SUBSTITUTION_CODE = 5;
32 private static final int DELETION_CODE = 6;
33 private static final int MERGE_CODE = 7;
34 private static final int MISPLACED_CODE = 8;
35 private static final int SCOPE_CODE = 9;
36 private static final int SECONDARY_CODE = 10;
37 private static final int EOF_CODE = 11;
39 private static final int BUFF_UBOUND = 31;
40 private static final int BUFF_SIZE = 32;
41 private static final int MAX_DISTANCE = 30;
42 private static final int MIN_DISTANCE = 3;
44 private CompilerOptions options;
46 private LexStream lexStream;
47 private int errorToken;
48 private int errorTokenStart;
50 private int currentToken = 0;
52 private int stackLength;
53 private int stateStackTop;
56 private int[] locationStack;
57 private int[] locationStartStack;
59 private int tempStackTop;
60 private int[] tempStack;
62 private int prevStackTop;
63 private int[] prevStack;
64 private int nextStackTop;
65 private int[] nextStack;
67 private int scopeStackTop;
68 private int[] scopeIndex;
69 private int[] scopePosition;
71 int[] list = new int[NUM_SYMBOLS + 1];
72 int[] buffer = new int[BUFF_SIZE];
74 private static final int NIL = -1;
78 StateInfo[] statePool;
80 private Parser parser;
82 private class RepairCandidate {
86 public RepairCandidate(){
92 private class PrimaryRepairInfo {
94 public int misspellIndex;
96 public int bufferPosition;
99 public PrimaryRepairInfo(){
101 this.misspellIndex = 0;
103 this.bufferPosition = 0;
107 public PrimaryRepairInfo copy(){
108 PrimaryRepairInfo c = new PrimaryRepairInfo();
109 c.distance = this.distance;
110 c.misspellIndex = this.misspellIndex;
112 c.bufferPosition = this .bufferPosition;
113 c.symbol = this.symbol;
119 private class SecondaryRepairInfo {
122 public int bufferPosition;
123 public int stackPosition;
124 public int numDeletions;
127 boolean recoveryOnNextStack;
130 private class StateInfo {
134 public StateInfo(int state, int next){
140 public DiagnoseParser(Parser parser, int firstToken, int start, int end, CompilerOptions options) {
141 this(parser, firstToken, start, end, new int[0], new int[0], new int[0], options);
144 public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, CompilerOptions options) {
145 this.parser = parser;
146 this.options = options;
147 this.lexStream = new LexStream(BUFF_SIZE, parser.scanner, intervalStartToSkip, intervalEndToSkip, intervalFlagsToSkip, firstToken, start, end);
150 private ProblemReporter problemReporter(){
151 return parser.problemReporter();
154 private void reallocateStacks() {
155 int old_stack_length = stackLength;
157 stackLength += STACK_INCREMENT;
159 if(old_stack_length == 0){
160 stack = new int[stackLength];
161 locationStack = new int[stackLength];
162 locationStartStack = new int[stackLength];
163 tempStack = new int[stackLength];
164 prevStack = new int[stackLength];
165 nextStack = new int[stackLength];
166 scopeIndex = new int[stackLength];
167 scopePosition = new int[stackLength];
169 System.arraycopy(stack, 0, stack = new int[stackLength], 0, old_stack_length);
170 System.arraycopy(locationStack, 0, locationStack = new int[stackLength], 0, old_stack_length);
171 System.arraycopy(locationStartStack, 0, locationStartStack = new int[stackLength], 0, old_stack_length);
172 System.arraycopy(tempStack, 0, tempStack = new int[stackLength], 0, old_stack_length);
173 System.arraycopy(prevStack, 0, prevStack = new int[stackLength], 0, old_stack_length);
174 System.arraycopy(nextStack, 0, nextStack = new int[stackLength], 0, old_stack_length);
175 System.arraycopy(scopeIndex, 0, scopeIndex = new int[stackLength], 0, old_stack_length);
176 System.arraycopy(scopePosition, 0, scopePosition = new int[stackLength], 0, old_stack_length);
182 public void diagnoseParse() {
185 currentToken = lexStream.getToken();
190 int act = START_STATE;
198 stack[stateStackTop] = act;
200 int tok = lexStream.kind(currentToken);
201 locationStack[stateStackTop] = currentToken;
202 locationStartStack[stateStackTop] = lexStream.start(currentToken);
204 boolean forceRecoveryAfterLBracketMissing = false;
205 // int forceRecoveryToken = -1;
208 // Process a terminal
212 // Synchronize state stacks and update the location stack
221 tempStackTop = stateStackTop - 1;
222 for (int i = 0; i <= stateStackTop; i++)
223 tempStack[i] = stack[i];
225 act = Parser.tAction(act, tok);
227 // When a reduce action is encountered, we compute all REDUCE
228 // and associated goto actions induced by the current token.
229 // Eventually, a SHIFT, SHIFT-REDUCE, ACCEPT or ERROR action is
232 while (act <= NUM_RULES) {
234 tempStackTop -= (Parser.rhs[act]-1);
235 act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
236 } while(act <= NUM_RULES);
238 // ... Update the maximum useful position of the
239 // (STATE_)STACK, push goto state into stack, and
240 // compute next action on current symbol ...
242 if (tempStackTop + 1 >= stackLength)
244 pos = pos < tempStackTop ? pos : tempStackTop;
245 tempStack[tempStackTop + 1] = act;
246 act = Parser.tAction(act, tok);
250 // At this point, we have a shift, shift-reduce, accept or error
251 // action. STACK contains the configuration of the state stack
252 // prior to executing any action on curtok. next_stack contains
253 // the configuration of the state stack after executing all
254 // reduce actions induced by curtok. The variable pos indicates
255 // the highest position in STACK that is still useful after the
256 // reductions are executed.
258 while(act > ERROR_ACTION || act < ACCEPT_ACTION) { // SHIFT-REDUCE action or SHIFT action ?
259 nextStackTop = tempStackTop + 1;
260 for (int i = next_pos + 1; i <= nextStackTop; i++)
261 nextStack[i] = tempStack[i];
263 for (int i = pos + 1; i <= nextStackTop; i++) {
264 locationStack[i] = locationStack[stateStackTop];
265 locationStartStack[i] = locationStartStack[stateStackTop];
269 // If we have a shift-reduce, process it as well as
270 // the goto-reduce actions that follow it.
272 if (act > ERROR_ACTION) {
275 nextStackTop -= (Parser.rhs[act]-1);
276 act = Parser.ntAction(nextStack[nextStackTop], Parser.lhs[act]);
277 } while(act <= NUM_RULES);
278 pos = pos < nextStackTop ? pos : nextStackTop;
281 if (nextStackTop + 1 >= stackLength)
284 tempStackTop = nextStackTop;
285 nextStack[++nextStackTop] = act;
286 next_pos = nextStackTop;
289 // Simulate the parser through the next token without
290 // destroying STACK or next_stack.
292 currentToken = lexStream.getToken();
293 tok = lexStream.kind(currentToken);
294 act = Parser.tAction(act, tok);
295 while(act <= NUM_RULES) {
297 // ... Process all goto-reduce actions following
298 // reduction, until a goto action is computed ...
301 int lhs_symbol = Parser.lhs[act];
303 System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
305 tempStackTop -= (Parser.rhs[act]-1);
306 act = (tempStackTop > next_pos
307 ? tempStack[tempStackTop]
308 : nextStack[tempStackTop]);
309 act = Parser.ntAction(act, lhs_symbol);
310 } while(act <= NUM_RULES);
313 // ... Update the maximum useful position of the
314 // (STATE_)STACK, push GOTO state into stack, and
315 // compute next action on current symbol ...
317 if (tempStackTop + 1 >= stackLength)
320 next_pos = next_pos < tempStackTop ? next_pos : tempStackTop;
321 tempStack[tempStackTop + 1] = act;
322 act = Parser.tAction(act, tok);
325 // if((tok != TokenNameRBRACE || (forceRecoveryToken != currentToken && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0))
326 // && (lexStream.flags(currentToken) & LexStream.IS_AFTER_JUMP) !=0) {
327 // act = ERROR_ACTION;
328 // if(forceRecoveryToken != currentToken
329 // && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0) {
330 // forceRecoveryAfterLBracketMissing = true;
331 // forceRecoveryToken = currentToken;
336 // No error was detected, Read next token into
337 // PREVTOK element, advance CURTOK pointer and
340 if (act != ERROR_ACTION) {
341 prevStackTop = stateStackTop;
342 for (int i = prev_pos + 1; i <= prevStackTop; i++)
343 prevStack[i] = stack[i];
346 stateStackTop = nextStackTop;
347 for (int i = pos + 1; i <= stateStackTop; i++)
348 stack[i] = nextStack[i];
349 locationStack[stateStackTop] = currentToken;
350 locationStartStack[stateStackTop] = lexStream.start(currentToken);
356 // At this stage, either we have an ACCEPT or an ERROR
359 if (act == ERROR_ACTION) {
361 // An error was detected.
363 RepairCandidate candidate = errorRecovery(currentToken, forceRecoveryAfterLBracketMissing);
365 forceRecoveryAfterLBracketMissing = false;
367 if(parser.reportOnlyOneSyntaxError) {
371 if(this.parser.problemReporter().options.maxProblemsPerUnit < this.parser.compilationUnit.compilationResult.problemCount) {
375 act = stack[stateStackTop];
378 // If the recovery was successful on a nonterminal candidate,
379 // parse through that candidate and "read" the next token.
381 if (candidate.symbol == 0) {
383 } else if (candidate.symbol > NT_OFFSET) {
384 int lhs_symbol = candidate.symbol - NT_OFFSET;
386 System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
388 act = Parser.ntAction(act, lhs_symbol);
389 while(act <= NUM_RULES) {
390 stateStackTop -= (Parser.rhs[act]-1);
391 act = Parser.ntAction(stack[stateStackTop], Parser.lhs[act]);
393 stack[++stateStackTop] = act;
394 currentToken = lexStream.getToken();
395 tok = lexStream.kind(currentToken);
396 locationStack[stateStackTop] = currentToken;
397 locationStartStack[stateStackTop] = lexStream.start(currentToken);
399 tok = candidate.symbol;
400 locationStack[stateStackTop] = candidate.location;
401 locationStartStack[stateStackTop] = lexStream.start(candidate.location);
404 } while (act != ACCEPT_ACTION);
410 // This routine is invoked when an error is encountered. It
411 // tries to diagnose the error and recover from it. If it is
412 // successful, the state stack, the current token and the buffer
413 // are readjusted; i.e., after a successful recovery,
414 // state_stack_top points to the location in the state stack
415 // that contains the state on which to recover; curtok
416 // identifies the symbol on which to recover.
418 // Up to three configurations may be available when this routine
419 // is invoked. PREV_STACK may contain the sequence of states
420 // preceding any action on prevtok, STACK always contains the
421 // sequence of states preceding any action on curtok, and
422 // NEXT_STACK may contain the sequence of states preceding any
423 // action on the successor of curtok.
425 private RepairCandidate errorRecovery(int error_token, boolean forcedError) {
426 this.errorToken = error_token;
427 this.errorTokenStart = lexStream.start(error_token);
429 int prevtok = lexStream.previous(error_token);
430 int prevtokKind = lexStream.kind(prevtok);
433 int name_index = Parser.terminal_index[TokenNameLBRACE];
435 reportError(INSERTION_CODE, name_index, prevtok, prevtok);
437 RepairCandidate candidate = new RepairCandidate();
438 candidate.symbol = TokenNameLBRACE;
439 candidate.location = error_token;
440 lexStream.reset(error_token);
442 stateStackTop = nextStackTop;
443 for (int j = 0; j <= stateStackTop; j++) {
444 stack[j] = nextStack[j];
446 locationStack[stateStackTop] = error_token;
447 locationStartStack[stateStackTop] = lexStream.start(error_token);
453 // Try primary phase recoveries. If not successful, try secondary
454 // phase recoveries. If not successful and we are at end of the
455 // file, we issue the end-of-file error and quit. Otherwise, ...
457 RepairCandidate candidate = primaryPhase(error_token);
458 if (candidate.symbol != 0) {
462 candidate = secondaryPhase(error_token);
463 if (candidate.symbol != 0) {
467 if (lexStream.kind(error_token) == EOFT_SYMBOL) {
468 reportError(EOF_CODE,
469 Parser.terminal_index[EOFT_SYMBOL],
472 candidate.symbol = 0;
473 candidate.location = error_token;
478 // At this point, primary and (initial attempt at) secondary
479 // recovery did not work. We will now get into "panic mode" and
480 // keep trying secondary phase recoveries until we either find
481 // a successful recovery or have consumed the remaining input
484 while(lexStream.kind(buffer[BUFF_UBOUND]) != EOFT_SYMBOL) {
485 candidate = secondaryPhase(buffer[MAX_DISTANCE - MIN_DISTANCE + 2]);
486 if (candidate.symbol != 0) {
492 // We reached the end of the file while panicking. Delete all
493 // remaining tokens in the input.
496 for (i = BUFF_UBOUND; lexStream.kind(buffer[i]) == EOFT_SYMBOL; i--){/*empty*/}
498 reportError(DELETION_CODE,
499 Parser.terminal_index[prevtokKind],//Parser.terminal_index[lexStream.kind(prevtok)],
503 candidate.symbol = 0;
504 candidate.location = buffer[i];
510 // This function tries primary and scope recovery on each
511 // available configuration. If a successful recovery is found
512 // and no secondary phase recovery can do better, a diagnosis is
513 // issued, the configuration is updated and the function returns
514 // "true". Otherwise, it returns "false".
516 private RepairCandidate primaryPhase(int error_token) {
517 PrimaryRepairInfo repair = new PrimaryRepairInfo();
518 RepairCandidate candidate = new RepairCandidate();
521 // Initialize the buffer.
523 int i = (nextStackTop >= 0 ? 3 : 2);
524 buffer[i] = error_token;
526 for (int j = i; j > 0; j--)
527 buffer[j - 1] = lexStream.previous(buffer[j]);
529 for (int k = i + 1; k < BUFF_SIZE; k++)
530 buffer[k] = lexStream.next(buffer[k - 1]);
533 // If NEXT_STACK_TOP > 0 then the parse was successful on CURTOK
534 // and the error was detected on the successor of CURTOK. In
535 // that case, first check whether or not primary recovery is
536 // possible on next_stack ...
538 if (nextStackTop >= 0) {
539 repair.bufferPosition = 3;
540 repair = checkPrimaryDistance(nextStack, nextStackTop, repair);
544 // ... Next, try primary recovery on the current token...
546 PrimaryRepairInfo new_repair = repair.copy();
548 new_repair.bufferPosition = 2;
549 new_repair = checkPrimaryDistance(stack, stateStackTop, new_repair);
550 if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
555 // Finally, if prev_stack_top >= 0 then try primary recovery on
556 // the prev_stack configuration.
559 if (prevStackTop >= 0) {
560 new_repair = repair.copy();
561 new_repair.bufferPosition = 1;
562 new_repair = checkPrimaryDistance(prevStack,prevStackTop, new_repair);
563 if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
569 // Before accepting the best primary phase recovery obtained,
570 // ensure that we cannot do better with a similar secondary
573 if (nextStackTop >= 0) {// next_stack available
574 if (secondaryCheck(nextStack,nextStackTop,3,repair.distance)) {
578 else if (secondaryCheck(stack, stateStackTop, 2, repair.distance)) {
583 // First, adjust distance if the recovery is on the error token;
584 // it is important that the adjustment be made here and not at
585 // each primary trial to prevent the distance tests from being
586 // biased in favor of deferred recoveries which have access to
587 // more input tokens...
589 repair.distance = repair.distance - repair.bufferPosition + 1;
592 // ...Next, adjust the distance if the recovery is a deletion or
593 // (some form of) substitution...
595 if (repair.code == INVALID_CODE ||
596 repair.code == DELETION_CODE ||
597 repair.code == SUBSTITUTION_CODE ||
598 repair.code == MERGE_CODE) {
603 // ... After adjustment, check if the most successful primary
604 // recovery can be applied. If not, continue with more radical
607 if (repair.distance < MIN_DISTANCE) {
612 // When processing an insertion error, if the token preceeding
613 // the error token is not available, we change the repair code
614 // into a BEFORE_CODE to instruct the reporting routine that it
615 // indicates that the repair symbol should be inserted before
618 if (repair.code == INSERTION_CODE) {
619 if (buffer[repair.bufferPosition - 1] == 0) {
620 repair.code = BEFORE_CODE;
625 // Select the proper sequence of states on which to recover,
626 // update stack accordingly and call diagnostic routine.
628 if (repair.bufferPosition == 1) {
629 stateStackTop = prevStackTop;
630 for (int j = 0; j <= stateStackTop; j++) {
631 stack[j] = prevStack[j];
633 } else if (nextStackTop >= 0 && repair.bufferPosition >= 3) {
634 stateStackTop = nextStackTop;
635 for (int j = 0; j <= stateStackTop; j++) {
636 stack[j] = nextStack[j];
638 locationStack[stateStackTop] = buffer[3];
639 locationStartStack[stateStackTop] = lexStream.start(buffer[3]);
642 return primaryDiagnosis(repair);
647 // This function checks whether or not a given state has a
648 // candidate, whose string representaion is a merging of the two
649 // tokens at positions buffer_position and buffer_position+1 in
650 // the buffer. If so, it returns the candidate in question;
651 // otherwise it returns 0.
653 private int mergeCandidate(int state, int buffer_position) {
654 char[] name1 = lexStream.name(buffer[buffer_position]);
655 char[] name2 = lexStream.name(buffer[buffer_position + 1]);
657 int len = name1.length + name2.length;
659 char[] str = CharOperation.concat(name1, name2);
661 for (int k = Parser.asi(state); Parser.asr[k] != 0; k++) {
662 int l = Parser.terminal_index[Parser.asr[k]];
664 if (len == Parser.name[l].length()) {
665 char[] name = Parser.name[l].toCharArray();
667 if (CharOperation.equals(str, name, false)) {
668 return Parser.asr[k];
678 // This procedure takes as arguments a parsing configuration
679 // consisting of a state stack (stack and stack_top) and a fixed
680 // number of input tokens (starting at buffer_position) in the
681 // input BUFFER; and some reference arguments: repair_code,
682 // distance, misspell_index, candidate, and stack_position
683 // which it sets based on the best possible recovery that it
684 // finds in the given configuration. The effectiveness of a
685 // a repair is judged based on two criteria:
687 // 1) the number of tokens that can be parsed after the repair
688 // is applied: distance.
689 // 2) how close to perfection is the candidate that is chosen:
691 // When this procedure is entered, distance, misspell_index and
692 // repair_code are assumed to be initialized.
694 private PrimaryRepairInfo checkPrimaryDistance(int stck[], int stack_top, PrimaryRepairInfo repair) {
695 int i, j, k, next_state, max_pos, act, root, symbol, tok;
698 // First, try scope and manual recovery.
700 PrimaryRepairInfo scope_repair = scopeTrial(stck, stack_top, repair.copy());
701 if (scope_repair.distance > repair.distance)
702 repair = scope_repair;
705 // Next, try merging the error token with its successor.
707 if(buffer[repair.bufferPosition] != 0 && buffer[repair.bufferPosition + 1] != 0) {// do not merge the first token
708 symbol = mergeCandidate(stck[stack_top], repair.bufferPosition);
710 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+2);
711 if ((j > repair.distance) || (j == repair.distance && repair.misspellIndex < 10)) {
712 repair.misspellIndex = 10;
713 repair.symbol = symbol;
715 repair.code = MERGE_CODE;
721 // Next, try deletion of the error token.
726 lexStream.kind(buffer[repair.bufferPosition + 1]),
727 repair.bufferPosition + 2);
728 if (lexStream.kind(buffer[repair.bufferPosition]) == EOLT_SYMBOL &&
729 lexStream.afterEol(buffer[repair.bufferPosition+1])) {
734 if (j > repair.distance || (j == repair.distance && k > repair.misspellIndex)) {
735 repair.misspellIndex = k;
736 repair.code = DELETION_CODE;
741 // Update the error configuration by simulating all reduce and
742 // goto actions induced by the error token. Then assign the top
743 // most state of the new configuration to next_state.
745 next_state = stck[stack_top];
747 tempStackTop = stack_top - 1;
749 tok = lexStream.kind(buffer[repair.bufferPosition]);
750 lexStream.reset(buffer[repair.bufferPosition + 1]);
751 act = Parser.tAction(next_state, tok);
752 while(act <= NUM_RULES) {
754 tempStackTop -= (Parser.rhs[act]-1);
755 symbol = Parser.lhs[act];
756 act = (tempStackTop > max_pos
757 ? tempStack[tempStackTop]
758 : stck[tempStackTop]);
759 act = Parser.ntAction(act, symbol);
760 } while(act <= NUM_RULES);
761 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
762 tempStack[tempStackTop + 1] = act;
764 act = Parser.tAction(next_state, tok);
768 // Next, place the list of candidates in proper order.
771 for (i = Parser.asi(next_state); Parser.asr[i] != 0; i++) {
772 symbol = Parser.asr[i];
773 if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL) {
775 list[symbol] = symbol;
777 list[symbol] = list[root];
784 if (stck[stack_top] != next_state) {
785 for (i = Parser.asi(stck[stack_top]); Parser.asr[i] != 0; i++) {
786 symbol = Parser.asr[i];
787 if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL && list[symbol] == 0) {
789 list[symbol] = symbol;
791 list[symbol] = list[root];
804 // Next, try insertion for each possible candidate available in
805 // the current state, except EOFT and ERROR_SYMBOL.
809 if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition])) {
814 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
815 if (j > repair.distance) {
816 repair.misspellIndex = k;
818 repair.symbol = symbol;
819 repair.code = INSERTION_CODE;
820 } else if (j == repair.distance && k > repair.misspellIndex) {
821 repair.misspellIndex = k;
823 repair.symbol = symbol;
824 repair.code = INSERTION_CODE;
825 } else if (j == repair.distance && k == repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
826 repair.misspellIndex = k;
828 repair.symbol = symbol;
829 repair.code = INSERTION_CODE;
832 symbol = list[symbol];
836 // Next, Try substitution for each possible candidate available
837 // in the current state, except EOFT and ERROR_SYMBOL.
841 if(buffer[repair.bufferPosition] != 0) {// do not replace the first token
843 if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition+1])) {
846 k = misspell(symbol, buffer[repair.bufferPosition]);
848 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
849 if (j > repair.distance) {
850 repair.misspellIndex = k;
852 repair.symbol = symbol;
853 repair.code = SUBSTITUTION_CODE;
854 } else if (j == repair.distance && k > repair.misspellIndex) {
855 repair.misspellIndex = k;
856 repair.symbol = symbol;
857 repair.code = SUBSTITUTION_CODE;
858 } else if (j == repair.distance && k > repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
859 repair.misspellIndex = k;
860 repair.symbol = symbol;
861 repair.code = SUBSTITUTION_CODE;
864 symbol = list[symbol];
865 list[i] = 0; // reset element
871 // Next, we try to insert a nonterminal candidate in front of the
872 // error token, or substituting a nonterminal candidate for the
873 // error token. Precedence is given to insertion.
875 for (i = Parser.nasi(stck[stack_top]); Parser.nasr[i] != 0; i++) {
876 symbol = Parser.nasr[i] + NT_OFFSET;
877 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
878 if (j > repair.distance) {
879 repair.misspellIndex = 0;
881 repair.symbol = symbol;
882 repair.code = INVALID_CODE;
885 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
886 if ((j > repair.distance) || (j == repair.distance && repair.code == INVALID_CODE)) {
887 repair.misspellIndex = 0;
889 repair.symbol = symbol;
890 repair.code = INSERTION_CODE;
899 // This procedure is invoked to issue a diagnostic message and
900 // adjust the input buffer. The recovery in question is either
901 // the insertion of one or more scopes, the merging of the error
902 // token with its successor, the deletion of the error token,
903 // the insertion of a single token in front of the error token
904 // or the substitution of another token for the error token.
906 private RepairCandidate primaryDiagnosis(PrimaryRepairInfo repair) {
912 int prevtok = buffer[repair.bufferPosition - 1];
913 int curtok = buffer[repair.bufferPosition];
915 switch(repair.code) {
918 if (repair.symbol > NT_OFFSET)
919 name_index = getNtermIndex(stack[stateStackTop],
921 repair.bufferPosition);
922 else name_index = getTermIndex(stack,
925 repair.bufferPosition);
927 int t = (repair.code == INSERTION_CODE ? prevtok : curtok);
928 reportError(repair.code, name_index, t, t);
932 name_index = getNtermIndex(stack[stateStackTop],
934 repair.bufferPosition + 1);
935 reportError(repair.code, name_index, curtok, curtok);
938 case SUBSTITUTION_CODE: {
939 if (repair.misspellIndex >= 6)
940 name_index = Parser.terminal_index[repair.symbol];
943 name_index = getTermIndex(stack, stateStackTop,
945 repair.bufferPosition + 1);
946 if (name_index != Parser.terminal_index[repair.symbol])
947 repair.code = INVALID_CODE;
949 reportError(repair.code, name_index, curtok, curtok);
953 reportError(repair.code,
954 Parser.terminal_index[repair.symbol],
956 lexStream.next(curtok));
960 for (int i = 0; i < scopeStackTop; i++) {
961 reportError(repair.code,
963 locationStack[scopePosition[i]],
965 Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
968 repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
969 stateStackTop = scopePosition[scopeStackTop];
970 reportError(repair.code,
971 -scopeIndex[scopeStackTop],
972 locationStack[scopePosition[scopeStackTop]],
974 getNtermIndex(stack[stateStackTop],
976 repair.bufferPosition)
980 default: {// deletion
981 reportError(repair.code, Parser.terminal_index[ERROR_SYMBOL], curtok, curtok);
988 RepairCandidate candidate = new RepairCandidate();
989 switch (repair.code) {
993 candidate.symbol = repair.symbol;
994 candidate.location = buffer[repair.bufferPosition];
995 lexStream.reset(buffer[repair.bufferPosition]);
999 case SUBSTITUTION_CODE: {
1000 candidate.symbol = repair.symbol;
1001 candidate.location = buffer[repair.bufferPosition];
1002 lexStream.reset(buffer[repair.bufferPosition + 1]);
1006 candidate.symbol = repair.symbol;
1007 candidate.location = buffer[repair.bufferPosition];
1008 lexStream.reset(buffer[repair.bufferPosition + 2]);
1011 default: {// deletion
1012 candidate.location = buffer[repair.bufferPosition + 1];
1014 lexStream.kind(buffer[repair.bufferPosition + 1]);
1015 lexStream.reset(buffer[repair.bufferPosition + 2]);
1025 // This function takes as parameter an integer STACK_TOP that
1026 // points to a STACK element containing the state on which a
1027 // primary recovery will be made; the terminal candidate on which
1028 // to recover; and an integer: buffer_position, which points to
1029 // the position of the next input token in the BUFFER. The
1030 // parser is simulated until a shift (or shift-reduce) action
1031 // is computed on the candidate. Then we proceed to compute the
1032 // the name index of the highest level nonterminal that can
1033 // directly or indirectly produce the candidate.
1035 private int getTermIndex(int stck[], int stack_top, int tok, int buffer_position) {
1037 // Initialize stack index of temp_stack and initialize maximum
1038 // position of state stack that is still useful.
1040 int act = stck[stack_top],
1041 max_pos = stack_top,
1042 highest_symbol = tok;
1044 tempStackTop = stack_top - 1;
1047 // Compute all reduce and associated actions induced by the
1048 // candidate until a SHIFT or SHIFT-REDUCE is computed. ERROR
1049 // and ACCEPT actions cannot be computed on the candidate in
1050 // this context, since we know that it is suitable for recovery.
1052 lexStream.reset(buffer[buffer_position]);
1053 act = Parser.tAction(act, tok);
1054 while(act <= NUM_RULES) {
1056 // Process all goto-reduce actions following reduction,
1057 // until a goto action is computed ...
1060 tempStackTop -= (Parser.rhs[act]-1);
1061 int lhs_symbol = Parser.lhs[act];
1062 act = (tempStackTop > max_pos
1063 ? tempStack[tempStackTop]
1064 : stck[tempStackTop]);
1065 act = Parser.ntAction(act, lhs_symbol);
1066 } while(act <= NUM_RULES);
1069 // Compute new maximum useful position of (STATE_)stack,
1070 // push goto state into the stack, and compute next
1071 // action on candidate ...
1073 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1074 tempStack[tempStackTop + 1] = act;
1075 act = Parser.tAction(act, tok);
1079 // At this stage, we have simulated all actions induced by the
1080 // candidate and we are ready to shift or shift-reduce it. First,
1081 // set tok and next_ptr appropriately and identify the candidate
1082 // as the initial highest_symbol. If a shift action was computed
1083 // on the candidate, update the stack and compute the next
1084 // action. Next, simulate all actions possible on the next input
1085 // token until we either have to shift it or are about to reduce
1086 // below the initial starting point in the stack (indicated by
1087 // max_pos as computed in the previous loop). At that point,
1088 // return the highest_symbol computed.
1090 tempStackTop++; // adjust top of stack to reflect last goto
1091 // next move is shift or shift-reduce.
1092 int threshold = tempStackTop;
1094 tok = lexStream.kind(buffer[buffer_position]);
1095 lexStream.reset(buffer[buffer_position + 1]);
1097 if (act > ERROR_ACTION) { // shift-reduce on candidate?
1098 act -= ERROR_ACTION;
1100 tempStack[tempStackTop + 1] = act;
1101 act = Parser.tAction(act, tok);
1104 while(act <= NUM_RULES) {
1106 // Process all goto-reduce actions following reduction,
1107 // until a goto action is computed ...
1110 tempStackTop -= (Parser.rhs[act]-1);
1112 if (tempStackTop < threshold) {
1113 return (highest_symbol > NT_OFFSET
1114 ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1115 : Parser.terminal_index[highest_symbol]);
1118 int lhs_symbol = Parser.lhs[act];
1119 if (tempStackTop == threshold)
1120 highest_symbol = lhs_symbol + NT_OFFSET;
1121 act = (tempStackTop > max_pos
1122 ? tempStack[tempStackTop]
1123 : stck[tempStackTop]);
1124 act = Parser.ntAction(act, lhs_symbol);
1125 } while(act <= NUM_RULES);
1127 tempStack[tempStackTop + 1] = act;
1128 act = Parser.tAction(act, tok);
1131 return (highest_symbol > NT_OFFSET
1132 ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1133 : Parser.terminal_index[highest_symbol]);
1137 // This function takes as parameter a starting state number:
1138 // start, a nonterminal symbol, A (candidate), and an integer,
1139 // buffer_position, which points to the position of the next
1140 // input token in the BUFFER.
1141 // It returns the highest level non-terminal B such that
1142 // B =>*rm A. I.e., there does not exists a nonterminal C such
1143 // that C =>+rm B. (Recall that for an LALR(k) grammar if
1144 // C =>+rm B, it cannot be the case that B =>+rm C)
1146 private int getNtermIndex(int start, int sym, int buffer_position) {
1147 int highest_symbol = sym - NT_OFFSET,
1148 tok = lexStream.kind(buffer[buffer_position]);
1149 lexStream.reset(buffer[buffer_position + 1]);
1152 // Initialize stack index of temp_stack and initialize maximum
1153 // position of state stack that is still useful.
1156 tempStack[tempStackTop] = start;
1158 int act = Parser.ntAction(start, highest_symbol);
1159 if (act > NUM_RULES) { // goto action?
1160 tempStack[tempStackTop + 1] = act;
1161 act = Parser.tAction(act, tok);
1164 while(act <= NUM_RULES) {
1166 // Process all goto-reduce actions following reduction,
1167 // until a goto action is computed ...
1170 tempStackTop -= (Parser.rhs[act]-1);
1171 if (tempStackTop < 0)
1172 return Parser.non_terminal_index[highest_symbol];
1173 if (tempStackTop == 0)
1174 highest_symbol = Parser.lhs[act];
1175 act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
1176 } while(act <= NUM_RULES);
1177 tempStack[tempStackTop + 1] = act;
1178 act = Parser.tAction(act, tok);
1181 return Parser.non_terminal_index[highest_symbol];
1184 private boolean isBetterSymbol(int symbol, int actualSymbol) {
1185 // switch (actualSymbol) {
1186 // case TokenNameinterface :
1187 // if(symbol == TokenNameclass) {
1196 // Check whether or not there is a high probability that a
1197 // given string is a misspelling of another.
1198 // Certain singleton symbols (such as ":" and ";") are also
1199 // considered to be misspelling of each other.
1201 private int misspell(int sym, int tok) {
1207 char[] name = Parser.name[Parser.terminal_index[sym]].toCharArray();
1208 int n = name.length;
1209 char[] s1 = new char[n + 1];
1210 for (int k = 0; k < n; k++) {
1212 s1[k] = Character.toLowerCase(c);
1219 char[] tokenName = lexStream.name(tok);
1220 int len = tokenName.length;
1221 int m = len < MAX_NAME_LENGTH ? len : MAX_NAME_LENGTH;
1222 char[] s2 = new char[m + 1];
1223 for (int k = 0; k < m; k++) {
1224 char c = tokenName[k];
1225 s2[k] = Character.toLowerCase(c);
1230 // Singleton mispellings:
1241 if (n == 1 && m == 1) {
1242 if ((s1[0] == ';' && s2[0] == ',') ||
1243 (s1[0] == ',' && s2[0] == ';') ||
1244 (s1[0] == ';' && s2[0] == ':') ||
1245 (s1[0] == ':' && s2[0] == ';') ||
1246 (s1[0] == '.' && s2[0] == ',') ||
1247 (s1[0] == ',' && s2[0] == '.') ||
1248 (s1[0] == '\'' && s2[0] == '\"') ||
1249 (s1[0] == '\"' && s2[0] == '\'')) {
1255 // Scan the two strings. Increment "match" count for each match.
1256 // When a transposition is encountered, increase "match" count
1257 // by two but count it as an error. When a typo is found, skip
1258 // it and count it as an error. Otherwise we have a mismatch; if
1259 // one of the strings is longer, increment its index, otherwise,
1260 // increment both indices and continue.
1262 // This algorithm is an adaptation of a boolean misspelling
1263 // algorithm proposed by Juergen Uhl.
1266 int prefix_length = 0;
1271 while ((i < n) && (j < m)) {
1272 if (s1[i] == s2[j]) {
1276 if (num_errors == 0) {
1279 } else if (s1[i+1] == s2[j] && s1[i] == s2[j+1]) {
1284 } else if (s1[i+1] == s2[j+1]) {
1289 if ((n - i) > (m - j)) {
1291 } else if ((m - j) > (n - i)) {
1304 if (num_errors > ((n < m ? n : m) / 6 + 1))
1305 count = prefix_length;
1307 return(count * 10 / ((n < len ? len : n) + num_errors));
1310 private PrimaryRepairInfo scopeTrial(int stck[], int stack_top, PrimaryRepairInfo repair) {
1311 stateSeen = new int[stackLength];
1312 for (int i = 0; i < stackLength; i++)
1316 statePool = new StateInfo[stackLength];
1318 scopeTrialCheck(stck, stack_top, repair, 0);
1323 repair.code = SCOPE_CODE;
1324 repair.misspellIndex = 10;
1329 private void scopeTrialCheck(int stck[], int stack_top, PrimaryRepairInfo repair, int indx) {
1330 if(indx > 20) return; // avoid too much recursive call to improve performance
1332 int act = stck[stack_top];
1334 for (int i = stateSeen[stack_top]; i != NIL; i = statePool[i].next) {
1335 if (statePool[i].state == act) return;
1338 int old_state_pool_top = statePoolTop++;
1339 if(statePoolTop >= statePool.length) {
1340 System.arraycopy(statePool, 0, statePool = new StateInfo[statePoolTop * 2], 0, statePoolTop);
1343 statePool[old_state_pool_top] = new StateInfo(act, stateSeen[stack_top]);
1344 stateSeen[stack_top] = old_state_pool_top;
1346 for (int i = 0; i < SCOPE_SIZE; i++) {
1348 // Use the scope lookahead symbol to force all reductions
1349 // inducible by that symbol.
1351 act = stck[stack_top];
1352 tempStackTop = stack_top - 1;
1353 int max_pos = stack_top;
1354 int tok = Parser.scope_la[i];
1355 lexStream.reset(buffer[repair.bufferPosition]);
1356 act = Parser.tAction(act, tok);
1357 while(act <= NUM_RULES) {
1359 // ... Process all goto-reduce actions following
1360 // reduction, until a goto action is computed ...
1363 tempStackTop -= (Parser.rhs[act]-1);
1364 int lhs_symbol = Parser.lhs[act];
1365 act = (tempStackTop > max_pos
1366 ? tempStack[tempStackTop]
1367 : stck[tempStackTop]);
1368 act = Parser.ntAction(act, lhs_symbol);
1369 } while(act <= NUM_RULES);
1370 if (tempStackTop + 1 >= stackLength)
1372 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1373 tempStack[tempStackTop + 1] = act;
1374 act = Parser.tAction(act, tok);
1378 // If the lookahead symbol is parsable, then we check
1379 // whether or not we have a match between the scope
1380 // prefix and the transition symbols corresponding to
1381 // the states on top of the stack.
1383 if (act != ERROR_ACTION) {
1385 k = Parser.scope_prefix[i];
1386 for (j = tempStackTop + 1;
1387 j >= (max_pos + 1) &&
1388 Parser.in_symbol(tempStack[j]) == Parser.scope_rhs[k]; j--) {
1393 j >= 1 && Parser.in_symbol(stck[j]) == Parser.scope_rhs[k];
1399 // If the prefix matches, check whether the state
1400 // newly exposed on top of the stack, (after the
1401 // corresponding prefix states are popped from the
1402 // stack), is in the set of "source states" for the
1403 // scope in question and that it is at a position
1404 // below the threshold indicated by MARKED_POS.
1406 int marked_pos = (max_pos < stack_top ? max_pos + 1 : stack_top);
1407 if (Parser.scope_rhs[k] == 0 && j < marked_pos) { // match?
1408 int stack_position = j;
1409 for (j = Parser.scope_state_set[i];
1410 stck[stack_position] != Parser.scope_state[j] &&
1411 Parser.scope_state[j] != 0;
1414 // If the top state is valid for scope recovery,
1415 // the left-hand side of the scope is used as
1416 // starting symbol and we calculate how far the
1417 // parser can advance within the forward context
1418 // after parsing the left-hand symbol.
1420 if (Parser.scope_state[j] != 0) { // state was found
1421 int previous_distance = repair.distance;
1422 int distance = parseCheck(stck,
1424 Parser.scope_lhs[i]+NT_OFFSET,
1425 repair.bufferPosition);
1427 // if the recovery is not successful, we
1428 // update the stack with all actions induced
1429 // by the left-hand symbol, and recursively
1430 // call SCOPE_TRIAL_CHECK to try again.
1431 // Otherwise, the recovery is successful. If
1432 // the new distance is greater than the
1433 // initial SCOPE_DISTANCE, we update
1434 // SCOPE_DISTANCE and set scope_stack_top to INDX
1435 // to indicate the number of scopes that are
1436 // to be applied for a succesful recovery.
1437 // NOTE that this procedure cannot get into
1438 // an infinite loop, since each prefix match
1439 // is guaranteed to take us to a lower point
1440 // within the stack.
1442 if ((distance - repair.bufferPosition + 1) < MIN_DISTANCE) {
1443 int top = stack_position;
1444 act = Parser.ntAction(stck[top], Parser.scope_lhs[i]);
1445 while(act <= NUM_RULES) {
1446 top -= (Parser.rhs[act]-1);
1447 act = Parser.ntAction(stck[top], Parser.lhs[act]);
1452 act = stck[top]; // save
1453 stck[top] = j; // swap
1454 scopeTrialCheck(stck, top, repair, indx+1);
1455 stck[top] = act; // restore
1456 } else if (distance > repair.distance) {
1457 scopeStackTop = indx;
1458 repair.distance = distance;
1461 if (lexStream.kind(buffer[repair.bufferPosition]) == EOFT_SYMBOL &&
1462 repair.distance == previous_distance) {
1463 scopeStackTop = indx;
1464 repair.distance = MAX_DISTANCE;
1468 // If this scope recovery has beaten the
1469 // previous distance, then we have found a
1470 // better recovery (or this recovery is one
1471 // of a list of scope recoveries). Record
1472 // its information at the proper location
1473 // (INDX) in SCOPE_INDEX and SCOPE_STACK.
1475 if (repair.distance > previous_distance) {
1476 scopeIndex[indx] = i;
1477 scopePosition[indx] = stack_position;
1486 // This function computes the ParseCheck distance for the best
1487 // possible secondary recovery for a given configuration that
1488 // either deletes none or only one symbol in the forward context.
1489 // If the recovery found is more effective than the best primary
1490 // recovery previously computed, then the function returns true.
1491 // Only misplacement, scope and manual recoveries are attempted;
1492 // simple insertion or substitution of a nonterminal are tried
1493 // in CHECK_PRIMARY_DISTANCE as part of primary recovery.
1495 private boolean secondaryCheck(int stck[], int stack_top, int buffer_position, int distance) {
1498 for (top = stack_top - 1; top >= 0; top--) {
1499 j = parseCheck(stck, top,
1500 lexStream.kind(buffer[buffer_position]),
1501 buffer_position + 1);
1502 if (((j - buffer_position + 1) > MIN_DISTANCE) && (j > distance))
1506 PrimaryRepairInfo repair = new PrimaryRepairInfo();
1507 repair.bufferPosition = buffer_position + 1;
1508 repair.distance = distance;
1509 repair = scopeTrial(stck, stack_top, repair);
1510 if ((repair.distance - buffer_position) > MIN_DISTANCE && repair.distance > distance)
1517 // Secondary_phase is a boolean function that checks whether or
1518 // not some form of secondary recovery is applicable to one of
1519 // the error configurations. First, if "next_stack" is available,
1520 // misplacement and secondary recoveries are attempted on it.
1521 // Then, in any case, these recoveries are attempted on "stack".
1522 // If a successful recovery is found, a diagnosis is issued, the
1523 // configuration is updated and the function returns "true".
1524 // Otherwise, the function returns false.
1526 private RepairCandidate secondaryPhase(int error_token) {
1527 SecondaryRepairInfo repair = new SecondaryRepairInfo();
1528 SecondaryRepairInfo misplaced = new SecondaryRepairInfo();
1530 RepairCandidate candidate = new RepairCandidate();
1533 int next_last_index = 0;
1536 candidate.symbol = 0;
1539 repair.distance = 0;
1540 repair.recoveryOnNextStack = false;
1542 misplaced.distance = 0;
1543 misplaced.recoveryOnNextStack = false;
1546 // If the next_stack is available, try misplaced and secondary
1547 // recovery on it first.
1549 if (nextStackTop >= 0) {
1552 buffer[2] = error_token;
1553 buffer[1] = lexStream.previous(buffer[2]);
1554 buffer[0] = lexStream.previous(buffer[1]);
1556 for (k = 3; k < BUFF_UBOUND; k++)
1557 buffer[k] = lexStream.next(buffer[k - 1]);
1559 buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1562 // If we are at the end of the input stream, compute the
1563 // index position of the first EOFT symbol (last useful
1566 for (next_last_index = MAX_DISTANCE - 1;
1567 next_last_index >= 1 &&
1568 lexStream.kind(buffer[next_last_index]) == EOFT_SYMBOL;
1569 next_last_index--){/*empty*/}
1570 next_last_index = next_last_index + 1;
1572 save_location = locationStack[nextStackTop];
1573 int save_location_start = locationStartStack[nextStackTop];
1574 locationStack[nextStackTop] = buffer[2];
1575 locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1576 misplaced.numDeletions = nextStackTop;
1577 misplaced = misplacementRecovery(nextStack, nextStackTop,
1580 if (misplaced.recoveryOnNextStack)
1581 misplaced.distance++;
1583 repair.numDeletions = nextStackTop + BUFF_UBOUND;
1584 repair = secondaryRecovery(nextStack, nextStackTop,
1587 if (repair.recoveryOnNextStack)
1590 locationStack[nextStackTop] = save_location;
1591 locationStartStack[nextStackTop] = save_location_start;
1592 } else { // next_stack not available, initialize ...
1593 misplaced.numDeletions = stateStackTop;
1594 repair.numDeletions = stateStackTop + BUFF_UBOUND;
1598 // Try secondary recovery on the "stack" configuration.
1600 buffer[3] = error_token;
1602 buffer[2] = lexStream.previous(buffer[3]);
1603 buffer[1] = lexStream.previous(buffer[2]);
1604 buffer[0] = lexStream.previous(buffer[1]);
1606 for (k = 4; k < BUFF_SIZE; k++)
1607 buffer[k] = lexStream.next(buffer[k - 1]);
1609 for (last_index = MAX_DISTANCE - 1;
1610 last_index >= 1 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL;
1611 last_index--){/*empty*/}
1614 misplaced = misplacementRecovery(stack, stateStackTop,
1618 repair = secondaryRecovery(stack, stateStackTop,
1619 last_index, repair, false);
1622 // If a successful misplaced recovery was found, compare it with
1623 // the most successful secondary recovery. If the misplaced
1624 // recovery either deletes fewer symbols or parse-checks further
1625 // then it is chosen.
1627 if (misplaced.distance > MIN_DISTANCE) {
1628 if (misplaced.numDeletions <= repair.numDeletions ||
1629 (misplaced.distance - misplaced.numDeletions) >=
1630 (repair.distance - repair.numDeletions)) {
1631 repair.code = MISPLACED_CODE;
1632 repair.stackPosition = misplaced.stackPosition;
1633 repair.bufferPosition = 2;
1634 repair.numDeletions = misplaced.numDeletions;
1635 repair.distance = misplaced.distance;
1636 repair.recoveryOnNextStack = misplaced.recoveryOnNextStack;
1641 // If the successful recovery was on next_stack, update: stack,
1642 // buffer, location_stack and last_index.
1644 if (repair.recoveryOnNextStack) {
1645 stateStackTop = nextStackTop;
1646 for (i = 0; i <= stateStackTop; i++)
1647 stack[i] = nextStack[i];
1649 buffer[2] = error_token;
1650 buffer[1] = lexStream.previous(buffer[2]);
1651 buffer[0] = lexStream.previous(buffer[1]);
1653 for (k = 3; k < BUFF_UBOUND; k++)
1654 buffer[k] = lexStream.next(buffer[k - 1]);
1656 buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1658 locationStack[nextStackTop] = buffer[2];
1659 locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1660 last_index = next_last_index;
1664 // Next, try scope recoveries after deletion of one, two, three,
1665 // four ... buffer_position tokens from the input stream.
1667 if (repair.code == SECONDARY_CODE || repair.code == DELETION_CODE) {
1668 PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1670 scope_repair.distance = 0;
1671 for (scope_repair.bufferPosition = 2;
1672 scope_repair.bufferPosition <= repair.bufferPosition &&
1673 repair.code != SCOPE_CODE; scope_repair.bufferPosition++) {
1674 scope_repair = scopeTrial(stack, stateStackTop, scope_repair);
1675 j = (scope_repair.distance == MAX_DISTANCE
1677 : scope_repair.distance);
1678 k = scope_repair.bufferPosition - 1;
1679 if ((j - k) > MIN_DISTANCE && (j - k) > (repair.distance - repair.numDeletions)) {
1680 repair.code = SCOPE_CODE;
1681 i = scopeIndex[scopeStackTop]; // upper bound
1682 repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1683 repair.stackPosition = stateStackTop;
1684 repair.bufferPosition = scope_repair.bufferPosition;
1690 // If no successful recovery is found and we have reached the
1691 // end of the file, check whether or not scope recovery is
1692 // applicable at the end of the file after discarding some
1695 if (repair.code == 0 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL) {
1696 PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1698 scope_repair.bufferPosition = last_index;
1699 scope_repair.distance = 0;
1700 for (top = stateStackTop;
1701 top >= 0 && repair.code == 0; top--)
1703 scope_repair = scopeTrial(stack, top, scope_repair);
1704 if (scope_repair.distance > 0)
1706 repair.code = SCOPE_CODE;
1707 i = scopeIndex[scopeStackTop]; // upper bound
1708 repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1709 repair.stackPosition = top;
1710 repair.bufferPosition = scope_repair.bufferPosition;
1716 // If a successful repair was not found, quit! Otherwise, issue
1717 // diagnosis and adjust configuration...
1719 if (repair.code == 0)
1722 secondaryDiagnosis(repair);
1725 // Update buffer based on number of elements that are deleted.
1727 switch(repair.code) {
1728 case MISPLACED_CODE:
1729 candidate.location = buffer[2];
1730 candidate.symbol = lexStream.kind(buffer[2]);
1731 lexStream.reset(lexStream.next(buffer[2]));
1736 candidate.location = buffer[repair.bufferPosition];
1738 lexStream.kind(buffer[repair.bufferPosition]);
1739 lexStream.reset(lexStream.next(buffer[repair.bufferPosition]));
1743 default: // SCOPE_CODE || SECONDARY_CODE
1744 candidate.symbol = repair.symbol;
1745 candidate.location = buffer[repair.bufferPosition];
1746 lexStream.reset(buffer[repair.bufferPosition]);
1756 // This boolean function checks whether or not a given
1757 // configuration yields a better misplacement recovery than
1758 // the best misplacement recovery computed previously.
1760 private SecondaryRepairInfo misplacementRecovery(int stck[], int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1761 int previous_loc = buffer[2];
1762 int stack_deletions = 0;
1764 for (int top = stack_top - 1; top >= 0; top--) {
1765 if (locationStack[top] < previous_loc) {
1768 previous_loc = locationStack[top];
1770 int j = parseCheck(stck, top, lexStream.kind(buffer[2]), 3);
1771 if (j == MAX_DISTANCE) {
1774 if ((j > MIN_DISTANCE) && (j - stack_deletions) > (repair.distance - repair.numDeletions)) {
1775 repair.stackPosition = top;
1776 repair.distance = j;
1777 repair.numDeletions = stack_deletions;
1778 repair.recoveryOnNextStack = stack_flag;
1787 // This boolean function checks whether or not a given
1788 // configuration yields a better secondary recovery than the
1789 // best misplacement recovery computed previously.
1791 private SecondaryRepairInfo secondaryRecovery(int stck[],int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1793 int stack_deletions = 0;
1795 previous_loc = buffer[2];
1796 for (int top = stack_top; top >= 0 && repair.numDeletions >= stack_deletions; top--) {
1797 if (locationStack[top] < previous_loc) {
1800 previous_loc = locationStack[top];
1803 i <= (last_index - MIN_DISTANCE + 1) &&
1804 (repair.numDeletions >= (stack_deletions + i - 1)); i++) {
1805 int j = parseCheck(stck, top, lexStream.kind(buffer[i]), i + 1);
1807 if (j == MAX_DISTANCE) {
1810 if ((j - i + 1) > MIN_DISTANCE) {
1811 int k = stack_deletions + i - 1;
1812 if ((k < repair.numDeletions) ||
1813 (j - k) > (repair.distance - repair.numDeletions) ||
1814 ((repair.code == SECONDARY_CODE) && (j - k) == (repair.distance - repair.numDeletions))) {
1815 repair.code = DELETION_CODE;
1816 repair.distance = j;
1817 repair.stackPosition = top;
1818 repair.bufferPosition = i;
1819 repair.numDeletions = k;
1820 repair.recoveryOnNextStack = stack_flag;
1824 for (int l = Parser.nasi(stck[top]); l >= 0 && Parser.nasr[l] != 0; l++) {
1825 int symbol = Parser.nasr[l] + NT_OFFSET;
1826 j = parseCheck(stck, top, symbol, i);
1827 if (j == MAX_DISTANCE) {
1830 if ((j - i + 1) > MIN_DISTANCE) {
1831 int k = stack_deletions + i - 1;
1832 if (k < repair.numDeletions || (j - k) > (repair.distance - repair.numDeletions)) {
1833 repair.code = SECONDARY_CODE;
1834 repair.symbol = symbol;
1835 repair.distance = j;
1836 repair.stackPosition = top;
1837 repair.bufferPosition = i;
1838 repair.numDeletions = k;
1839 repair.recoveryOnNextStack = stack_flag;
1851 // This procedure is invoked to issue a secondary diagnosis and
1852 // adjust the input buffer. The recovery in question is either
1853 // an automatic scope recovery, a manual scope recovery, a
1854 // secondary substitution or a secondary deletion.
1856 private void secondaryDiagnosis(SecondaryRepairInfo repair) {
1857 switch(repair.code) {
1859 if (repair.stackPosition < stateStackTop) {
1860 reportError(DELETION_CODE,
1861 Parser.terminal_index[ERROR_SYMBOL],
1862 locationStack[repair.stackPosition],
1865 for (int i = 0; i < scopeStackTop; i++) {
1866 reportError(SCOPE_CODE,
1868 locationStack[scopePosition[i]],
1870 Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
1873 repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
1874 stateStackTop = scopePosition[scopeStackTop];
1875 reportError(SCOPE_CODE,
1876 -scopeIndex[scopeStackTop],
1877 locationStack[scopePosition[scopeStackTop]],
1879 getNtermIndex(stack[stateStackTop],
1881 repair.bufferPosition)
1886 reportError(repair.code,
1887 (repair.code == SECONDARY_CODE
1888 ? getNtermIndex(stack[repair.stackPosition],
1890 repair.bufferPosition)
1891 : Parser.terminal_index[ERROR_SYMBOL]),
1892 locationStack[repair.stackPosition],
1893 buffer[repair.bufferPosition - 1]);
1894 stateStackTop = repair.stackPosition;
1903 // Try to parse until first_token and all tokens in BUFFER have
1904 // been consumed, or an error is encountered. Return the number
1905 // of tokens that were expended before the parse blocked.
1907 private int parseCheck(int stck[], int stack_top, int first_token, int buffer_position) {
1914 // Initialize pointer for temp_stack and initialize maximum
1915 // position of state stack that is still useful.
1917 act = stck[stack_top];
1918 if (first_token > NT_OFFSET) {
1919 tempStackTop = stack_top;
1920 if(DEBUG_PARSECHECK) {
1921 System.out.println(tempStackTop);
1923 max_pos = stack_top;
1924 indx = buffer_position;
1925 ct = lexStream.kind(buffer[indx]);
1926 lexStream.reset(lexStream.next(buffer[indx]));
1927 int lhs_symbol = first_token - NT_OFFSET;
1928 act = Parser.ntAction(act, lhs_symbol);
1929 if (act <= NUM_RULES) {
1930 // same loop as 'process_non_terminal'
1932 tempStackTop -= (Parser.rhs[act]-1);
1934 if(DEBUG_PARSECHECK) {
1935 System.out.print(tempStackTop);
1936 System.out.print(" ("); //$NON-NLS-1$
1937 System.out.print(-(Parser.rhs[act]-1));
1938 System.out.print(") [max:"); //$NON-NLS-1$
1939 System.out.print(max_pos);
1940 System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
1941 System.out.print(act);
1942 System.out.print("\t"); //$NON-NLS-1$
1943 System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
1944 System.out.println();
1947 if(Parser.rules_compliance[act] > this.options.sourceLevel) {
1950 lhs_symbol = Parser.lhs[act];
1951 act = (tempStackTop > max_pos
1952 ? tempStack[tempStackTop]
1953 : stck[tempStackTop]);
1954 act = Parser.ntAction(act, lhs_symbol);
1955 } while(act <= NUM_RULES);
1957 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1960 tempStackTop = stack_top - 1;
1962 if(DEBUG_PARSECHECK) {
1963 System.out.println(tempStackTop);
1966 max_pos = tempStackTop;
1967 indx = buffer_position - 1;
1969 lexStream.reset(buffer[buffer_position]);
1972 process_terminal: for (;;) {
1973 if(DEBUG_PARSECHECK) {
1974 System.out.print(tempStackTop + 1);
1975 System.out.print(" (+1) [max:"); //$NON-NLS-1$
1976 System.out.print(max_pos);
1977 System.out.print("]\tprocess_terminal \t"); //$NON-NLS-1$
1978 System.out.print(ct);
1979 System.out.print("\t"); //$NON-NLS-1$
1980 System.out.print(Parser.name[Parser.terminal_index[ct]]);
1981 System.out.println();
1984 if (++tempStackTop >= stackLength) // Stack overflow!!!
1986 tempStack[tempStackTop] = act;
1988 act = Parser.tAction(act, ct);
1990 if (act <= NUM_RULES) { // reduce action
1993 if(DEBUG_PARSECHECK) {
1994 System.out.print(tempStackTop);
1995 System.out.print(" (-1) [max:"); //$NON-NLS-1$
1996 System.out.print(max_pos);
1997 System.out.print("]\treduce"); //$NON-NLS-1$
1998 System.out.println();
2000 } else if (act < ACCEPT_ACTION || // shift action
2001 act > ERROR_ACTION) { // shift-reduce action
2002 if (indx == MAX_DISTANCE)
2005 ct = lexStream.kind(buffer[indx]);
2006 lexStream.reset(lexStream.next(buffer[indx]));
2007 if (act > ERROR_ACTION) {
2008 act -= ERROR_ACTION;
2010 if(DEBUG_PARSECHECK) {
2011 System.out.print(tempStackTop);
2012 System.out.print("\tshift reduce"); //$NON-NLS-1$
2013 System.out.println();
2016 if(DEBUG_PARSECHECK) {
2017 System.out.println("\tshift"); //$NON-NLS-1$
2019 continue process_terminal;
2021 } else if (act == ACCEPT_ACTION) { // accept action
2022 return MAX_DISTANCE;
2024 return indx; // error action
2027 // same loop as first token initialization
2028 process_non_terminal:
2030 tempStackTop -= (Parser.rhs[act]-1);
2032 if(DEBUG_PARSECHECK) {
2033 System.out.print(tempStackTop);
2034 System.out.print(" ("); //$NON-NLS-1$
2035 System.out.print(-(Parser.rhs[act]-1));
2036 System.out.print(") [max:"); //$NON-NLS-1$
2037 System.out.print(max_pos);
2038 System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
2039 System.out.print(act);
2040 System.out.print("\t"); //$NON-NLS-1$
2041 System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
2042 System.out.println();
2045 if(act <= NUM_RULES) {
2046 if(Parser.rules_compliance[act] > this.options.sourceLevel) {
2050 int lhs_symbol = Parser.lhs[act];
2051 act = (tempStackTop > max_pos
2052 ? tempStack[tempStackTop]
2053 : stck[tempStackTop]);
2054 act = Parser.ntAction(act, lhs_symbol);
2055 } while(act <= NUM_RULES);
2057 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
2058 } // process_terminal;
2060 private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken) {
2061 reportError(msgCode, nameIndex, leftToken, rightToken, 0);
2064 private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
2065 int lToken = (leftToken > rightToken ? rightToken : leftToken);
2067 if (lToken < rightToken) {
2068 reportSecondaryError(msgCode, nameIndex, lToken, rightToken, scopeNameIndex);
2070 reportPrimaryError(msgCode, nameIndex, rightToken, scopeNameIndex);
2073 private void reportPrimaryError(int msgCode, int nameIndex, int token, int scopeNameIndex) {
2075 if (nameIndex >= 0) {
2076 name = Parser.readableName[nameIndex];
2078 name = EMPTY_STRING;
2081 int errorStart = lexStream.start(token);
2082 int errorEnd = lexStream.end(token);
2083 int currentKind = lexStream.kind(token);
2084 String errorTokenName = Parser.name[Parser.terminal_index[lexStream.kind(token)]];
2085 char[] errorTokenSource = lexStream.name(token);
2089 problemReporter().parseErrorInsertBeforeToken(
2097 case INSERTION_CODE:
2098 problemReporter().parseErrorInsertAfterToken(
2107 problemReporter().parseErrorDeleteToken(
2115 if (name.length() == 0) {
2116 problemReporter().parseErrorReplaceToken(
2124 problemReporter().parseErrorInvalidToken(
2133 case SUBSTITUTION_CODE:
2134 problemReporter().parseErrorReplaceToken(
2143 StringBuffer buf = new StringBuffer();
2144 for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2145 buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2146 if (Parser.scope_rhs[i + 1] != 0) // any more symbols to print?
2151 if (scopeNameIndex != 0) {
2152 problemReporter().parseErrorInsertToComplete(
2156 Parser.readableName[scopeNameIndex]);
2158 problemReporter().parseErrorInsertToCompleteScope(
2166 problemReporter().parseErrorUnexpectedEnd(
2171 problemReporter().parseErrorMergeTokens(
2176 case MISPLACED_CODE:
2177 problemReporter().parseErrorMisplacedConstruct(
2182 if (name.length() == 0) {
2183 problemReporter().parseErrorNoSuggestion(
2190 problemReporter().parseErrorReplaceToken(
2202 private void reportSecondaryError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
2204 if (nameIndex >= 0) {
2205 name = Parser.readableName[nameIndex];
2207 name = EMPTY_STRING;
2210 int errorStart = -1;
2211 if(lexStream.isInsideStream(leftToken)) {
2212 if(leftToken == 0) {
2213 errorStart = lexStream.start(leftToken + 1);
2215 errorStart = lexStream.start(leftToken);
2218 if(leftToken == errorToken) {
2219 errorStart = errorTokenStart;
2221 for (int i = 0; i <= stateStackTop; i++) {
2222 if(locationStack[i] == leftToken) {
2223 errorStart = locationStartStack[i];
2227 if(errorStart == -1) {
2228 errorStart = lexStream.start(rightToken);
2231 int errorEnd = lexStream.end(rightToken);
2234 case MISPLACED_CODE:
2235 problemReporter().parseErrorMisplacedConstruct(
2240 // error start is on the last token start
2241 errorStart = lexStream.start(rightToken);
2243 StringBuffer buf = new StringBuffer();
2244 for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2245 buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2246 if (Parser.scope_rhs[i+1] != 0)
2249 if (scopeNameIndex != 0) {
2250 problemReporter().parseErrorInsertToComplete(
2254 Parser.readableName[scopeNameIndex]);
2256 problemReporter().parseErrorInsertToCompletePhrase(
2263 problemReporter().parseErrorMergeTokens(
2269 problemReporter().parseErrorDeleteTokens(
2274 if (name.length() == 0) {
2275 problemReporter().parseErrorNoSuggestionForTokens(
2279 problemReporter().parseErrorReplaceTokens(
2288 public String toString() {
2289 StringBuffer res = new StringBuffer();
2291 res.append(lexStream.toString());
2293 return res.toString();