KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > parser > diagnose > DiagnoseParser


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.parser.diagnose;
12
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.RecoveryScanner;
18 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
19 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
20 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
21 import org.eclipse.jdt.internal.compiler.util.Util;
22
23 public class DiagnoseParser implements ParserBasicInformation, TerminalTokens {
24     private static final boolean DEBUG = false;
25     private boolean DEBUG_PARSECHECK = false;
26
27     private static final int STACK_INCREMENT = 256;
28     
29 // private static final int ERROR_CODE = 1;
30
private static final int BEFORE_CODE = 2;
31     private static final int INSERTION_CODE = 3;
32     private static final int INVALID_CODE = 4;
33     private static final int SUBSTITUTION_CODE = 5;
34     private static final int DELETION_CODE = 6;
35     private static final int MERGE_CODE = 7;
36     private static final int MISPLACED_CODE = 8;
37     private static final int SCOPE_CODE = 9;
38     private static final int SECONDARY_CODE = 10;
39     private static final int EOF_CODE = 11;
40
41     private static final int BUFF_UBOUND = 31;
42     private static final int BUFF_SIZE = 32;
43     private static final int MAX_DISTANCE = 30;
44     private static final int MIN_DISTANCE = 3;
45     
46     private CompilerOptions options;
47     
48     private LexStream lexStream;
49     private int errorToken;
50     private int errorTokenStart;
51     
52     private int currentToken = 0;
53     
54     private int stackLength;
55     private int stateStackTop;
56     private int[] stack;
57     
58     private int[] locationStack;
59     private int[] locationStartStack;
60     
61     private int tempStackTop;
62     private int[] tempStack;
63     
64     private int prevStackTop;
65     private int[] prevStack;
66     private int nextStackTop;
67     private int[] nextStack;
68     
69     private int scopeStackTop;
70     private int[] scopeIndex;
71     private int[] scopePosition;
72     
73     int[] list = new int[NUM_SYMBOLS + 1];
74     int[] buffer = new int[BUFF_SIZE];
75     
76     private static final int NIL = -1;
77     int[] stateSeen;
78     
79     int statePoolTop;
80     StateInfo[] statePool;
81     
82     private Parser parser;
83     
84     private RecoveryScanner recoveryScanner;
85     
86     private boolean reportProblem;
87     
88     private static class RepairCandidate {
89         public int symbol;
90         public int location;
91         
92         public RepairCandidate(){
93             this.symbol = 0;
94             this.location = 0;
95         }
96     }
97     
98     private static class PrimaryRepairInfo {
99         public int distance;
100         public int misspellIndex;
101         public int code;
102         public int bufferPosition;
103         public int symbol;
104         
105         public PrimaryRepairInfo(){
106             this.distance = 0;
107             this.misspellIndex = 0;
108             this.code = 0;
109             this.bufferPosition = 0;
110             this.symbol = 0;
111         }
112         
113         public PrimaryRepairInfo copy(){
114             PrimaryRepairInfo c = new PrimaryRepairInfo();
115             c.distance = this.distance;
116             c.misspellIndex = this.misspellIndex;
117             c.code = this.code;
118             c.bufferPosition = this .bufferPosition;
119             c.symbol = this.symbol;
120             return c;
121             
122         }
123     }
124     
125     static class SecondaryRepairInfo {
126         public int code;
127         public int distance;
128         public int bufferPosition;
129         public int stackPosition;
130         public int numDeletions;
131         public int symbol;
132
133         boolean recoveryOnNextStack;
134     }
135     
136     private static class StateInfo {
137         int state;
138         int next;
139         
140         public StateInfo(int state, int next){
141             this.state = state;
142             this.next = next;
143         }
144     }
145
146     public DiagnoseParser(Parser parser, int firstToken, int start, int end, CompilerOptions options) {
147         this(parser, firstToken, start, end, Util.EMPTY_INT_ARRAY, Util.EMPTY_INT_ARRAY, Util.EMPTY_INT_ARRAY, options);
148     }
149
150     public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, CompilerOptions options) {
151         this.parser = parser;
152         this.options = options;
153         this.lexStream = new LexStream(BUFF_SIZE, parser.scanner, intervalStartToSkip, intervalEndToSkip, intervalFlagsToSkip, firstToken, start, end);
154         this.recoveryScanner = parser.recoveryScanner;
155     }
156     
157     private ProblemReporter problemReporter(){
158         return parser.problemReporter();
159     }
160
161     private void reallocateStacks() {
162         int old_stack_length = stackLength;
163
164         stackLength += STACK_INCREMENT;
165
166         if(old_stack_length == 0){
167             stack = new int[stackLength];
168             locationStack = new int[stackLength];
169             locationStartStack = new int[stackLength];
170             tempStack = new int[stackLength];
171             prevStack = new int[stackLength];
172             nextStack = new int[stackLength];
173             scopeIndex = new int[stackLength];
174             scopePosition = new int[stackLength];
175         } else {
176             System.arraycopy(stack, 0, stack = new int[stackLength], 0, old_stack_length);
177             System.arraycopy(locationStack, 0, locationStack = new int[stackLength], 0, old_stack_length);
178             System.arraycopy(locationStartStack, 0, locationStartStack = new int[stackLength], 0, old_stack_length);
179             System.arraycopy(tempStack, 0, tempStack = new int[stackLength], 0, old_stack_length);
180             System.arraycopy(prevStack, 0, prevStack = new int[stackLength], 0, old_stack_length);
181             System.arraycopy(nextStack, 0, nextStack = new int[stackLength], 0, old_stack_length);
182             System.arraycopy(scopeIndex, 0, scopeIndex = new int[stackLength], 0, old_stack_length);
183             System.arraycopy(scopePosition, 0, scopePosition = new int[stackLength], 0, old_stack_length);
184         }
185         return;
186     }
187
188
189     public void diagnoseParse(boolean record) {
190         this.reportProblem = true;
191         boolean oldRecord = false;
192         if(this.recoveryScanner != null) {
193             oldRecord = this.recoveryScanner.record;
194             this.recoveryScanner.record = record;
195         }
196         try {
197             lexStream.reset();
198     
199             currentToken = lexStream.getToken();
200     
201             int prev_pos;
202             int pos;
203             int next_pos;
204             int act = START_STATE;
205     
206             reallocateStacks();
207     
208             //
209
// Start parsing
210
//
211
stateStackTop = 0;
212             stack[stateStackTop] = act;
213     
214             int tok = lexStream.kind(currentToken);
215             locationStack[stateStackTop] = currentToken;
216             locationStartStack[stateStackTop] = lexStream.start(currentToken);
217             
218             boolean forceRecoveryAfterLBracketMissing = false;
219     // int forceRecoveryToken = -1;
220

221             //
222
// Process a terminal
223
//
224
do {
225                 //
226
// Synchronize state stacks and update the location stack
227
//
228
prev_pos = -1;
229                 prevStackTop = -1;
230     
231                 next_pos = -1;
232                 nextStackTop = -1;
233     
234                 pos = stateStackTop;
235                 tempStackTop = stateStackTop - 1;
236                 for (int i = 0; i <= stateStackTop; i++)
237                     tempStack[i] = stack[i];
238     
239                 act = Parser.tAction(act, tok);
240                 //
241
// When a reduce action is encountered, we compute all REDUCE
242
// and associated goto actions induced by the current token.
243
// Eventually, a SHIFT, SHIFT-REDUCE, ACCEPT or ERROR action is
244
// computed...
245
//
246
while (act <= NUM_RULES) {
247                     do {
248                         tempStackTop -= (Parser.rhs[act]-1);
249                         act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
250                     } while(act <= NUM_RULES);
251                     //
252
// ... Update the maximum useful position of the
253
// (STATE_)STACK, push goto state into stack, and
254
// compute next action on current symbol ...
255
//
256
if (tempStackTop + 1 >= stackLength)
257                         reallocateStacks();
258                     pos = pos < tempStackTop ? pos : tempStackTop;
259                     tempStack[tempStackTop + 1] = act;
260                     act = Parser.tAction(act, tok);
261                 }
262     
263                 //
264
// At this point, we have a shift, shift-reduce, accept or error
265
// action. STACK contains the configuration of the state stack
266
// prior to executing any action on curtok. next_stack contains
267
// the configuration of the state stack after executing all
268
// reduce actions induced by curtok. The variable pos indicates
269
// the highest position in STACK that is still useful after the
270
// reductions are executed.
271
//
272
while(act > ERROR_ACTION || act < ACCEPT_ACTION) { // SHIFT-REDUCE action or SHIFT action ?
273
nextStackTop = tempStackTop + 1;
274                     for (int i = next_pos + 1; i <= nextStackTop; i++)
275                         nextStack[i] = tempStack[i];
276     
277                     for (int i = pos + 1; i <= nextStackTop; i++) {
278                         locationStack[i] = locationStack[stateStackTop];
279                         locationStartStack[i] = locationStartStack[stateStackTop];
280                     }
281     
282                     //
283
// If we have a shift-reduce, process it as well as
284
// the goto-reduce actions that follow it.
285
//
286
if (act > ERROR_ACTION) {
287                         act -= ERROR_ACTION;
288                         do {
289                             nextStackTop -= (Parser.rhs[act]-1);
290                             act = Parser.ntAction(nextStack[nextStackTop], Parser.lhs[act]);
291                         } while(act <= NUM_RULES);
292                         pos = pos < nextStackTop ? pos : nextStackTop;
293                     }
294     
295                     if (nextStackTop + 1 >= stackLength)
296                         reallocateStacks();
297     
298                     tempStackTop = nextStackTop;
299                     nextStack[++nextStackTop] = act;
300                     next_pos = nextStackTop;
301     
302                     //
303
// Simulate the parser through the next token without
304
// destroying STACK or next_stack.
305
//
306
currentToken = lexStream.getToken();
307                     tok = lexStream.kind(currentToken);
308                     act = Parser.tAction(act, tok);
309                     while(act <= NUM_RULES) {
310                         //
311
// ... Process all goto-reduce actions following
312
// reduction, until a goto action is computed ...
313
//
314
do {
315                             int lhs_symbol = Parser.lhs[act];
316                             if(DEBUG) {
317                                 System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
318                             }
319                             tempStackTop -= (Parser.rhs[act]-1);
320                             act = (tempStackTop > next_pos
321                                        ? tempStack[tempStackTop]
322                                        : nextStack[tempStackTop]);
323                             act = Parser.ntAction(act, lhs_symbol);
324                         } while(act <= NUM_RULES);
325     
326                         //
327
// ... Update the maximum useful position of the
328
// (STATE_)STACK, push GOTO state into stack, and
329
// compute next action on current symbol ...
330
//
331
if (tempStackTop + 1 >= stackLength)
332                             reallocateStacks();
333     
334                         next_pos = next_pos < tempStackTop ? next_pos : tempStackTop;
335                         tempStack[tempStackTop + 1] = act;
336                         act = Parser.tAction(act, tok);
337                     }
338     
339     // if((tok != TokenNameRBRACE || (forceRecoveryToken != currentToken && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0))
340
// && (lexStream.flags(currentToken) & LexStream.IS_AFTER_JUMP) !=0) {
341
// act = ERROR_ACTION;
342
// if(forceRecoveryToken != currentToken
343
// && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0) {
344
// forceRecoveryAfterLBracketMissing = true;
345
// forceRecoveryToken = currentToken;
346
// }
347
// }
348

349                     //
350
// No error was detected, Read next token into
351
// PREVTOK element, advance CURTOK pointer and
352
// update stacks.
353
//
354
if (act != ERROR_ACTION) {
355                         prevStackTop = stateStackTop;
356                         for (int i = prev_pos + 1; i <= prevStackTop; i++)
357                             prevStack[i] = stack[i];
358                         prev_pos = pos;
359     
360                         stateStackTop = nextStackTop;
361                         for (int i = pos + 1; i <= stateStackTop; i++)
362                             stack[i] = nextStack[i];
363                         locationStack[stateStackTop] = currentToken;
364                         locationStartStack[stateStackTop] = lexStream.start(currentToken);
365                         pos = next_pos;
366                     }
367                 }
368     
369                 //
370
// At this stage, either we have an ACCEPT or an ERROR
371
// action.
372
//
373
if (act == ERROR_ACTION) {
374                     //
375
// An error was detected.
376
//
377
RepairCandidate candidate = errorRecovery(currentToken, forceRecoveryAfterLBracketMissing);
378                     
379                     forceRecoveryAfterLBracketMissing = false;
380                     
381                     if(parser.reportOnlyOneSyntaxError) {
382                         return;
383                     }
384                     
385                     if(this.parser.problemReporter().options.maxProblemsPerUnit < this.parser.compilationUnit.compilationResult.problemCount) {
386                         if(this.recoveryScanner == null || !this.recoveryScanner.record) return;
387                         this.reportProblem = false;
388                     }
389     
390                     act = stack[stateStackTop];
391     
392                     //
393
// If the recovery was successful on a nonterminal candidate,
394
// parse through that candidate and "read" the next token.
395
//
396
if (candidate.symbol == 0) {
397                         break;
398                     } else if (candidate.symbol > NT_OFFSET) {
399                         int lhs_symbol = candidate.symbol - NT_OFFSET;
400                         if(DEBUG) {
401                             System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
402                         }
403                         act = Parser.ntAction(act, lhs_symbol);
404                         while(act <= NUM_RULES) {
405                             stateStackTop -= (Parser.rhs[act]-1);
406                             act = Parser.ntAction(stack[stateStackTop], Parser.lhs[act]);
407                         }
408                         stack[++stateStackTop] = act;
409                         currentToken = lexStream.getToken();
410                         tok = lexStream.kind(currentToken);
411                         locationStack[stateStackTop] = currentToken;
412                         locationStartStack[stateStackTop] = lexStream.start(currentToken);
413                     } else {
414                         tok = candidate.symbol;
415                         locationStack[stateStackTop] = candidate.location;
416                         locationStartStack[stateStackTop] = lexStream.start(candidate.location);
417                     }
418                 }
419             } while (act != ACCEPT_ACTION);
420         } finally {
421             if(this.recoveryScanner != null) {
422                 this.recoveryScanner.record = oldRecord;
423             }
424         }
425         return;
426     }
427
428     //
429
// This routine is invoked when an error is encountered. It
430
// tries to diagnose the error and recover from it. If it is
431
// successful, the state stack, the current token and the buffer
432
// are readjusted; i.e., after a successful recovery,
433
// state_stack_top points to the location in the state stack
434
// that contains the state on which to recover; curtok
435
// identifies the symbol on which to recover.
436
//
437
// Up to three configurations may be available when this routine
438
// is invoked. PREV_STACK may contain the sequence of states
439
// preceding any action on prevtok, STACK always contains the
440
// sequence of states preceding any action on curtok, and
441
// NEXT_STACK may contain the sequence of states preceding any
442
// action on the successor of curtok.
443
//
444
private RepairCandidate errorRecovery(int error_token, boolean forcedError) {
445         this.errorToken = error_token;
446         this.errorTokenStart = lexStream.start(error_token);
447         
448         int prevtok = lexStream.previous(error_token);
449         int prevtokKind = lexStream.kind(prevtok);
450         
451         if(forcedError) {
452             int name_index = Parser.terminal_index[TokenNameLBRACE];
453
454             reportError(INSERTION_CODE, name_index, prevtok, prevtok);
455             
456             RepairCandidate candidate = new RepairCandidate();
457             candidate.symbol = TokenNameLBRACE;
458             candidate.location = error_token;
459             lexStream.reset(error_token);
460             
461             stateStackTop = nextStackTop;
462             for (int j = 0; j <= stateStackTop; j++) {
463                 stack[j] = nextStack[j];
464             }
465             locationStack[stateStackTop] = error_token;
466             locationStartStack[stateStackTop] = lexStream.start(error_token);
467             
468             return candidate;
469         }
470
471         //
472
// Try primary phase recoveries. If not successful, try secondary
473
// phase recoveries. If not successful and we are at end of the
474
// file, we issue the end-of-file error and quit. Otherwise, ...
475
//
476
RepairCandidate candidate = primaryPhase(error_token);
477         if (candidate.symbol != 0) {
478             return candidate;
479         }
480
481         candidate = secondaryPhase(error_token);
482         if (candidate.symbol != 0) {
483             return candidate;
484         }
485
486         if (lexStream.kind(error_token) == EOFT_SYMBOL) {
487             reportError(EOF_CODE,
488                         Parser.terminal_index[EOFT_SYMBOL],
489                         prevtok,
490                         prevtok);
491             candidate.symbol = 0;
492             candidate.location = error_token;
493             return candidate;
494         }
495
496         //
497
// At this point, primary and (initial attempt at) secondary
498
// recovery did not work. We will now get into "panic mode" and
499
// keep trying secondary phase recoveries until we either find
500
// a successful recovery or have consumed the remaining input
501
// tokens.
502
//
503
while(lexStream.kind(buffer[BUFF_UBOUND]) != EOFT_SYMBOL) {
504             candidate = secondaryPhase(buffer[MAX_DISTANCE - MIN_DISTANCE + 2]);
505             if (candidate.symbol != 0) {
506                 return candidate;
507             }
508         }
509
510         //
511
// We reached the end of the file while panicking. Delete all
512
// remaining tokens in the input.
513
//
514
int i;
515         for (i = BUFF_UBOUND; lexStream.kind(buffer[i]) == EOFT_SYMBOL; i--){/*empty*/}
516
517         reportError(DELETION_CODE,
518                     Parser.terminal_index[prevtokKind],//Parser.terminal_index[lexStream.kind(prevtok)],
519
error_token,
520                     buffer[i]);
521
522         candidate.symbol = 0;
523         candidate.location = buffer[i];
524
525         return candidate;
526     }
527
528 //
529
// This function tries primary and scope recovery on each
530
// available configuration. If a successful recovery is found
531
// and no secondary phase recovery can do better, a diagnosis is
532
// issued, the configuration is updated and the function returns
533
// "true". Otherwise, it returns "false".
534
//
535
private RepairCandidate primaryPhase(int error_token) {
536         PrimaryRepairInfo repair = new PrimaryRepairInfo();
537         RepairCandidate candidate = new RepairCandidate();
538
539         //
540
// Initialize the buffer.
541
//
542
int i = (nextStackTop >= 0 ? 3 : 2);
543         buffer[i] = error_token;
544
545         for (int j = i; j > 0; j--)
546             buffer[j - 1] = lexStream.previous(buffer[j]);
547
548         for (int k = i + 1; k < BUFF_SIZE; k++)
549             buffer[k] = lexStream.next(buffer[k - 1]);
550
551         //
552
// If NEXT_STACK_TOP > 0 then the parse was successful on CURTOK
553
// and the error was detected on the successor of CURTOK. In
554
// that case, first check whether or not primary recovery is
555
// possible on next_stack ...
556
//
557
if (nextStackTop >= 0) {
558             repair.bufferPosition = 3;
559             repair = checkPrimaryDistance(nextStack, nextStackTop, repair);
560         }
561
562         //
563
// ... Next, try primary recovery on the current token...
564
//
565
PrimaryRepairInfo new_repair = repair.copy();
566
567         new_repair.bufferPosition = 2;
568         new_repair = checkPrimaryDistance(stack, stateStackTop, new_repair);
569         if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
570             repair = new_repair;
571         }
572
573         //
574
// Finally, if prev_stack_top >= 0 then try primary recovery on
575
// the prev_stack configuration.
576
//
577

578         if (prevStackTop >= 0) {
579             new_repair = repair.copy();
580             new_repair.bufferPosition = 1;
581             new_repair = checkPrimaryDistance(prevStack,prevStackTop, new_repair);
582             if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
583                 repair = new_repair;
584             }
585         }
586
587         //
588
// Before accepting the best primary phase recovery obtained,
589
// ensure that we cannot do better with a similar secondary
590
// phase recovery.
591
//
592
if (nextStackTop >= 0) {// next_stack available
593
if (secondaryCheck(nextStack,nextStackTop,3,repair.distance)) {
594                 return candidate;
595             }
596         }
597         else if (secondaryCheck(stack, stateStackTop, 2, repair.distance)) {
598             return candidate;
599         }
600
601         //
602
// First, adjust distance if the recovery is on the error token;
603
// it is important that the adjustment be made here and not at
604
// each primary trial to prevent the distance tests from being
605
// biased in favor of deferred recoveries which have access to
606
// more input tokens...
607
//
608
repair.distance = repair.distance - repair.bufferPosition + 1;
609
610         //
611
// ...Next, adjust the distance if the recovery is a deletion or
612
// (some form of) substitution...
613
//
614
if (repair.code == INVALID_CODE ||
615             repair.code == DELETION_CODE ||
616             repair.code == SUBSTITUTION_CODE ||
617             repair.code == MERGE_CODE) {
618              repair.distance--;
619         }
620
621         //
622
// ... After adjustment, check if the most successful primary
623
// recovery can be applied. If not, continue with more radical
624
// recoveries...
625
//
626
if (repair.distance < MIN_DISTANCE) {
627             return candidate;
628         }
629
630         //
631
// When processing an insertion error, if the token preceeding
632
// the error token is not available, we change the repair code
633
// into a BEFORE_CODE to instruct the reporting routine that it
634
// indicates that the repair symbol should be inserted before
635
// the error token.
636
//
637
if (repair.code == INSERTION_CODE) {
638             if (buffer[repair.bufferPosition - 1] == 0) {
639                 repair.code = BEFORE_CODE;
640             }
641         }
642
643         //
644
// Select the proper sequence of states on which to recover,
645
// update stack accordingly and call diagnostic routine.
646
//
647
if (repair.bufferPosition == 1) {
648             stateStackTop = prevStackTop;
649             for (int j = 0; j <= stateStackTop; j++) {
650                 stack[j] = prevStack[j];
651             }
652         } else if (nextStackTop >= 0 && repair.bufferPosition >= 3) {
653             stateStackTop = nextStackTop;
654             for (int j = 0; j <= stateStackTop; j++) {
655                 stack[j] = nextStack[j];
656             }
657             locationStack[stateStackTop] = buffer[3];
658             locationStartStack[stateStackTop] = lexStream.start(buffer[3]);
659         }
660
661         return primaryDiagnosis(repair);
662     }
663
664
665 //
666
// This function checks whether or not a given state has a
667
// candidate, whose string representaion is a merging of the two
668
// tokens at positions buffer_position and buffer_position+1 in
669
// the buffer. If so, it returns the candidate in question;
670
// otherwise it returns 0.
671
//
672
private int mergeCandidate(int state, int buffer_position) {
673         char[] name1 = lexStream.name(buffer[buffer_position]);
674         char[] name2 = lexStream.name(buffer[buffer_position + 1]);
675         
676         int len = name1.length + name2.length;
677
678         char[] str = CharOperation.concat(name1, name2);
679
680         for (int k = Parser.asi(state); Parser.asr[k] != 0; k++) {
681             int l = Parser.terminal_index[Parser.asr[k]];
682
683             if (len == Parser.name[l].length()) {
684                 char[] name = Parser.name[l].toCharArray();
685
686                 if (CharOperation.equals(str, name, false)) {
687                     return Parser.asr[k];
688                 }
689             }
690         }
691
692         return 0;
693     }
694
695
696 //
697
// This procedure takes as arguments a parsing configuration
698
// consisting of a state stack (stack and stack_top) and a fixed
699
// number of input tokens (starting at buffer_position) in the
700
// input BUFFER; and some reference arguments: repair_code,
701
// distance, misspell_index, candidate, and stack_position
702
// which it sets based on the best possible recovery that it
703
// finds in the given configuration. The effectiveness of a
704
// a repair is judged based on two criteria:
705
//
706
// 1) the number of tokens that can be parsed after the repair
707
// is applied: distance.
708
// 2) how close to perfection is the candidate that is chosen:
709
// misspell_index.
710
// When this procedure is entered, distance, misspell_index and
711
// repair_code are assumed to be initialized.
712
//
713
private PrimaryRepairInfo checkPrimaryDistance(int stck[], int stack_top, PrimaryRepairInfo repair) {
714         int i, j, k, next_state, max_pos, act, root, symbol, tok;
715
716         //
717
// First, try scope and manual recovery.
718
//
719
PrimaryRepairInfo scope_repair = scopeTrial(stck, stack_top, repair.copy());
720         if (scope_repair.distance > repair.distance)
721             repair = scope_repair;
722             
723         //
724
// Next, try merging the error token with its successor.
725
//
726
if(buffer[repair.bufferPosition] != 0 && buffer[repair.bufferPosition + 1] != 0) {// do not merge the first token
727
symbol = mergeCandidate(stck[stack_top], repair.bufferPosition);
728             if (symbol != 0) {
729                 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+2);
730                 if ((j > repair.distance) || (j == repair.distance && repair.misspellIndex < 10)) {
731                     repair.misspellIndex = 10;
732                     repair.symbol = symbol;
733                     repair.distance = j;
734                     repair.code = MERGE_CODE;
735                 }
736             }
737         }
738
739         //
740
// Next, try deletion of the error token.
741
//
742
j = parseCheck(
743                 stck,
744                 stack_top,
745                 lexStream.kind(buffer[repair.bufferPosition + 1]),
746                 repair.bufferPosition + 2);
747         if (lexStream.kind(buffer[repair.bufferPosition]) == EOLT_SYMBOL &&
748             lexStream.afterEol(buffer[repair.bufferPosition+1])) {
749              k = 10;
750         } else {
751             k = 0;
752         }
753         if (j > repair.distance || (j == repair.distance && k > repair.misspellIndex)) {
754             repair.misspellIndex = k;
755             repair.code = DELETION_CODE;
756             repair.distance = j;
757         }
758
759         //
760
// Update the error configuration by simulating all reduce and
761
// goto actions induced by the error token. Then assign the top
762
// most state of the new configuration to next_state.
763
//
764
next_state = stck[stack_top];
765         max_pos = stack_top;
766         tempStackTop = stack_top - 1;
767
768         tok = lexStream.kind(buffer[repair.bufferPosition]);
769         lexStream.reset(buffer[repair.bufferPosition + 1]);
770         act = Parser.tAction(next_state, tok);
771         while(act <= NUM_RULES) {
772             do {
773                 tempStackTop -= (Parser.rhs[act]-1);
774                 symbol = Parser.lhs[act];
775                 act = (tempStackTop > max_pos
776                                       ? tempStack[tempStackTop]
777                                       : stck[tempStackTop]);
778                 act = Parser.ntAction(act, symbol);
779             } while(act <= NUM_RULES);
780             max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
781             tempStack[tempStackTop + 1] = act;
782             next_state = act;
783             act = Parser.tAction(next_state, tok);
784         }
785
786         //
787
// Next, place the list of candidates in proper order.
788
//
789
root = 0;
790         for (i = Parser.asi(next_state); Parser.asr[i] != 0; i++) {
791             symbol = Parser.asr[i];
792             if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL) {
793                 if (root == 0) {
794                     list[symbol] = symbol;
795                 } else {
796                     list[symbol] = list[root];
797                     list[root] = symbol;
798                 }
799                 root = symbol;
800             }
801         }
802
803         if (stck[stack_top] != next_state) {
804             for (i = Parser.asi(stck[stack_top]); Parser.asr[i] != 0; i++) {
805                 symbol = Parser.asr[i];
806                 if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL && list[symbol] == 0) {
807                     if (root == 0) {
808                         list[symbol] = symbol;
809                     } else {
810                         list[symbol] = list[root];
811                         list[root] = symbol;
812                     }
813                     root = symbol;
814                 }
815             }
816         }
817
818         i = list[root];
819         list[root] = 0;
820         root = i;
821
822         //
823
// Next, try insertion for each possible candidate available in
824
// the current state, except EOFT and ERROR_SYMBOL.
825
//
826
symbol = root;
827         while(symbol != 0) {
828             if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition])) {
829                 k = 10;
830             } else {
831                 k = 0;
832             }
833             j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
834             if (j > repair.distance) {
835                 repair.misspellIndex = k;
836                 repair.distance = j;
837                 repair.symbol = symbol;
838                 repair.code = INSERTION_CODE;
839             } else if (j == repair.distance && k > repair.misspellIndex) {
840                 repair.misspellIndex = k;
841                 repair.distance = j;
842                 repair.symbol = symbol;
843                 repair.code = INSERTION_CODE;
844             } else if (j == repair.distance && k == repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
845                 repair.misspellIndex = k;
846                 repair.distance = j;
847                 repair.symbol = symbol;
848                 repair.code = INSERTION_CODE;
849             }
850
851             symbol = list[symbol];
852         }
853
854         //
855
// Next, Try substitution for each possible candidate available
856
// in the current state, except EOFT and ERROR_SYMBOL.
857
//
858
symbol = root;
859         
860         if(buffer[repair.bufferPosition] != 0) {// do not replace the first token
861
while(symbol != 0) {
862                 if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition+1])) {
863                     k = 10;
864                 } else {
865                     k = misspell(symbol, buffer[repair.bufferPosition]);
866                 }
867                 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
868                 if (j > repair.distance) {
869                     repair.misspellIndex = k;
870                     repair.distance = j;
871                     repair.symbol = symbol;
872                     repair.code = SUBSTITUTION_CODE;
873                 } else if (j == repair.distance && k > repair.misspellIndex) {
874                     repair.misspellIndex = k;
875                     repair.symbol = symbol;
876                     repair.code = SUBSTITUTION_CODE;
877                 } else if (j == repair.distance && k > repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
878                     repair.misspellIndex = k;
879                     repair.symbol = symbol;
880                     repair.code = SUBSTITUTION_CODE;
881                 }
882                 i = symbol;
883                 symbol = list[symbol];
884                 list[i] = 0; // reset element
885
}
886         }
887
888
889         //
890
// Next, we try to insert a nonterminal candidate in front of the
891
// error token, or substituting a nonterminal candidate for the
892
// error token. Precedence is given to insertion.
893
//
894
for (i = Parser.nasi(stck[stack_top]); Parser.nasr[i] != 0; i++) {
895              symbol = Parser.nasr[i] + NT_OFFSET;
896              j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
897              if (j > repair.distance) {
898                  repair.misspellIndex = 0;
899                  repair.distance = j;
900                  repair.symbol = symbol;
901                  repair.code = INVALID_CODE;
902              }
903
904              j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
905              if ((j > repair.distance) || (j == repair.distance && repair.code == INVALID_CODE)) {
906                  repair.misspellIndex = 0;
907                  repair.distance = j;
908                  repair.symbol = symbol;
909                  repair.code = INSERTION_CODE;
910              }
911          }
912
913         return repair;
914     }
915
916
917 //
918
// This procedure is invoked to issue a diagnostic message and
919
// adjust the input buffer. The recovery in question is either
920
// the insertion of one or more scopes, the merging of the error
921
// token with its successor, the deletion of the error token,
922
// the insertion of a single token in front of the error token
923
// or the substitution of another token for the error token.
924
//
925
private RepairCandidate primaryDiagnosis(PrimaryRepairInfo repair) {
926         int name_index;
927
928         //
929
// Issue diagnostic.
930
//
931
int prevtok = buffer[repair.bufferPosition - 1];
932         int curtok = buffer[repair.bufferPosition];
933
934         switch(repair.code) {
935             case INSERTION_CODE:
936             case BEFORE_CODE: {
937                 if (repair.symbol > NT_OFFSET)
938                      name_index = getNtermIndex(stack[stateStackTop],
939                                                 repair.symbol,
940                                                 repair.bufferPosition);
941                 else name_index = getTermIndex(stack,
942                                                stateStackTop,
943                                                repair.symbol,
944                                                repair.bufferPosition);
945
946                 int t = (repair.code == INSERTION_CODE ? prevtok : curtok);
947                 reportError(repair.code, name_index, t, t);
948                 break;
949             }
950             case INVALID_CODE: {
951                 name_index = getNtermIndex(stack[stateStackTop],
952                                            repair.symbol,
953                                            repair.bufferPosition + 1);
954                 reportError(repair.code, name_index, curtok, curtok);
955                 break;
956             }
957             case SUBSTITUTION_CODE: {
958                 if (repair.misspellIndex >= 6)
959                     name_index = Parser.terminal_index[repair.symbol];
960                 else
961                 {
962                     name_index = getTermIndex(stack, stateStackTop,
963                                               repair.symbol,
964                                               repair.bufferPosition + 1);
965                     if (name_index != Parser.terminal_index[repair.symbol])
966                         repair.code = INVALID_CODE;
967                 }
968                 reportError(repair.code, name_index, curtok, curtok);
969                 break;
970             }
971             case MERGE_CODE: {
972                 reportError(repair.code,
973                              Parser.terminal_index[repair.symbol],
974                              curtok,
975                              lexStream.next(curtok));
976                 break;
977             }
978             case SCOPE_CODE: {
979                 for (int i = 0; i < scopeStackTop; i++) {
980                     reportError(repair.code,
981                                 -scopeIndex[i],
982                                 locationStack[scopePosition[i]],
983                                 prevtok,
984                                 Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
985                 }
986     
987                 repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
988                 stateStackTop = scopePosition[scopeStackTop];
989                 reportError(repair.code,
990                             -scopeIndex[scopeStackTop],
991                             locationStack[scopePosition[scopeStackTop]],
992                             prevtok,
993                             getNtermIndex(stack[stateStackTop],
994                                           repair.symbol,
995                                           repair.bufferPosition)
996                            );
997                 break;
998             }
999             default: {// deletion
1000
reportError(repair.code, Parser.terminal_index[ERROR_SYMBOL], curtok, curtok);
1001            }
1002        }
1003
1004        //
1005
// Update buffer.
1006
//
1007
RepairCandidate candidate = new RepairCandidate();
1008        switch (repair.code) {
1009            case INSERTION_CODE:
1010            case BEFORE_CODE:
1011            case SCOPE_CODE: {
1012                candidate.symbol = repair.symbol;
1013                candidate.location = buffer[repair.bufferPosition];
1014                lexStream.reset(buffer[repair.bufferPosition]);
1015                break;
1016            }
1017            case INVALID_CODE:
1018            case SUBSTITUTION_CODE: {
1019                candidate.symbol = repair.symbol;
1020                candidate.location = buffer[repair.bufferPosition];
1021                lexStream.reset(buffer[repair.bufferPosition + 1]);
1022                break;
1023            }
1024            case MERGE_CODE: {
1025                candidate.symbol = repair.symbol;
1026                candidate.location = buffer[repair.bufferPosition];
1027                lexStream.reset(buffer[repair.bufferPosition + 2]);
1028                break;
1029            }
1030            default: {// deletion
1031
candidate.location = buffer[repair.bufferPosition + 1];
1032                candidate.symbol =
1033                          lexStream.kind(buffer[repair.bufferPosition + 1]);
1034                lexStream.reset(buffer[repair.bufferPosition + 2]);
1035                break;
1036            }
1037        }
1038
1039        return candidate;
1040    }
1041
1042
1043//
1044
// This function takes as parameter an integer STACK_TOP that
1045
// points to a STACK element containing the state on which a
1046
// primary recovery will be made; the terminal candidate on which
1047
// to recover; and an integer: buffer_position, which points to
1048
// the position of the next input token in the BUFFER. The
1049
// parser is simulated until a shift (or shift-reduce) action
1050
// is computed on the candidate. Then we proceed to compute the
1051
// the name index of the highest level nonterminal that can
1052
// directly or indirectly produce the candidate.
1053
//
1054
private int getTermIndex(int stck[], int stack_top, int tok, int buffer_position) {
1055        //
1056
// Initialize stack index of temp_stack and initialize maximum
1057
// position of state stack that is still useful.
1058
//
1059
int act = stck[stack_top],
1060            max_pos = stack_top,
1061            highest_symbol = tok;
1062
1063        tempStackTop = stack_top - 1;
1064
1065        //
1066
// Compute all reduce and associated actions induced by the
1067
// candidate until a SHIFT or SHIFT-REDUCE is computed. ERROR
1068
// and ACCEPT actions cannot be computed on the candidate in
1069
// this context, since we know that it is suitable for recovery.
1070
//
1071
lexStream.reset(buffer[buffer_position]);
1072        act = Parser.tAction(act, tok);
1073        while(act <= NUM_RULES) {
1074            //
1075
// Process all goto-reduce actions following reduction,
1076
// until a goto action is computed ...
1077
//
1078
do {
1079                tempStackTop -= (Parser.rhs[act]-1);
1080                int lhs_symbol = Parser.lhs[act];
1081                act = (tempStackTop > max_pos
1082                                      ? tempStack[tempStackTop]
1083                                      : stck[tempStackTop]);
1084                act = Parser.ntAction(act, lhs_symbol);
1085            } while(act <= NUM_RULES);
1086
1087            //
1088
// Compute new maximum useful position of (STATE_)stack,
1089
// push goto state into the stack, and compute next
1090
// action on candidate ...
1091
//
1092
max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1093            tempStack[tempStackTop + 1] = act;
1094            act = Parser.tAction(act, tok);
1095        }
1096
1097        //
1098
// At this stage, we have simulated all actions induced by the
1099
// candidate and we are ready to shift or shift-reduce it. First,
1100
// set tok and next_ptr appropriately and identify the candidate
1101
// as the initial highest_symbol. If a shift action was computed
1102
// on the candidate, update the stack and compute the next
1103
// action. Next, simulate all actions possible on the next input
1104
// token until we either have to shift it or are about to reduce
1105
// below the initial starting point in the stack (indicated by
1106
// max_pos as computed in the previous loop). At that point,
1107
// return the highest_symbol computed.
1108
//
1109
tempStackTop++; // adjust top of stack to reflect last goto
1110
// next move is shift or shift-reduce.
1111
int threshold = tempStackTop;
1112
1113        tok = lexStream.kind(buffer[buffer_position]);
1114        lexStream.reset(buffer[buffer_position + 1]);
1115
1116        if (act > ERROR_ACTION) { // shift-reduce on candidate?
1117
act -= ERROR_ACTION;
1118        } else {
1119            tempStack[tempStackTop + 1] = act;
1120            act = Parser.tAction(act, tok);
1121        }
1122
1123        while(act <= NUM_RULES) {
1124            //
1125
// Process all goto-reduce actions following reduction,
1126
// until a goto action is computed ...
1127
//
1128
do {
1129                tempStackTop -= (Parser.rhs[act]-1);
1130
1131                if (tempStackTop < threshold) {
1132                    return (highest_symbol > NT_OFFSET
1133                         ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1134                         : Parser.terminal_index[highest_symbol]);
1135                }
1136
1137                int lhs_symbol = Parser.lhs[act];
1138                if (tempStackTop == threshold)
1139                    highest_symbol = lhs_symbol + NT_OFFSET;
1140                act = (tempStackTop > max_pos
1141                                      ? tempStack[tempStackTop]
1142                                      : stck[tempStackTop]);
1143                act = Parser.ntAction(act, lhs_symbol);
1144            } while(act <= NUM_RULES);
1145
1146            tempStack[tempStackTop + 1] = act;
1147            act = Parser.tAction(act, tok);
1148        }
1149
1150        return (highest_symbol > NT_OFFSET
1151                             ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1152                             : Parser.terminal_index[highest_symbol]);
1153    }
1154
1155//
1156
// This function takes as parameter a starting state number:
1157
// start, a nonterminal symbol, A (candidate), and an integer,
1158
// buffer_position, which points to the position of the next
1159
// input token in the BUFFER.
1160
// It returns the highest level non-terminal B such that
1161
// B =>*rm A. I.e., there does not exists a nonterminal C such
1162
// that C =>+rm B. (Recall that for an LALR(k) grammar if
1163
// C =>+rm B, it cannot be the case that B =>+rm C)
1164
//
1165
private int getNtermIndex(int start, int sym, int buffer_position) {
1166        int highest_symbol = sym - NT_OFFSET,
1167            tok = lexStream.kind(buffer[buffer_position]);
1168        lexStream.reset(buffer[buffer_position + 1]);
1169
1170        //
1171
// Initialize stack index of temp_stack and initialize maximum
1172
// position of state stack that is still useful.
1173
//
1174
tempStackTop = 0;
1175        tempStack[tempStackTop] = start;
1176
1177        int act = Parser.ntAction(start, highest_symbol);
1178        if (act > NUM_RULES) { // goto action?
1179
tempStack[tempStackTop + 1] = act;
1180            act = Parser.tAction(act, tok);
1181        }
1182
1183        while(act <= NUM_RULES) {
1184            //
1185
// Process all goto-reduce actions following reduction,
1186
// until a goto action is computed ...
1187
//
1188
do {
1189                tempStackTop -= (Parser.rhs[act]-1);
1190                if (tempStackTop < 0)
1191                    return Parser.non_terminal_index[highest_symbol];
1192                if (tempStackTop == 0)
1193                    highest_symbol = Parser.lhs[act];
1194                act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
1195            } while(act <= NUM_RULES);
1196            tempStack[tempStackTop + 1] = act;
1197            act = Parser.tAction(act, tok);
1198        }
1199
1200        return Parser.non_terminal_index[highest_symbol];
1201    }
1202
1203    private boolean isBetterSymbol(int symbol, int actualSymbol) {
1204// switch (actualSymbol) {
1205
// case TokenNameinterface :
1206
// if(symbol == TokenNameclass) {
1207
// return true;
1208
// }
1209
// break;
1210
// }
1211
return false;
1212    }
1213
1214//
1215
// Check whether or not there is a high probability that a
1216
// given string is a misspelling of another.
1217
// Certain singleton symbols (such as ":" and ";") are also
1218
// considered to be misspelling of each other.
1219
//
1220
private int misspell(int sym, int tok) {
1221        
1222
1223        //
1224
//
1225
//
1226
char[] name = Parser.name[Parser.terminal_index[sym]].toCharArray();
1227        int n = name.length;
1228        char[] s1 = new char[n + 1];
1229        for (int k = 0; k < n; k++) {
1230            char c = name[k];
1231            s1[k] = ScannerHelper.toLowerCase(c);
1232        }
1233        s1[n] = '\0';
1234
1235        //
1236
//
1237
//
1238
char[] tokenName = lexStream.name(tok);
1239        int len = tokenName.length;
1240        int m = len < MAX_NAME_LENGTH ? len : MAX_NAME_LENGTH;
1241        char[] s2 = new char[m + 1];
1242        for (int k = 0; k < m; k++) {
1243            char c = tokenName[k];
1244            s2[k] = ScannerHelper.toLowerCase(c);
1245        }
1246        s2[m] = '\0';
1247
1248        //
1249
// Singleton mispellings:
1250
//
1251
// ; <----> ,
1252
//
1253
// ; <----> :
1254
//
1255
// . <----> ,
1256
//
1257
// ' <----> "
1258
//
1259
//
1260
if (n == 1 && m == 1) {
1261            if ((s1[0] == ';' && s2[0] == ',') ||
1262                (s1[0] == ',' && s2[0] == ';') ||
1263                (s1[0] == ';' && s2[0] == ':') ||
1264                (s1[0] == ':' && s2[0] == ';') ||
1265                (s1[0] == '.' && s2[0] == ',') ||
1266                (s1[0] == ',' && s2[0] == '.') ||
1267                (s1[0] == '\'' && s2[0] == '\"') ||
1268                (s1[0] == '\"' && s2[0] == '\'')) {
1269                    return 3;
1270            }
1271        }
1272
1273        //
1274
// Scan the two strings. Increment "match" count for each match.
1275
// When a transposition is encountered, increase "match" count
1276
// by two but count it as an error. When a typo is found, skip
1277
// it and count it as an error. Otherwise we have a mismatch; if
1278
// one of the strings is longer, increment its index, otherwise,
1279
// increment both indices and continue.
1280
//
1281
// This algorithm is an adaptation of a boolean misspelling
1282
// algorithm proposed by Juergen Uhl.
1283
//
1284
int count = 0;
1285        int prefix_length = 0;
1286        int num_errors = 0;
1287
1288        int i = 0;
1289        int j = 0;
1290        while ((i < n) && (j < m)) {
1291            if (s1[i] == s2[j]) {
1292                count++;
1293                i++;
1294                j++;
1295                if (num_errors == 0) {
1296                    prefix_length++;
1297                }
1298            } else if (s1[i+1] == s2[j] && s1[i] == s2[j+1]) {
1299                count += 2;
1300                i += 2;
1301                j += 2;
1302                num_errors++;
1303            } else if (s1[i+1] == s2[j+1]) {
1304                i++;
1305                j++;
1306                num_errors++;
1307            } else {
1308                if ((n - i) > (m - j)) {
1309                     i++;
1310                } else if ((m - j) > (n - i)) {
1311                     j++;
1312                } else {
1313                    i++;
1314                    j++;
1315                }
1316                num_errors++;
1317            }
1318        }
1319
1320        if (i < n || j < m)
1321            num_errors++;
1322
1323        if (num_errors > ((n < m ? n : m) / 6 + 1))
1324             count = prefix_length;
1325
1326        return(count * 10 / ((n < len ? len : n) + num_errors));
1327    }
1328    
1329    private PrimaryRepairInfo scopeTrial(int stck[], int stack_top, PrimaryRepairInfo repair) {
1330        stateSeen = new int[stackLength];
1331        for (int i = 0; i < stackLength; i++)
1332            stateSeen[i] = NIL;
1333        
1334        statePoolTop = 0;
1335        statePool = new StateInfo[stackLength];
1336    
1337        scopeTrialCheck(stck, stack_top, repair, 0);
1338    
1339        stateSeen = null;
1340        statePoolTop = 0;
1341    
1342        repair.code = SCOPE_CODE;
1343        repair.misspellIndex = 10;
1344    
1345        return repair;
1346    }
1347    
1348    private void scopeTrialCheck(int stck[], int stack_top, PrimaryRepairInfo repair, int indx) {
1349        if(indx > 20) return; // avoid too much recursive call to improve performance
1350

1351        int act = stck[stack_top];
1352    
1353        for (int i = stateSeen[stack_top]; i != NIL; i = statePool[i].next) {
1354            if (statePool[i].state == act) return;
1355        }
1356
1357        int old_state_pool_top = statePoolTop++;
1358        if(statePoolTop >= statePool.length) {
1359            System.arraycopy(statePool, 0, statePool = new StateInfo[statePoolTop * 2], 0, statePoolTop);
1360        }
1361        
1362        statePool[old_state_pool_top] = new StateInfo(act, stateSeen[stack_top]);
1363        stateSeen[stack_top] = old_state_pool_top;
1364    
1365        next : for (int i = 0; i < SCOPE_SIZE; i++) {
1366            //
1367
// Use the scope lookahead symbol to force all reductions
1368
// inducible by that symbol.
1369
//
1370
act = stck[stack_top];
1371            tempStackTop = stack_top - 1;
1372            int max_pos = stack_top;
1373            int tok = Parser.scope_la[i];
1374            lexStream.reset(buffer[repair.bufferPosition]);
1375            act = Parser.tAction(act, tok);
1376            while(act <= NUM_RULES) {
1377                //
1378
// ... Process all goto-reduce actions following
1379
// reduction, until a goto action is computed ...
1380
//
1381
do {
1382                    tempStackTop -= (Parser.rhs[act]-1);
1383                    int lhs_symbol = Parser.lhs[act];
1384                    act = (tempStackTop > max_pos
1385                                ? tempStack[tempStackTop]
1386                                : stck[tempStackTop]);
1387                    act = Parser.ntAction(act, lhs_symbol);
1388                } while(act <= NUM_RULES);
1389                if (tempStackTop + 1 >= stackLength)
1390                    return;
1391                max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1392                tempStack[tempStackTop + 1] = act;
1393                act = Parser.tAction(act, tok);
1394            }
1395    
1396            //
1397
// If the lookahead symbol is parsable, then we check
1398
// whether or not we have a match between the scope
1399
// prefix and the transition symbols corresponding to
1400
// the states on top of the stack.
1401
//
1402
if (act != ERROR_ACTION) {
1403                int j, k;
1404                k = Parser.scope_prefix[i];
1405                for (j = tempStackTop + 1;
1406                     j >= (max_pos + 1) &&
1407                     Parser.in_symbol(tempStack[j]) == Parser.scope_rhs[k]; j--) {
1408                     k++;
1409                }
1410                if (j == max_pos) {
1411                    for (j = max_pos;
1412                         j >= 1 && Parser.in_symbol(stck[j]) == Parser.scope_rhs[k];
1413                         j--) {
1414                        k++;
1415                    }
1416                }
1417                //
1418
// If the prefix matches, check whether the state
1419
// newly exposed on top of the stack, (after the
1420
// corresponding prefix states are popped from the
1421
// stack), is in the set of "source states" for the
1422
// scope in question and that it is at a position
1423
// below the threshold indicated by MARKED_POS.
1424
//
1425
int marked_pos = (max_pos < stack_top ? max_pos + 1 : stack_top);
1426                if (Parser.scope_rhs[k] == 0 && j < marked_pos) { // match?
1427
int stack_position = j;
1428                    for (j = Parser.scope_state_set[i];
1429                         stck[stack_position] != Parser.scope_state[j] &&
1430                         Parser.scope_state[j] != 0;
1431                         j++){/*empty*/}
1432                    //
1433
// If the top state is valid for scope recovery,
1434
// the left-hand side of the scope is used as
1435
// starting symbol and we calculate how far the
1436
// parser can advance within the forward context
1437
// after parsing the left-hand symbol.
1438
//
1439
if (Parser.scope_state[j] != 0) { // state was found
1440
int previous_distance = repair.distance;
1441                        int distance = parseCheck(stck,
1442                                              stack_position,
1443                                              Parser.scope_lhs[i]+NT_OFFSET,
1444                                              repair.bufferPosition);
1445                        //
1446
// if the recovery is not successful, we
1447
// update the stack with all actions induced
1448
// by the left-hand symbol, and recursively
1449
// call SCOPE_TRIAL_CHECK to try again.
1450
// Otherwise, the recovery is successful. If
1451
// the new distance is greater than the
1452
// initial SCOPE_DISTANCE, we update
1453
// SCOPE_DISTANCE and set scope_stack_top to INDX
1454
// to indicate the number of scopes that are
1455
// to be applied for a succesful recovery.
1456
// NOTE that this procedure cannot get into
1457
// an infinite loop, since each prefix match
1458
// is guaranteed to take us to a lower point
1459
// within the stack.
1460
//
1461
if ((distance - repair.bufferPosition + 1) < MIN_DISTANCE) {
1462                            int top = stack_position;
1463                            act = Parser.ntAction(stck[top], Parser.scope_lhs[i]);
1464                            while(act <= NUM_RULES) {
1465                                if(Parser.rules_compliance[act] > this.options.sourceLevel) {
1466                                    continue next;
1467                                }
1468                                top -= (Parser.rhs[act]-1);
1469                                act = Parser.ntAction(stck[top], Parser.lhs[act]);
1470                            }
1471                            top++;
1472    
1473                            j = act;
1474                            act = stck[top]; // save
1475
stck[top] = j; // swap
1476
scopeTrialCheck(stck, top, repair, indx+1);
1477                            stck[top] = act; // restore
1478
} else if (distance > repair.distance) {
1479                            scopeStackTop = indx;
1480                            repair.distance = distance;
1481                        }
1482    
1483                        if (lexStream.kind(buffer[repair.bufferPosition]) == EOFT_SYMBOL &&
1484                            repair.distance == previous_distance) {
1485                            scopeStackTop = indx;
1486                            repair.distance = MAX_DISTANCE;
1487                        }
1488    
1489                        //
1490
// If this scope recovery has beaten the
1491
// previous distance, then we have found a
1492
// better recovery (or this recovery is one
1493
// of a list of scope recoveries). Record
1494
// its information at the proper location
1495
// (INDX) in SCOPE_INDEX and SCOPE_STACK.
1496
//
1497
if (repair.distance > previous_distance) {
1498                            scopeIndex[indx] = i;
1499                            scopePosition[indx] = stack_position;
1500                            return;
1501                        }
1502                    }
1503                }
1504            }
1505        }
1506    }
1507//
1508
// This function computes the ParseCheck distance for the best
1509
// possible secondary recovery for a given configuration that
1510
// either deletes none or only one symbol in the forward context.
1511
// If the recovery found is more effective than the best primary
1512
// recovery previously computed, then the function returns true.
1513
// Only misplacement, scope and manual recoveries are attempted;
1514
// simple insertion or substitution of a nonterminal are tried
1515
// in CHECK_PRIMARY_DISTANCE as part of primary recovery.
1516
//
1517
private boolean secondaryCheck(int stck[], int stack_top, int buffer_position, int distance) {
1518        int top, j;
1519
1520        for (top = stack_top - 1; top >= 0; top--) {
1521            j = parseCheck(stck, top,
1522                           lexStream.kind(buffer[buffer_position]),
1523                           buffer_position + 1);
1524            if (((j - buffer_position + 1) > MIN_DISTANCE) && (j > distance))
1525                return true;
1526        }
1527        
1528        PrimaryRepairInfo repair = new PrimaryRepairInfo();
1529        repair.bufferPosition = buffer_position + 1;
1530        repair.distance = distance;
1531        repair = scopeTrial(stck, stack_top, repair);
1532        if ((repair.distance - buffer_position) > MIN_DISTANCE && repair.distance > distance)
1533             return true;
1534        return false;
1535    }
1536
1537
1538//
1539
// Secondary_phase is a boolean function that checks whether or
1540
// not some form of secondary recovery is applicable to one of
1541
// the error configurations. First, if "next_stack" is available,
1542
// misplacement and secondary recoveries are attempted on it.
1543
// Then, in any case, these recoveries are attempted on "stack".
1544
// If a successful recovery is found, a diagnosis is issued, the
1545
// configuration is updated and the function returns "true".
1546
// Otherwise, the function returns false.
1547
//
1548
private RepairCandidate secondaryPhase(int error_token) {
1549        SecondaryRepairInfo repair = new SecondaryRepairInfo();
1550        SecondaryRepairInfo misplaced = new SecondaryRepairInfo();
1551
1552        RepairCandidate candidate = new RepairCandidate();
1553
1554        int i, j, k, top;
1555        int next_last_index = 0;
1556        int last_index;
1557
1558        candidate.symbol = 0;
1559
1560        repair.code = 0;
1561        repair.distance = 0;
1562        repair.recoveryOnNextStack = false;
1563
1564        misplaced.distance = 0;
1565        misplaced.recoveryOnNextStack = false;
1566
1567        //
1568
// If the next_stack is available, try misplaced and secondary
1569
// recovery on it first.
1570
//
1571
if (nextStackTop >= 0) {
1572            int save_location;
1573
1574            buffer[2] = error_token;
1575            buffer[1] = lexStream.previous(buffer[2]);
1576            buffer[0] = lexStream.previous(buffer[1]);
1577
1578            for (k = 3; k < BUFF_UBOUND; k++)
1579                buffer[k] = lexStream.next(buffer[k - 1]);
1580
1581            buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1582

1583            //
1584
// If we are at the end of the input stream, compute the
1585
// index position of the first EOFT symbol (last useful
1586
// index).
1587
//
1588
for (next_last_index = MAX_DISTANCE - 1;
1589                 next_last_index >= 1 &&
1590                 lexStream.kind(buffer[next_last_index]) == EOFT_SYMBOL;
1591                 next_last_index--){/*empty*/}
1592            next_last_index = next_last_index + 1;
1593
1594            save_location = locationStack[nextStackTop];
1595            int save_location_start = locationStartStack[nextStackTop];
1596            locationStack[nextStackTop] = buffer[2];
1597            locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1598            misplaced.numDeletions = nextStackTop;
1599            misplaced = misplacementRecovery(nextStack, nextStackTop,
1600                                             next_last_index,
1601                                             misplaced, true);
1602            if (misplaced.recoveryOnNextStack)
1603                misplaced.distance++;
1604
1605            repair.numDeletions = nextStackTop + BUFF_UBOUND;
1606            repair = secondaryRecovery(nextStack, nextStackTop,
1607                                       next_last_index,
1608                                       repair, true);
1609            if (repair.recoveryOnNextStack)
1610                repair.distance++;
1611
1612            locationStack[nextStackTop] = save_location;
1613            locationStartStack[nextStackTop] = save_location_start;
1614        } else { // next_stack not available, initialize ...
1615
misplaced.numDeletions = stateStackTop;
1616            repair.numDeletions = stateStackTop + BUFF_UBOUND;
1617        }
1618
1619        //
1620
// Try secondary recovery on the "stack" configuration.
1621
//
1622
buffer[3] = error_token;
1623
1624        buffer[2] = lexStream.previous(buffer[3]);
1625        buffer[1] = lexStream.previous(buffer[2]);
1626        buffer[0] = lexStream.previous(buffer[1]);
1627
1628        for (k = 4; k < BUFF_SIZE; k++)
1629            buffer[k] = lexStream.next(buffer[k - 1]);
1630
1631        for (last_index = MAX_DISTANCE - 1;
1632             last_index >= 1 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL;
1633             last_index--){/*empty*/}
1634        last_index++;
1635
1636        misplaced = misplacementRecovery(stack, stateStackTop,
1637                                         last_index,
1638                                         misplaced, false);
1639
1640        repair = secondaryRecovery(stack, stateStackTop,
1641                                   last_index, repair, false);
1642
1643        //
1644
// If a successful misplaced recovery was found, compare it with
1645
// the most successful secondary recovery. If the misplaced
1646
// recovery either deletes fewer symbols or parse-checks further
1647
// then it is chosen.
1648
//
1649
if (misplaced.distance > MIN_DISTANCE) {
1650            if (misplaced.numDeletions <= repair.numDeletions ||
1651               (misplaced.distance - misplaced.numDeletions) >=
1652               (repair.distance - repair.numDeletions)) {
1653                repair.code = MISPLACED_CODE;
1654                repair.stackPosition = misplaced.stackPosition;
1655                repair.bufferPosition = 2;
1656                repair.numDeletions = misplaced.numDeletions;
1657                repair.distance = misplaced.distance;
1658                repair.recoveryOnNextStack = misplaced.recoveryOnNextStack;
1659            }
1660        }
1661
1662        //
1663
// If the successful recovery was on next_stack, update: stack,
1664
// buffer, location_stack and last_index.
1665
//
1666
if (repair.recoveryOnNextStack) {
1667            stateStackTop = nextStackTop;
1668            for (i = 0; i <= stateStackTop; i++)
1669                stack[i] = nextStack[i];
1670
1671            buffer[2] = error_token;
1672            buffer[1] = lexStream.previous(buffer[2]);
1673            buffer[0] = lexStream.previous(buffer[1]);
1674
1675            for (k = 3; k < BUFF_UBOUND; k++)
1676                buffer[k] = lexStream.next(buffer[k - 1]);
1677
1678            buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1679

1680            locationStack[nextStackTop] = buffer[2];
1681            locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1682            last_index = next_last_index;
1683        }
1684
1685        //
1686
// Next, try scope recoveries after deletion of one, two, three,
1687
// four ... buffer_position tokens from the input stream.
1688
//
1689
if (repair.code == SECONDARY_CODE || repair.code == DELETION_CODE) {
1690            PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1691    
1692            scope_repair.distance = 0;
1693            for (scope_repair.bufferPosition = 2;
1694                 scope_repair.bufferPosition <= repair.bufferPosition &&
1695                 repair.code != SCOPE_CODE; scope_repair.bufferPosition++) {
1696                scope_repair = scopeTrial(stack, stateStackTop, scope_repair);
1697                j = (scope_repair.distance == MAX_DISTANCE
1698                                            ? last_index
1699                                            : scope_repair.distance);
1700                k = scope_repair.bufferPosition - 1;
1701                if ((j - k) > MIN_DISTANCE && (j - k) > (repair.distance - repair.numDeletions)) {
1702                    repair.code = SCOPE_CODE;
1703                    i = scopeIndex[scopeStackTop]; // upper bound
1704
repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1705                    repair.stackPosition = stateStackTop;
1706                    repair.bufferPosition = scope_repair.bufferPosition;
1707                }
1708            }
1709        }
1710    
1711        //
1712
// If no successful recovery is found and we have reached the
1713
// end of the file, check whether or not scope recovery is
1714
// applicable at the end of the file after discarding some
1715
// states.
1716
//
1717
if (repair.code == 0 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL) {
1718            PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1719    
1720            scope_repair.bufferPosition = last_index;
1721            scope_repair.distance = 0;
1722            for (top = stateStackTop;
1723                 top >= 0 && repair.code == 0; top--)
1724            {
1725                scope_repair = scopeTrial(stack, top, scope_repair);
1726                if (scope_repair.distance > 0)
1727                {
1728                    repair.code = SCOPE_CODE;
1729                    i = scopeIndex[scopeStackTop]; // upper bound
1730
repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1731                    repair.stackPosition = top;
1732                    repair.bufferPosition = scope_repair.bufferPosition;
1733                }
1734            }
1735        }
1736
1737        //
1738
// If a successful repair was not found, quit! Otherwise, issue
1739
// diagnosis and adjust configuration...
1740
//
1741
if (repair.code == 0)
1742            return candidate;
1743
1744        secondaryDiagnosis(repair);
1745
1746        //
1747
// Update buffer based on number of elements that are deleted.
1748
//
1749
switch(repair.code) {
1750            case MISPLACED_CODE:
1751                 candidate.location = buffer[2];
1752                 candidate.symbol = lexStream.kind(buffer[2]);
1753                 lexStream.reset(lexStream.next(buffer[2]));
1754
1755                 break;
1756
1757            case DELETION_CODE:
1758                 candidate.location = buffer[repair.bufferPosition];
1759                 candidate.symbol =
1760                           lexStream.kind(buffer[repair.bufferPosition]);
1761                 lexStream.reset(lexStream.next(buffer[repair.bufferPosition]));
1762
1763                 break;
1764
1765        default: // SCOPE_CODE || SECONDARY_CODE
1766
candidate.symbol = repair.symbol;
1767                 candidate.location = buffer[repair.bufferPosition];
1768                 lexStream.reset(buffer[repair.bufferPosition]);
1769
1770                 break;
1771        }
1772
1773        return candidate;
1774    }
1775
1776
1777//
1778
// This boolean function checks whether or not a given
1779
// configuration yields a better misplacement recovery than
1780
// the best misplacement recovery computed previously.
1781
//
1782
private SecondaryRepairInfo misplacementRecovery(int stck[], int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1783        int previous_loc = buffer[2];
1784        int stack_deletions = 0;
1785
1786        for (int top = stack_top - 1; top >= 0; top--) {
1787            if (locationStack[top] < previous_loc) {
1788                stack_deletions++;
1789            }
1790            previous_loc = locationStack[top];
1791
1792            int j = parseCheck(stck, top, lexStream.kind(buffer[2]), 3);
1793            if (j == MAX_DISTANCE) {
1794                 j = last_index;
1795            }
1796            if ((j > MIN_DISTANCE) && (j - stack_deletions) > (repair.distance - repair.numDeletions)) {
1797                repair.stackPosition = top;
1798                repair.distance = j;
1799                repair.numDeletions = stack_deletions;
1800                repair.recoveryOnNextStack = stack_flag;
1801            }
1802        }
1803
1804        return repair;
1805    }
1806
1807
1808//
1809
// This boolean function checks whether or not a given
1810
// configuration yields a better secondary recovery than the
1811
// best misplacement recovery computed previously.
1812
//
1813
private SecondaryRepairInfo secondaryRecovery(int stck[],int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1814        int previous_loc;
1815        int stack_deletions = 0;
1816        
1817        previous_loc = buffer[2];
1818        for (int top = stack_top; top >= 0 && repair.numDeletions >= stack_deletions; top--) {
1819            if (locationStack[top] < previous_loc) {
1820                stack_deletions++;
1821            }
1822            previous_loc = locationStack[top];
1823
1824            for (int i = 2;
1825                 i <= (last_index - MIN_DISTANCE + 1) &&
1826                 (repair.numDeletions >= (stack_deletions + i - 1)); i++) {
1827                int j = parseCheck(stck, top, lexStream.kind(buffer[i]), i + 1);
1828
1829                if (j == MAX_DISTANCE) {
1830                     j = last_index;
1831                }
1832                if ((j - i + 1) > MIN_DISTANCE) {
1833                    int k = stack_deletions + i - 1;
1834                    if ((k < repair.numDeletions) ||
1835                        (j - k) > (repair.distance - repair.numDeletions) ||
1836                        ((repair.code == SECONDARY_CODE) && (j - k) == (repair.distance - repair.numDeletions))) {
1837                        repair.code = DELETION_CODE;
1838                        repair.distance = j;
1839                        repair.stackPosition = top;
1840                        repair.bufferPosition = i;
1841                        repair.numDeletions = k;
1842                        repair.recoveryOnNextStack = stack_flag;
1843                    }
1844                }
1845
1846                for (int l = Parser.nasi(stck[top]); l >= 0 && Parser.nasr[l] != 0; l++) {
1847                    int symbol = Parser.nasr[l] + NT_OFFSET;
1848                    j = parseCheck(stck, top, symbol, i);
1849                    if (j == MAX_DISTANCE) {
1850                         j = last_index;
1851                    }
1852                    if ((j - i + 1) > MIN_DISTANCE) {
1853                        int k = stack_deletions + i - 1;
1854                        if (k < repair.numDeletions || (j - k) > (repair.distance - repair.numDeletions)) {
1855                            repair.code = SECONDARY_CODE;
1856                            repair.symbol = symbol;
1857                            repair.distance = j;
1858                            repair.stackPosition = top;
1859                            repair.bufferPosition = i;
1860                            repair.numDeletions = k;
1861                            repair.recoveryOnNextStack = stack_flag;
1862                        }
1863                    }
1864                }
1865            }
1866        }
1867
1868        return repair;
1869    }
1870
1871
1872//
1873
// This procedure is invoked to issue a secondary diagnosis and
1874
// adjust the input buffer. The recovery in question is either
1875
// an automatic scope recovery, a manual scope recovery, a
1876
// secondary substitution or a secondary deletion.
1877
//
1878
private void secondaryDiagnosis(SecondaryRepairInfo repair) {
1879        switch(repair.code) {
1880            case SCOPE_CODE: {
1881                if (repair.stackPosition < stateStackTop) {
1882                    reportError(DELETION_CODE,
1883                                Parser.terminal_index[ERROR_SYMBOL],
1884                                locationStack[repair.stackPosition],
1885                                buffer[1]);
1886                }
1887                for (int i = 0; i < scopeStackTop; i++) {
1888                    reportError(SCOPE_CODE,
1889                                -scopeIndex[i],
1890                                locationStack[scopePosition[i]],
1891                                buffer[1],
1892                                Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
1893                }
1894    
1895                repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
1896                stateStackTop = scopePosition[scopeStackTop];
1897                reportError(SCOPE_CODE,
1898                            -scopeIndex[scopeStackTop],
1899                            locationStack[scopePosition[scopeStackTop]],
1900                            buffer[1],
1901                            getNtermIndex(stack[stateStackTop],
1902                                          repair.symbol,
1903                                          repair.bufferPosition)
1904                           );
1905                break;
1906            }
1907            default: {
1908                reportError(repair.code,
1909                            (repair.code == SECONDARY_CODE
1910                                          ? getNtermIndex(stack[repair.stackPosition],
1911                                                          repair.symbol,
1912                                                          repair.bufferPosition)
1913                                          : Parser.terminal_index[ERROR_SYMBOL]),
1914                            locationStack[repair.stackPosition],
1915                            buffer[repair.bufferPosition - 1]);
1916                stateStackTop = repair.stackPosition;
1917            }
1918        }
1919    }
1920
1921
1922
1923
1924//
1925
// Try to parse until first_token and all tokens in BUFFER have
1926
// been consumed, or an error is encountered. Return the number
1927
// of tokens that were expended before the parse blocked.
1928
//
1929
private int parseCheck(int stck[], int stack_top, int first_token, int buffer_position) {
1930        int max_pos;
1931        int indx;
1932        int ct;
1933        int act;
1934
1935        //
1936
// Initialize pointer for temp_stack and initialize maximum
1937
// position of state stack that is still useful.
1938
//
1939
act = stck[stack_top];
1940        if (first_token > NT_OFFSET) {
1941            tempStackTop = stack_top;
1942            if(DEBUG_PARSECHECK) {
1943                System.out.println(tempStackTop);
1944            }
1945            max_pos = stack_top;
1946            indx = buffer_position;
1947            ct = lexStream.kind(buffer[indx]);
1948            lexStream.reset(lexStream.next(buffer[indx]));
1949            int lhs_symbol = first_token - NT_OFFSET;
1950            act = Parser.ntAction(act, lhs_symbol);
1951            if (act <= NUM_RULES) {
1952                // same loop as 'process_non_terminal'
1953
do {
1954                    tempStackTop -= (Parser.rhs[act]-1);
1955                    
1956                    if(DEBUG_PARSECHECK) {
1957                        System.out.print(tempStackTop);
1958                        System.out.print(" ("); //$NON-NLS-1$
1959
System.out.print(-(Parser.rhs[act]-1));
1960                        System.out.print(") [max:"); //$NON-NLS-1$
1961
System.out.print(max_pos);
1962                        System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
1963
System.out.print(act);
1964                        System.out.print("\t"); //$NON-NLS-1$
1965
System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
1966                        System.out.println();
1967                    }
1968                    
1969                    if(Parser.rules_compliance[act] > this.options.sourceLevel) {
1970                        return 0;
1971                    }
1972                    lhs_symbol = Parser.lhs[act];
1973                    act = (tempStackTop > max_pos
1974                                          ? tempStack[tempStackTop]
1975                                          : stck[tempStackTop]);
1976                    act = Parser.ntAction(act, lhs_symbol);
1977                } while(act <= NUM_RULES);
1978    
1979                max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1980            }
1981        } else {
1982            tempStackTop = stack_top - 1;
1983            
1984            if(DEBUG_PARSECHECK) {
1985                System.out.println(tempStackTop);
1986            }
1987            
1988            max_pos = tempStackTop;
1989            indx = buffer_position - 1;
1990            ct = first_token;
1991            lexStream.reset(buffer[buffer_position]);
1992        }
1993
1994        process_terminal: for (;;) {
1995            if(DEBUG_PARSECHECK) {
1996                System.out.print(tempStackTop + 1);
1997                System.out.print(" (+1) [max:"); //$NON-NLS-1$
1998
System.out.print(max_pos);
1999                System.out.print("]\tprocess_terminal \t"); //$NON-NLS-1$
2000
System.out.print(ct);
2001                System.out.print("\t"); //$NON-NLS-1$
2002
System.out.print(Parser.name[Parser.terminal_index[ct]]);
2003                System.out.println();
2004            }
2005            
2006            if (++tempStackTop >= stackLength) // Stack overflow!!!
2007
return indx;
2008            tempStack[tempStackTop] = act;
2009
2010            act = Parser.tAction(act, ct);
2011
2012            if (act <= NUM_RULES) { // reduce action
2013
tempStackTop--;
2014                
2015                if(DEBUG_PARSECHECK) {
2016                    System.out.print(tempStackTop);
2017                    System.out.print(" (-1) [max:"); //$NON-NLS-1$
2018
System.out.print(max_pos);
2019                    System.out.print("]\treduce"); //$NON-NLS-1$
2020
System.out.println();
2021                }
2022            } else if (act < ACCEPT_ACTION || // shift action
2023
act > ERROR_ACTION) { // shift-reduce action
2024
if (indx == MAX_DISTANCE)
2025                    return indx;
2026                indx++;
2027                ct = lexStream.kind(buffer[indx]);
2028                lexStream.reset(lexStream.next(buffer[indx]));
2029                if (act > ERROR_ACTION) {
2030                    act -= ERROR_ACTION;
2031                    
2032                    if(DEBUG_PARSECHECK) {
2033                        System.out.print(tempStackTop);
2034                        System.out.print("\tshift reduce"); //$NON-NLS-1$
2035
System.out.println();
2036                    }
2037                } else {
2038                    if(DEBUG_PARSECHECK) {
2039                        System.out.println("\tshift"); //$NON-NLS-1$
2040
}
2041                    continue process_terminal;
2042                }
2043            } else if (act == ACCEPT_ACTION) { // accept action
2044
return MAX_DISTANCE;
2045            } else {
2046                return indx; // error action
2047
}
2048
2049            // same loop as first token initialization
2050
// process_non_terminal:
2051
do {
2052                tempStackTop -= (Parser.rhs[act]-1);
2053                
2054                if(DEBUG_PARSECHECK) {
2055                    System.out.print(tempStackTop);
2056                    System.out.print(" ("); //$NON-NLS-1$
2057
System.out.print(-(Parser.rhs[act]-1));
2058                    System.out.print(") [max:"); //$NON-NLS-1$
2059
System.out.print(max_pos);
2060                    System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
2061
System.out.print(act);
2062                    System.out.print("\t"); //$NON-NLS-1$
2063
System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
2064                    System.out.println();
2065                }
2066                
2067                if(act <= NUM_RULES) {
2068                    if(Parser.rules_compliance[act] > this.options.sourceLevel) {
2069                        return 0;
2070                    }
2071                }
2072                int lhs_symbol = Parser.lhs[act];
2073                act = (tempStackTop > max_pos
2074                                      ? tempStack[tempStackTop]
2075                                      : stck[tempStackTop]);
2076                act = Parser.ntAction(act, lhs_symbol);
2077            } while(act <= NUM_RULES);
2078
2079            max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
2080        } // process_terminal;
2081
}
2082    private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken) {
2083        reportError(msgCode, nameIndex, leftToken, rightToken, 0);
2084    }
2085
2086    private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
2087        int lToken = (leftToken > rightToken ? rightToken : leftToken);
2088
2089        if (lToken < rightToken) {
2090            reportSecondaryError(msgCode, nameIndex, lToken, rightToken, scopeNameIndex);
2091        } else {
2092            reportPrimaryError(msgCode, nameIndex, rightToken, scopeNameIndex);
2093        }
2094    }
2095    private void reportPrimaryError(int msgCode, int nameIndex, int token, int scopeNameIndex) {
2096        String JavaDoc name;
2097        if (nameIndex >= 0) {
2098            name = Parser.readableName[nameIndex];
2099        } else {
2100            name = Util.EMPTY_STRING;
2101        }
2102
2103        int errorStart = lexStream.start(token);
2104        int errorEnd = lexStream.end(token);
2105        int currentKind = lexStream.kind(token);
2106        String JavaDoc errorTokenName = Parser.name[Parser.terminal_index[lexStream.kind(token)]];
2107        char[] errorTokenSource = lexStream.name(token);
2108
2109        int addedToken = -1;
2110        if(recoveryScanner != null) {
2111            if (nameIndex >= 0) {
2112                addedToken = Parser.reverse_index[nameIndex];
2113            }
2114        }
2115        switch(msgCode) {
2116            case BEFORE_CODE:
2117                if(recoveryScanner != null) {
2118                    if(addedToken > -1) {
2119                        recoveryScanner.insertToken(addedToken, -1, errorStart);
2120                    } else {
2121                        int[] template = getNTermTemplate(-addedToken);
2122                        if(template != null) {
2123                            recoveryScanner.insertTokens(template, -1, errorStart);
2124                        }
2125                    }
2126                }
2127                if(this.reportProblem) problemReporter().parseErrorInsertBeforeToken(
2128                    errorStart,
2129                    errorEnd,
2130                    currentKind,
2131                    errorTokenSource,
2132                    errorTokenName,
2133                    name);
2134                 break;
2135            case INSERTION_CODE:
2136                if(recoveryScanner != null) {
2137                    if(addedToken > -1) {
2138                        recoveryScanner.insertToken(addedToken, -1, errorEnd);
2139                    } else {
2140                        int[] template = getNTermTemplate(-addedToken);
2141                        if(template != null) {
2142                            recoveryScanner.insertTokens(template, -1, errorEnd);
2143                        }
2144                    }
2145                }
2146                if(this.reportProblem) problemReporter().parseErrorInsertAfterToken(
2147                    errorStart,
2148                    errorEnd,
2149                    currentKind,
2150                    errorTokenSource,
2151                    errorTokenName,
2152                    name);
2153                 break;
2154            case DELETION_CODE:
2155                if(recoveryScanner != null) {
2156                    recoveryScanner.removeTokens(errorStart, errorEnd);
2157                }
2158                if(this.reportProblem) problemReporter().parseErrorDeleteToken(
2159                    errorStart,
2160                    errorEnd,
2161                    currentKind,
2162                    errorTokenSource,
2163                    errorTokenName);
2164                break;
2165            case INVALID_CODE:
2166                if (name.length() == 0) {
2167                    if(recoveryScanner != null) {
2168                        recoveryScanner.removeTokens(errorStart, errorEnd);
2169                    }
2170                    if(this.reportProblem) problemReporter().parseErrorReplaceToken(
2171                        errorStart,
2172                        errorEnd,
2173                        currentKind,
2174                        errorTokenSource,
2175                        errorTokenName,
2176                        name);
2177                } else {
2178                    if(recoveryScanner != null) {
2179                        if(addedToken > -1) {
2180                            recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2181                        } else {
2182                            int[] template = getNTermTemplate(-addedToken);
2183                            if(template != null) {
2184                                recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2185                            }
2186                        }
2187                    }
2188                    if(this.reportProblem) problemReporter().parseErrorInvalidToken(
2189                        errorStart,
2190                        errorEnd,
2191                        currentKind,
2192                        errorTokenSource,
2193                        errorTokenName,
2194                        name);
2195                }
2196                break;
2197            case SUBSTITUTION_CODE:
2198                if(recoveryScanner != null) {
2199                    if(addedToken > -1) {
2200                        recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2201                    } else {
2202                        int[] template = getNTermTemplate(-addedToken);
2203                        if(template != null) {
2204                            recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2205                        }
2206                    }
2207                }
2208                if(this.reportProblem) problemReporter().parseErrorReplaceToken(
2209                    errorStart,
2210                    errorEnd,
2211                    currentKind,
2212                    errorTokenSource,
2213                    errorTokenName,
2214                    name);
2215                 break;
2216            case SCOPE_CODE:
2217                StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2218                
2219                int[] addedTokens = null;
2220                int addedTokenCount = 0;
2221                if(this.recoveryScanner != null) {
2222                    addedTokens = new int[Parser.scope_rhs.length - Parser.scope_suffix[- nameIndex]];
2223                }
2224                
2225                for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2226                    buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2227                    if (Parser.scope_rhs[i + 1] != 0) // any more symbols to print?
2228
buf.append(' ');
2229                    
2230                    if(addedTokens != null) {
2231                        int tmpAddedToken = Parser.reverse_index[Parser.scope_rhs[i]];
2232                        if (tmpAddedToken > -1) {
2233                            int length = addedTokens.length;
2234                            if(addedTokenCount == length) {
2235                                System.arraycopy(addedTokens, 0, addedTokens = new int[length * 2], 0, length);
2236                            }
2237                            addedTokens[addedTokenCount++] = tmpAddedToken;
2238                        } else {
2239                            int[] template = getNTermTemplate(-tmpAddedToken);
2240                            if(template != null) {
2241                                for (int j = 0; j < template.length; j++) {
2242                                    int length = addedTokens.length;
2243                                    if(addedTokenCount == length) {
2244                                        System.arraycopy(addedTokens, 0, addedTokens = new int[length * 2], 0, length);
2245                                    }
2246                                    addedTokens[addedTokenCount++] = template[j];
2247                                }
2248                            } else {
2249                                addedTokenCount = 0;
2250                                addedTokens = null;
2251                            }
2252                        }
2253                    }
2254                }
2255
2256                if(addedTokenCount > 0) {
2257                    System.arraycopy(addedTokens, 0, addedTokens = new int[addedTokenCount], 0, addedTokenCount);
2258                    
2259                    int completedToken = -1;
2260                    if(scopeNameIndex != 0) {
2261                        completedToken = -Parser.reverse_index[scopeNameIndex];
2262                    }
2263                    this.recoveryScanner.insertTokens(addedTokens, completedToken, errorEnd);
2264                }
2265                
2266                if (scopeNameIndex != 0) {
2267                    if(this.reportProblem) problemReporter().parseErrorInsertToComplete(
2268                        errorStart,
2269                        errorEnd,
2270                        buf.toString(),
2271                        Parser.readableName[scopeNameIndex]);
2272                } else {
2273                    if(this.reportProblem) problemReporter().parseErrorInsertToCompleteScope(
2274                        errorStart,
2275                        errorEnd,
2276                        buf.toString());
2277                }
2278                
2279                break;
2280            case EOF_CODE:
2281                if(this.reportProblem) problemReporter().parseErrorUnexpectedEnd(
2282                    errorStart,
2283                    errorEnd);
2284                break;
2285            case MERGE_CODE:
2286                if(recoveryScanner != null) {
2287                    if(addedToken > -1) {
2288                        recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2289                    } else {
2290                        int[] template = getNTermTemplate(-addedToken);
2291                        if(template != null) {
2292                            recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2293                        }
2294                    }
2295                }
2296                if(this.reportProblem) problemReporter().parseErrorMergeTokens(
2297                    errorStart,
2298                    errorEnd,
2299                    name);
2300                break;
2301            case MISPLACED_CODE:
2302                if(recoveryScanner != null) {
2303                    recoveryScanner.removeTokens(errorStart, errorEnd);
2304                }
2305                if(this.reportProblem) problemReporter().parseErrorMisplacedConstruct(
2306                    errorStart,
2307                    errorEnd);
2308                break;
2309            default:
2310                if (name.length() == 0) {
2311                    if(recoveryScanner != null) {
2312                        recoveryScanner.removeTokens(errorStart, errorEnd);
2313                    }
2314                    if(this.reportProblem) problemReporter().parseErrorNoSuggestion(
2315                        errorStart,
2316                        errorEnd,
2317                        currentKind,
2318                        errorTokenSource,
2319                        errorTokenName);
2320                } else {
2321                    if(recoveryScanner != null) {
2322                        if(addedToken > -1) {
2323                            recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2324                        } else {
2325                            int[] template = getNTermTemplate(-addedToken);
2326                            if(template != null) {
2327                                recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2328                            }
2329                        }
2330                    }
2331                    if(this.reportProblem) problemReporter().parseErrorReplaceToken(
2332                        errorStart,
2333                        errorEnd,
2334                        currentKind,
2335                        errorTokenSource,
2336                        errorTokenName,
2337                        name);
2338                }
2339                break;
2340        }
2341    }
2342
2343    private void reportSecondaryError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
2344        String JavaDoc name;
2345        if (nameIndex >= 0) {
2346            name = Parser.readableName[nameIndex];
2347        } else {
2348            name = Util.EMPTY_STRING;
2349        }
2350
2351        int errorStart = -1;
2352        if(lexStream.isInsideStream(leftToken)) {
2353            if(leftToken == 0) {
2354                errorStart = lexStream.start(leftToken + 1);
2355            } else {
2356                errorStart = lexStream.start(leftToken);
2357            }
2358        } else {
2359            if(leftToken == errorToken) {
2360                errorStart = errorTokenStart;
2361            } else {
2362                for (int i = 0; i <= stateStackTop; i++) {
2363                    if(locationStack[i] == leftToken) {
2364                        errorStart = locationStartStack[i];
2365                    }
2366                }
2367            }
2368            if(errorStart == -1) {
2369                errorStart = lexStream.start(rightToken);
2370            }
2371        }
2372        int errorEnd = lexStream.end(rightToken);
2373        
2374        int addedToken = -1;
2375        if(recoveryScanner != null) {
2376            if (nameIndex >= 0) {
2377                addedToken = Parser.reverse_index[nameIndex];
2378            }
2379        }
2380        
2381        switch(msgCode) {
2382            case MISPLACED_CODE:
2383                if(recoveryScanner != null) {
2384                    recoveryScanner.removeTokens(errorStart, errorEnd);
2385                }
2386                if(this.reportProblem) problemReporter().parseErrorMisplacedConstruct(
2387                    errorStart,
2388                    errorEnd);
2389                break;
2390            case SCOPE_CODE:
2391                // error start is on the last token start
2392
errorStart = lexStream.start(rightToken);
2393            
2394                StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2395                
2396                int[] addedTokens = null;
2397                int addedTokenCount = 0;
2398                if(this.recoveryScanner != null) {
2399                    addedTokens = new int[Parser.scope_rhs.length - Parser.scope_suffix[- nameIndex]];
2400                }
2401                
2402                for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2403                    
2404                    buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2405                    if (Parser.scope_rhs[i+1] != 0)
2406                         buf.append(' ');
2407                    
2408                    if(addedTokens != null) {
2409                        int tmpAddedToken = Parser.reverse_index[Parser.scope_rhs[i]];
2410                        if (tmpAddedToken > -1) {
2411                            int length = addedTokens.length;
2412                            if(addedTokenCount == length) {
2413                                System.arraycopy(addedTokens, 0, addedTokens = new int[length * 2], 0, length);
2414                            }
2415                            addedTokens[addedTokenCount++] = tmpAddedToken;
2416                        } else {
2417                            int[] template = getNTermTemplate(-tmpAddedToken);
2418                            if(template != null) {
2419                                for (int j = 0; j < template.length; j++) {
2420                                    int length = addedTokens.length;
2421                                    if(addedTokenCount == length) {
2422                                        System.arraycopy(addedTokens, 0, addedTokens = new int[length * 2], 0, length);
2423                                    }
2424                                    addedTokens[addedTokenCount++] = template[j];
2425                                }
2426                            } else {
2427                                addedTokenCount = 0;
2428                                addedTokens = null;
2429                            }
2430                        }
2431                    }
2432                }
2433                if(addedTokenCount > 0) {
2434                    System.arraycopy(addedTokens, 0, addedTokens = new int[addedTokenCount], 0, addedTokenCount);
2435                    int completedToken = -1;
2436                    if(scopeNameIndex != 0) {
2437                        completedToken = -Parser.reverse_index[scopeNameIndex];
2438                    }
2439                    this.recoveryScanner.insertTokens(addedTokens, completedToken, errorEnd);
2440                }
2441                if (scopeNameIndex != 0) {
2442                    if(this.reportProblem) problemReporter().parseErrorInsertToComplete(
2443                        errorStart,
2444                        errorEnd,
2445                        buf.toString(),
2446                        Parser.readableName[scopeNameIndex]);
2447                } else {
2448                    if(this.reportProblem) problemReporter().parseErrorInsertToCompletePhrase(
2449                        errorStart,
2450                        errorEnd,
2451                        buf.toString());
2452                }
2453                break;
2454            case MERGE_CODE:
2455                if(recoveryScanner != null) {
2456                    if(addedToken > -1) {
2457                        recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2458                    } else {
2459                        int[] template = getNTermTemplate(-addedToken);
2460                        if(template != null) {
2461                            recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2462                        }
2463                    }
2464                }
2465                if(this.reportProblem) problemReporter().parseErrorMergeTokens(
2466                    errorStart,
2467                    errorEnd,
2468                    name);
2469                break;
2470            case DELETION_CODE:
2471                if(recoveryScanner != null) {
2472                    recoveryScanner.removeTokens(errorStart, errorEnd);
2473                }
2474                if(this.reportProblem) problemReporter().parseErrorDeleteTokens(
2475                    errorStart,
2476                    errorEnd);
2477                break;
2478            default:
2479                if (name.length() == 0) {
2480                    if(recoveryScanner != null) {
2481                        recoveryScanner.removeTokens(errorStart, errorEnd);
2482                    }
2483                    if(this.reportProblem) problemReporter().parseErrorNoSuggestionForTokens(
2484                        errorStart,
2485                        errorEnd);
2486                } else {
2487                    if(recoveryScanner != null) {
2488                        if(addedToken > -1) {
2489                            recoveryScanner.replaceTokens(addedToken, errorStart, errorEnd);
2490                        } else {
2491                            int[] template = getNTermTemplate(-addedToken);
2492                            if(template != null) {
2493                                recoveryScanner.replaceTokens(template, errorStart, errorEnd);
2494                            }
2495                        }
2496                    }
2497                    if(this.reportProblem) problemReporter().parseErrorReplaceTokens(
2498                        errorStart,
2499                        errorEnd,
2500                        name);
2501                }
2502        }
2503        return;
2504    }
2505
2506    private int[] getNTermTemplate(int sym) {
2507        int templateIndex = Parser.recovery_templates_index[sym];
2508        if(templateIndex > 0) {
2509            int[] result = new int[Parser.recovery_templates.length];
2510            int count = 0;
2511            for(int j = templateIndex; Parser.recovery_templates[j] != 0; j++) {
2512                result[count++] = Parser.recovery_templates[j];
2513            }
2514            System.arraycopy(result, 0, result = new int[count], 0, count);
2515            return result;
2516        } else {
2517            return null;
2518        }
2519    }
2520    
2521    public String JavaDoc toString() {
2522        StringBuffer JavaDoc res = new StringBuffer JavaDoc();
2523        
2524        res.append(lexStream.toString());
2525        
2526        return res.toString();
2527    }
2528}
2529
Popular Tags