added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / parser / diagnose / DiagnoseParser.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
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.TerminalTokens;
18 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
19
20 public class DiagnoseParser implements ParserBasicInformation, TerminalTokens {
21         private static final boolean DEBUG = false;
22         private boolean DEBUG_PARSECHECK = false;
23         
24         private static final String EMPTY_STRING = ""; //$NON-NLS-1$
25         private static final int STACK_INCREMENT = 256;
26         
27 //      private static final int ERROR_CODE = 1;
28         private static final int BEFORE_CODE = 2;
29         private static final int INSERTION_CODE = 3;
30         private static final int INVALID_CODE = 4;
31         private static final int SUBSTITUTION_CODE = 5;
32         private static final int DELETION_CODE = 6;
33         private static final int MERGE_CODE = 7;
34         private static final int MISPLACED_CODE = 8;
35         private static final int SCOPE_CODE = 9;
36         private static final int SECONDARY_CODE = 10;
37         private static final int EOF_CODE = 11;
38
39         private static final int BUFF_UBOUND  = 31;
40         private static final int BUFF_SIZE    = 32;
41         private static final int MAX_DISTANCE = 30;
42         private static final int MIN_DISTANCE = 3;
43         
44         private CompilerOptions options;
45         
46         private LexStream lexStream;
47         private int errorToken;
48         private int errorTokenStart;
49         
50         private int currentToken = 0;
51         
52         private int stackLength;
53         private int stateStackTop;
54         private int[] stack;
55         
56         private int[] locationStack;
57         private int[] locationStartStack;
58         
59         private int tempStackTop;
60         private int[] tempStack;
61         
62         private int prevStackTop;
63         private int[] prevStack;
64         private int nextStackTop;
65         private int[] nextStack;
66         
67         private int scopeStackTop;
68     private int[] scopeIndex;
69     private int[] scopePosition;
70         
71         int[] list = new int[NUM_SYMBOLS + 1];
72         int[] buffer = new int[BUFF_SIZE];
73         
74         private static final int NIL = -1;
75         int[] stateSeen;
76         
77         int statePoolTop;
78         StateInfo[] statePool;
79         
80         private Parser parser;
81         
82         private class RepairCandidate {
83                 public int symbol;
84                 public int location;
85                 
86                 public RepairCandidate(){
87                         this.symbol = 0;
88                         this.location = 0;
89                 }
90         }
91         
92         private class PrimaryRepairInfo {
93                 public int distance;
94                 public int misspellIndex;
95                 public int code;
96                 public int bufferPosition;
97                 public int symbol;
98                 
99                 public PrimaryRepairInfo(){
100                         this.distance = 0;
101                         this.misspellIndex = 0;
102                         this.code = 0;
103                         this.bufferPosition = 0;
104                         this.symbol = 0;
105                 }
106                 
107                 public PrimaryRepairInfo copy(){
108                         PrimaryRepairInfo c = new PrimaryRepairInfo();
109                         c.distance = this.distance;
110                         c.misspellIndex = this.misspellIndex;
111                         c.code = this.code;
112                         c.bufferPosition = this .bufferPosition;
113                         c.symbol = this.symbol;
114                         return c;
115                         
116                 }
117         }
118         
119         private class SecondaryRepairInfo {
120                 public int code;
121                 public int distance;
122                 public int bufferPosition;
123                 public int stackPosition;
124                 public int numDeletions;
125                 public int symbol;
126
127                 boolean recoveryOnNextStack;
128         } 
129         
130         private class StateInfo {
131             int state;
132             int next;
133             
134             public StateInfo(int state, int next){
135                 this.state = state;
136                 this.next = next;
137             }
138         }
139
140         public DiagnoseParser(Parser parser, int firstToken, int start, int end, CompilerOptions options) {
141                 this(parser, firstToken, start, end, new int[0], new int[0], new int[0], options);
142         }
143
144         public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, CompilerOptions options) {
145                 this.parser = parser;
146                 this.options = options;
147                 this.lexStream = new LexStream(BUFF_SIZE, parser.scanner, intervalStartToSkip, intervalEndToSkip, intervalFlagsToSkip, firstToken, start, end);
148         }
149         
150         private ProblemReporter problemReporter(){
151                 return parser.problemReporter();
152         }
153
154         private void reallocateStacks() {
155                 int old_stack_length = stackLength;
156
157                 stackLength += STACK_INCREMENT;
158
159                 if(old_stack_length == 0){
160                         stack = new int[stackLength];
161                         locationStack = new int[stackLength];
162                         locationStartStack = new int[stackLength];
163                         tempStack = new int[stackLength];
164                         prevStack = new int[stackLength];
165                         nextStack = new int[stackLength];
166                         scopeIndex = new int[stackLength];
167                         scopePosition = new int[stackLength];
168                 } else {
169                         System.arraycopy(stack, 0, stack = new int[stackLength], 0, old_stack_length);
170                         System.arraycopy(locationStack, 0, locationStack = new int[stackLength], 0, old_stack_length);
171                         System.arraycopy(locationStartStack, 0, locationStartStack = new int[stackLength], 0, old_stack_length);
172                         System.arraycopy(tempStack, 0, tempStack = new int[stackLength], 0, old_stack_length);
173                         System.arraycopy(prevStack, 0, prevStack = new int[stackLength], 0, old_stack_length);
174                         System.arraycopy(nextStack, 0, nextStack = new int[stackLength], 0, old_stack_length);
175                         System.arraycopy(scopeIndex, 0, scopeIndex = new int[stackLength], 0, old_stack_length);
176                         System.arraycopy(scopePosition, 0, scopePosition = new int[stackLength], 0, old_stack_length);
177                 }
178                 return;
179         }
180
181
182         public void diagnoseParse() {
183                 lexStream.reset();
184
185                 currentToken = lexStream.getToken();
186
187                 int prev_pos;
188                 int pos;
189                 int next_pos;
190                 int act = START_STATE;
191
192                 reallocateStacks();
193
194                 //
195                 // Start parsing
196                 //
197                 stateStackTop = 0;
198                 stack[stateStackTop] = act;
199
200                 int tok = lexStream.kind(currentToken);
201                 locationStack[stateStackTop] = currentToken;
202                 locationStartStack[stateStackTop] = lexStream.start(currentToken);
203                 
204                 boolean forceRecoveryAfterLBracketMissing = false;
205 //              int forceRecoveryToken = -1;
206
207                 //
208                 // Process a terminal
209                 //
210                 do {
211                         //
212                         // Synchronize state stacks and update the location stack
213                         //
214                         prev_pos = -1;
215                         prevStackTop = -1;
216
217                         next_pos = -1;
218                         nextStackTop = -1;
219
220                         pos = stateStackTop;
221                         tempStackTop = stateStackTop - 1;
222                         for (int i = 0; i <= stateStackTop; i++)
223                                 tempStack[i] = stack[i];
224
225                         act = Parser.tAction(act, tok);
226                         //
227                         // When a reduce action is encountered, we compute all REDUCE
228                         // and associated goto actions induced by the current token.
229                         // Eventually, a SHIFT, SHIFT-REDUCE, ACCEPT or ERROR action is
230                         // computed...
231                         //
232                         while (act <= NUM_RULES) {
233                                 do {
234                                         tempStackTop -= (Parser.rhs[act]-1);
235                                         act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
236                                 } while(act <= NUM_RULES);
237                                 //
238                                 // ... Update the maximum useful position of the
239                                 // (STATE_)STACK, push goto state into stack, and
240                                 // compute next action on current symbol ...
241                                 //
242                                 if (tempStackTop + 1 >= stackLength)
243                                         reallocateStacks();
244                                 pos = pos < tempStackTop ? pos : tempStackTop;
245                                 tempStack[tempStackTop + 1] = act;
246                                 act = Parser.tAction(act, tok);
247                         }
248
249                         //
250                         // At this point, we have a shift, shift-reduce, accept or error
251                         // action.  STACK contains the configuration of the state stack
252                         // prior to executing any action on curtok. next_stack contains
253                         // the configuration of the state stack after executing all
254                         // reduce actions induced by curtok.  The variable pos indicates
255                         // the highest position in STACK that is still useful after the
256                         // reductions are executed.
257                         //
258                         while(act > ERROR_ACTION || act < ACCEPT_ACTION) { // SHIFT-REDUCE action or SHIFT action ?
259                                 nextStackTop = tempStackTop + 1;
260                                 for (int i = next_pos + 1; i <= nextStackTop; i++)
261                                         nextStack[i] = tempStack[i];
262
263                                 for (int i = pos + 1; i <= nextStackTop; i++) {
264                                         locationStack[i] = locationStack[stateStackTop];
265                                         locationStartStack[i] = locationStartStack[stateStackTop];
266                                 }
267
268                                 //
269                                 // If we have a shift-reduce, process it as well as
270                                 // the goto-reduce actions that follow it.
271                                 //
272                                 if (act > ERROR_ACTION) {
273                                         act -= ERROR_ACTION;
274                                         do {
275                                                 nextStackTop -= (Parser.rhs[act]-1);
276                                                 act = Parser.ntAction(nextStack[nextStackTop], Parser.lhs[act]);
277                                         } while(act <= NUM_RULES);
278                                         pos = pos < nextStackTop ? pos : nextStackTop;
279                                 }
280
281                                 if (nextStackTop + 1 >= stackLength)
282                                         reallocateStacks();
283
284                                 tempStackTop = nextStackTop;
285                                 nextStack[++nextStackTop] = act;
286                                 next_pos = nextStackTop;
287
288                                 //
289                                 // Simulate the parser through the next token without
290                                 // destroying STACK or next_stack.
291                                 //
292                                 currentToken = lexStream.getToken();
293                                 tok = lexStream.kind(currentToken);
294                                 act = Parser.tAction(act, tok);
295                                 while(act <= NUM_RULES) {
296                                         //
297                                         // ... Process all goto-reduce actions following
298                                         // reduction, until a goto action is computed ...
299                                         //
300                                         do {
301                                                 int lhs_symbol = Parser.lhs[act];
302                                                 if(DEBUG) {
303                                                         System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
304                                                 }
305                                                 tempStackTop -= (Parser.rhs[act]-1);
306                                                 act = (tempStackTop > next_pos
307                                                                    ? tempStack[tempStackTop]
308                                                                    : nextStack[tempStackTop]);
309                                                 act = Parser.ntAction(act, lhs_symbol);
310                                         }   while(act <= NUM_RULES);
311
312                                         //
313                                         // ... Update the maximum useful position of the
314                                         // (STATE_)STACK, push GOTO state into stack, and
315                                         // compute next action on current symbol ...
316                                         //
317                                         if (tempStackTop + 1 >= stackLength)
318                                                 reallocateStacks();
319
320                                         next_pos = next_pos < tempStackTop ? next_pos : tempStackTop;
321                                         tempStack[tempStackTop + 1] = act;
322                                         act = Parser.tAction(act, tok);
323                                 }
324
325 //                              if((tok != TokenNameRBRACE || (forceRecoveryToken != currentToken && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0))
326 //                                      && (lexStream.flags(currentToken) & LexStream.IS_AFTER_JUMP) !=0) {
327 //                                      act = ERROR_ACTION;
328 //                                      if(forceRecoveryToken != currentToken
329 //                                              && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0) {
330 //                                              forceRecoveryAfterLBracketMissing = true;
331 //                                              forceRecoveryToken = currentToken;
332 //                                      }
333 //                              }
334                                 
335                                 //
336                                 // No error was detected, Read next token into
337                                 // PREVTOK element, advance CURTOK pointer and
338                                 // update stacks.
339                                 //
340                                 if (act != ERROR_ACTION) {
341                                         prevStackTop = stateStackTop;
342                                         for (int i = prev_pos + 1; i <= prevStackTop; i++)
343                                                 prevStack[i] = stack[i];
344                                         prev_pos = pos;
345
346                                         stateStackTop = nextStackTop;
347                                         for (int i = pos + 1; i <= stateStackTop; i++)
348                                                 stack[i] = nextStack[i];
349                                         locationStack[stateStackTop] = currentToken;
350                                         locationStartStack[stateStackTop] = lexStream.start(currentToken);
351                                         pos = next_pos;
352                                 }
353                         }
354
355                         //
356                         // At this stage, either we have an ACCEPT or an ERROR
357                         // action.
358                         //
359                         if (act == ERROR_ACTION) {
360                                 //
361                                 // An error was detected.
362                                 //
363                                 RepairCandidate candidate = errorRecovery(currentToken, forceRecoveryAfterLBracketMissing);
364                                 
365                                 forceRecoveryAfterLBracketMissing = false;
366                                 
367                                 if(parser.reportOnlyOneSyntaxError) {
368                                         return;
369                                 }
370                                 
371                                 if(this.parser.problemReporter().options.maxProblemsPerUnit < this.parser.compilationUnit.compilationResult.problemCount) {
372                                         return;
373                                 }
374
375                                 act = stack[stateStackTop];
376
377                                 //
378                                 // If the recovery was successful on a nonterminal candidate,
379                                 // parse through that candidate and "read" the next token.
380                                 //
381                                 if (candidate.symbol == 0) {
382                                         break;
383                                 } else if (candidate.symbol > NT_OFFSET) {
384                                         int lhs_symbol = candidate.symbol - NT_OFFSET;
385                                         if(DEBUG) {
386                                                 System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]);
387                                         }
388                                         act = Parser.ntAction(act, lhs_symbol);
389                                         while(act <= NUM_RULES) {
390                                                 stateStackTop -= (Parser.rhs[act]-1);
391                                                 act = Parser.ntAction(stack[stateStackTop], Parser.lhs[act]);
392                                         }
393                                         stack[++stateStackTop] = act;
394                                         currentToken = lexStream.getToken();
395                                         tok = lexStream.kind(currentToken);
396                                         locationStack[stateStackTop] = currentToken;
397                                         locationStartStack[stateStackTop] = lexStream.start(currentToken);
398                                 } else {
399                                         tok = candidate.symbol;
400                                         locationStack[stateStackTop] = candidate.location;
401                                         locationStartStack[stateStackTop] = lexStream.start(candidate.location);
402                                 }
403                         }
404                 } while (act != ACCEPT_ACTION);
405
406                 return;
407         }
408
409         //
410 //              This routine is invoked when an error is encountered.  It
411 //         tries to diagnose the error and recover from it.  If it is
412 //         successful, the state stack, the current token and the buffer
413 //         are readjusted; i.e., after a successful recovery,
414 //         state_stack_top points to the location in the state stack
415 //         that contains the state on which to recover; curtok
416 //         identifies the symbol on which to recover.
417 //
418 //         Up to three configurations may be available when this routine
419 //         is invoked. PREV_STACK may contain the sequence of states
420 //         preceding any action on prevtok, STACK always contains the
421 //         sequence of states preceding any action on curtok, and
422 //         NEXT_STACK may contain the sequence of states preceding any
423 //         action on the successor of curtok.
424 //
425         private RepairCandidate errorRecovery(int error_token, boolean forcedError) {
426                 this.errorToken = error_token;
427                 this.errorTokenStart = lexStream.start(error_token);
428                 
429                 int prevtok = lexStream.previous(error_token);
430                 int prevtokKind = lexStream.kind(prevtok);
431                 
432                 if(forcedError) {
433                         int name_index = Parser.terminal_index[TokenNameLBRACE];
434
435                         reportError(INSERTION_CODE, name_index, prevtok, prevtok);
436                         
437                         RepairCandidate candidate = new RepairCandidate();
438                         candidate.symbol = TokenNameLBRACE;
439                         candidate.location = error_token;
440                         lexStream.reset(error_token);
441                         
442                         stateStackTop = nextStackTop;
443                         for (int j = 0; j <= stateStackTop; j++) {
444                                 stack[j] = nextStack[j];
445                         }
446                         locationStack[stateStackTop] = error_token;
447                         locationStartStack[stateStackTop] = lexStream.start(error_token);
448                         
449                         return candidate;
450                 }
451
452                 //
453                 // Try primary phase recoveries. If not successful, try secondary
454                 // phase recoveries.  If not successful and we are at end of the
455                 // file, we issue the end-of-file error and quit. Otherwise, ...
456                 //
457                 RepairCandidate candidate = primaryPhase(error_token);
458                 if (candidate.symbol != 0) {
459                         return candidate;
460                 }
461
462                 candidate = secondaryPhase(error_token);
463                 if (candidate.symbol != 0) {
464                         return candidate;
465                 }
466
467                 if (lexStream.kind(error_token) == EOFT_SYMBOL) {
468                         reportError(EOF_CODE,
469                                                 Parser.terminal_index[EOFT_SYMBOL],
470                                                 prevtok,
471                                                 prevtok);
472                         candidate.symbol = 0;
473                         candidate.location = error_token;
474                         return candidate;
475                 }
476
477                 //
478                 // At this point, primary and (initial attempt at) secondary
479                 // recovery did not work.  We will now get into "panic mode" and
480                 // keep trying secondary phase recoveries until we either find
481                 // a successful recovery or have consumed the remaining input
482                 // tokens.
483                 //
484                 while(lexStream.kind(buffer[BUFF_UBOUND]) != EOFT_SYMBOL) {
485                         candidate = secondaryPhase(buffer[MAX_DISTANCE - MIN_DISTANCE + 2]);
486                         if (candidate.symbol != 0) {
487                                 return candidate;
488                         }
489                 }
490
491                 //
492                 // We reached the end of the file while panicking. Delete all
493                 // remaining tokens in the input.
494                 //
495                 int i;
496                 for (i = BUFF_UBOUND; lexStream.kind(buffer[i]) == EOFT_SYMBOL; i--){/*empty*/}
497
498                 reportError(DELETION_CODE,
499                                         Parser.terminal_index[prevtokKind],//Parser.terminal_index[lexStream.kind(prevtok)],
500                                         error_token,
501                                         buffer[i]);
502
503                 candidate.symbol = 0;
504                 candidate.location = buffer[i];
505
506                 return candidate;
507         }
508
509 //
510 //         This function tries primary and scope recovery on each
511 //         available configuration.  If a successful recovery is found
512 //         and no secondary phase recovery can do better, a diagnosis is
513 //         issued, the configuration is updated and the function returns
514 //         "true".  Otherwise, it returns "false".
515 //
516         private RepairCandidate primaryPhase(int error_token) {
517                 PrimaryRepairInfo repair = new PrimaryRepairInfo();
518                 RepairCandidate candidate = new RepairCandidate();
519
520                 //
521                 // Initialize the buffer.
522                 //
523                 int i = (nextStackTop >= 0 ? 3 : 2);
524                 buffer[i] = error_token;
525
526                 for (int j = i; j > 0; j--)
527                         buffer[j - 1] = lexStream.previous(buffer[j]);
528
529                 for (int k = i + 1; k < BUFF_SIZE; k++)
530                         buffer[k] = lexStream.next(buffer[k - 1]);
531
532                 //
533                 // If NEXT_STACK_TOP > 0 then the parse was successful on CURTOK
534                 // and the error was detected on the successor of CURTOK. In
535                 // that case, first check whether or not primary recovery is
536                 // possible on next_stack ...
537                 //
538                 if (nextStackTop >= 0) {
539                         repair.bufferPosition = 3;
540                         repair = checkPrimaryDistance(nextStack, nextStackTop, repair);
541                 }
542
543                 //
544                 // ... Next, try primary recovery on the current token...
545                 //
546                 PrimaryRepairInfo new_repair = repair.copy();
547
548                 new_repair.bufferPosition = 2;
549                 new_repair = checkPrimaryDistance(stack, stateStackTop, new_repair);
550                 if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
551                         repair = new_repair;
552                 }
553
554                 //
555                 // Finally, if prev_stack_top >= 0 then try primary recovery on
556                 // the prev_stack configuration.
557                 //
558                 
559                 if (prevStackTop >= 0) {
560                         new_repair = repair.copy();
561                         new_repair.bufferPosition = 1;
562                         new_repair = checkPrimaryDistance(prevStack,prevStackTop, new_repair);
563                         if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) {
564                                 repair = new_repair;
565                         }
566                 }
567
568                 //
569                 // Before accepting the best primary phase recovery obtained,
570                 // ensure that we cannot do better with a similar secondary
571                 // phase recovery.
572                 //
573                 if (nextStackTop >= 0) {// next_stack available
574                         if (secondaryCheck(nextStack,nextStackTop,3,repair.distance)) {
575                                 return candidate;
576                         }
577                 }
578                 else if (secondaryCheck(stack, stateStackTop, 2, repair.distance)) {
579                         return candidate;
580                 }
581
582                 //
583                 // First, adjust distance if the recovery is on the error token;
584                 // it is important that the adjustment be made here and not at
585                 // each primary trial to prevent the distance tests from being
586                 // biased in favor of deferred recoveries which have access to
587                 // more input tokens...
588                 //
589                 repair.distance = repair.distance - repair.bufferPosition + 1;
590
591                 //
592                 // ...Next, adjust the distance if the recovery is a deletion or
593                 // (some form of) substitution...
594                 //
595                 if (repair.code == INVALID_CODE      ||
596                         repair.code == DELETION_CODE     ||
597                         repair.code == SUBSTITUTION_CODE ||
598                         repair.code == MERGE_CODE) {
599                          repair.distance--;
600                 }
601
602                 //
603                 // ... After adjustment, check if the most successful primary
604                 // recovery can be applied.  If not, continue with more radical
605                 // recoveries...
606                 //
607                 if (repair.distance < MIN_DISTANCE) {
608                         return candidate;
609                 }
610
611                 //
612                 // When processing an insertion error, if the token preceeding
613                 // the error token is not available, we change the repair code
614                 // into a BEFORE_CODE to instruct the reporting routine that it
615                 // indicates that the repair symbol should be inserted before
616                 // the error token.
617                 //
618                 if (repair.code == INSERTION_CODE) {
619                         if (buffer[repair.bufferPosition - 1] == 0) {
620                                 repair.code = BEFORE_CODE;
621                         }
622                 }
623
624                 //
625                 // Select the proper sequence of states on which to recover,
626                 // update stack accordingly and call diagnostic routine.
627                 //
628                 if (repair.bufferPosition == 1) {
629                         stateStackTop = prevStackTop;
630                         for (int j = 0; j <= stateStackTop; j++) {
631                                 stack[j] = prevStack[j];
632                         }
633                 } else if (nextStackTop >= 0 && repair.bufferPosition >= 3) {
634                         stateStackTop = nextStackTop;
635                         for (int j = 0; j <= stateStackTop; j++) {
636                                 stack[j] = nextStack[j];
637                         }
638                         locationStack[stateStackTop] = buffer[3];
639                         locationStartStack[stateStackTop] = lexStream.start(buffer[3]);
640                 }
641
642                 return primaryDiagnosis(repair);
643         }
644
645
646 //
647 //                 This function checks whether or not a given state has a
648 //         candidate, whose string representaion is a merging of the two
649 //         tokens at positions buffer_position and buffer_position+1 in
650 //         the buffer.  If so, it returns the candidate in question;
651 //         otherwise it returns 0.
652 //
653         private int mergeCandidate(int state, int buffer_position) {
654                 char[] name1 = lexStream.name(buffer[buffer_position]);
655                 char[] name2 = lexStream.name(buffer[buffer_position + 1]);
656                 
657                 int len  = name1.length + name2.length;
658
659                 char[] str = CharOperation.concat(name1, name2);
660
661                 for (int k = Parser.asi(state); Parser.asr[k] != 0; k++) {
662                         int l = Parser.terminal_index[Parser.asr[k]];
663
664                         if (len == Parser.name[l].length()) {
665                                 char[] name = Parser.name[l].toCharArray();
666
667                                 if (CharOperation.equals(str, name, false)) {
668                                         return Parser.asr[k];
669                                 }
670                         }
671                 }
672
673                 return 0;
674         }
675
676
677 //
678 //         This procedure takes as arguments a parsing configuration
679 //         consisting of a state stack (stack and stack_top) and a fixed
680 //         number of input tokens (starting at buffer_position) in the
681 //         input BUFFER; and some reference arguments: repair_code,
682 //         distance, misspell_index, candidate, and stack_position
683 //         which it sets based on the best possible recovery that it
684 //         finds in the given configuration.  The effectiveness of a
685 //         a repair is judged based on two criteria:
686 //
687 //               1) the number of tokens that can be parsed after the repair
688 //                      is applied: distance.
689 //               2) how close to perfection is the candidate that is chosen:
690 //                      misspell_index.
691 //         When this procedure is entered, distance, misspell_index and
692 //         repair_code are assumed to be initialized.
693 //
694         private PrimaryRepairInfo checkPrimaryDistance(int stck[], int stack_top, PrimaryRepairInfo repair) {
695                 int i, j, k, next_state, max_pos, act, root, symbol, tok;
696
697                 //
698             //  First, try scope and manual recovery.
699             //
700             PrimaryRepairInfo scope_repair = scopeTrial(stck, stack_top, repair.copy());
701             if (scope_repair.distance > repair.distance)
702                 repair = scope_repair;
703                 
704                 //
705                 //  Next, try merging the error token with its successor.
706                 //
707             if(buffer[repair.bufferPosition] != 0 && buffer[repair.bufferPosition + 1] != 0) {// do not merge the first token
708                         symbol = mergeCandidate(stck[stack_top], repair.bufferPosition);
709                         if (symbol != 0) {
710                                 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+2);
711                                 if ((j > repair.distance) || (j == repair.distance && repair.misspellIndex < 10)) {
712                                         repair.misspellIndex = 10;
713                                         repair.symbol = symbol;
714                                         repair.distance = j;
715                                         repair.code = MERGE_CODE;
716                                 }
717                         }
718             }
719
720                 //
721                 // Next, try deletion of the error token.
722                 //
723                 j = parseCheck(
724                                 stck,
725                                 stack_top,
726                                 lexStream.kind(buffer[repair.bufferPosition + 1]),
727                                 repair.bufferPosition + 2);
728                 if (lexStream.kind(buffer[repair.bufferPosition]) == EOLT_SYMBOL &&
729                         lexStream.afterEol(buffer[repair.bufferPosition+1])) {
730                          k = 10;
731                 } else {
732                         k = 0;
733                 }
734                 if (j > repair.distance || (j == repair.distance && k > repair.misspellIndex)) {
735                         repair.misspellIndex = k;
736                         repair.code = DELETION_CODE;
737                         repair.distance = j;
738                 }
739
740                 //
741                 // Update the error configuration by simulating all reduce and
742                 // goto actions induced by the error token. Then assign the top
743                 // most state of the new configuration to next_state.
744                 //
745                 next_state = stck[stack_top];
746                 max_pos = stack_top;
747                 tempStackTop = stack_top - 1;
748
749                 tok = lexStream.kind(buffer[repair.bufferPosition]);
750                 lexStream.reset(buffer[repair.bufferPosition + 1]);
751                 act = Parser.tAction(next_state, tok);
752                 while(act <= NUM_RULES) {
753                         do {
754                                 tempStackTop -= (Parser.rhs[act]-1);
755                                 symbol = Parser.lhs[act];
756                                 act = (tempStackTop > max_pos
757                                                                           ? tempStack[tempStackTop]
758                                                                           : stck[tempStackTop]);
759                                 act = Parser.ntAction(act, symbol);
760                         } while(act <= NUM_RULES);
761                         max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
762                         tempStack[tempStackTop + 1] = act;
763                         next_state = act;
764                         act = Parser.tAction(next_state, tok);
765                 }
766
767                 //
768                 //  Next, place the list of candidates in proper order.
769                 //
770                 root = 0;
771                 for (i = Parser.asi(next_state); Parser.asr[i] != 0; i++) {
772                         symbol = Parser.asr[i];
773                         if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL) {
774                                 if (root == 0) {
775                                         list[symbol] = symbol;
776                                 } else {
777                                         list[symbol] = list[root];
778                                         list[root] = symbol;
779                                 }
780                                 root = symbol;
781                         }
782                 }
783
784                 if (stck[stack_top] != next_state) {
785                         for (i = Parser.asi(stck[stack_top]); Parser.asr[i] != 0; i++) {
786                                 symbol = Parser.asr[i];
787                                 if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL && list[symbol] == 0) {
788                                         if (root == 0) {
789                                                 list[symbol] = symbol;
790                                         } else {
791                                                 list[symbol] = list[root];
792                                                 list[root] = symbol;
793                                         }
794                                         root = symbol;
795                                 }
796                         }
797                 }
798
799                 i = list[root];
800                 list[root] = 0;
801                 root = i;
802
803                 //
804                 //  Next, try insertion for each possible candidate available in
805                 // the current state, except EOFT and ERROR_SYMBOL.
806                 //
807                 symbol = root;
808                 while(symbol != 0) {
809                         if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition])) {
810                                 k = 10;
811                         } else {
812                                 k = 0;
813                         }
814                         j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
815                         if (j > repair.distance) {
816                                 repair.misspellIndex = k;
817                                 repair.distance = j;
818                                 repair.symbol = symbol;
819                                 repair.code = INSERTION_CODE;
820                         } else if (j == repair.distance && k > repair.misspellIndex) {
821                                 repair.misspellIndex = k;
822                                 repair.distance = j;
823                                 repair.symbol = symbol;
824                                 repair.code = INSERTION_CODE;
825                         } else if (j == repair.distance && k == repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
826                                 repair.misspellIndex = k;
827                                 repair.distance = j;
828                                 repair.symbol = symbol;
829                                 repair.code = INSERTION_CODE;
830                         }
831
832                         symbol = list[symbol];
833                 }
834
835                 //
836                 //  Next, Try substitution for each possible candidate available
837                 // in the current state, except EOFT and ERROR_SYMBOL.
838                 //
839                 symbol = root;
840                 
841                 if(buffer[repair.bufferPosition] != 0) {// do not replace the first token
842                         while(symbol != 0) {
843                                 if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition+1])) {
844                                         k = 10;
845                                 } else {
846                                         k = misspell(symbol, buffer[repair.bufferPosition]);
847                                 }
848                                 j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
849                                 if (j > repair.distance) {
850                                         repair.misspellIndex = k;
851                                         repair.distance = j;
852                                         repair.symbol = symbol;
853                                         repair.code = SUBSTITUTION_CODE;
854                                 } else if (j == repair.distance && k > repair.misspellIndex) {
855                                         repair.misspellIndex = k;
856                                         repair.symbol = symbol;
857                                         repair.code = SUBSTITUTION_CODE;
858                                 } else if (j == repair.distance && k > repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) {
859                                         repair.misspellIndex = k;
860                                         repair.symbol = symbol;
861                                         repair.code = SUBSTITUTION_CODE;
862                                 }
863                                 i = symbol;
864                                 symbol = list[symbol];
865                                 list[i] = 0;                             // reset element
866                         }
867                 }
868
869
870                 //
871                 // Next, we try to insert a nonterminal candidate in front of the
872                 // error token, or substituting a nonterminal candidate for the
873                 // error token. Precedence is given to insertion.
874                 //
875                  for (i = Parser.nasi(stck[stack_top]); Parser.nasr[i] != 0; i++) {
876                          symbol = Parser.nasr[i] + NT_OFFSET;
877                          j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1);
878                          if (j > repair.distance) {
879                                  repair.misspellIndex = 0;
880                                  repair.distance = j;
881                                  repair.symbol = symbol;
882                                  repair.code = INVALID_CODE;
883                          }
884
885                          j = parseCheck(stck, stack_top, symbol, repair.bufferPosition);
886                          if ((j > repair.distance) || (j == repair.distance && repair.code == INVALID_CODE)) {
887                                  repair.misspellIndex = 0;
888                                  repair.distance = j;
889                                  repair.symbol = symbol;
890                                  repair.code = INSERTION_CODE;
891                          }
892                  }
893
894                 return repair;
895         }
896
897
898 //
899 //         This procedure is invoked to issue a diagnostic message and
900 //         adjust the input buffer.  The recovery in question is either
901 //         the insertion of one or more scopes, the merging of the error
902 //         token with its successor, the deletion of the error token,
903 //         the insertion of a single token in front of the error token
904 //         or the substitution of another token for the error token.
905 //
906         private RepairCandidate primaryDiagnosis(PrimaryRepairInfo repair) {
907                 int name_index;
908
909                 //
910                 //  Issue diagnostic.
911                 //
912                 int prevtok = buffer[repair.bufferPosition - 1];
913                 int     curtok  = buffer[repair.bufferPosition];
914
915                 switch(repair.code) {
916                         case INSERTION_CODE:
917                         case BEFORE_CODE: {
918                                 if (repair.symbol > NT_OFFSET)
919                                          name_index = getNtermIndex(stack[stateStackTop],
920                                                                                                 repair.symbol,
921                                                                                                 repair.bufferPosition);
922                                 else name_index = getTermIndex(stack,
923                                                                                            stateStackTop,
924                                                                                            repair.symbol,
925                                                                                            repair.bufferPosition);
926
927                                 int t = (repair.code == INSERTION_CODE ? prevtok : curtok);
928                                 reportError(repair.code, name_index, t, t);
929                                 break;
930                         }
931                         case INVALID_CODE: {
932                                 name_index = getNtermIndex(stack[stateStackTop],
933                                                                                    repair.symbol,
934                                                                                    repair.bufferPosition + 1);
935                                 reportError(repair.code, name_index, curtok, curtok);
936                                 break;
937                         }
938                         case SUBSTITUTION_CODE: {
939                                 if (repair.misspellIndex >= 6)
940                                         name_index = Parser.terminal_index[repair.symbol];
941                                 else
942                                 {
943                                         name_index = getTermIndex(stack, stateStackTop,
944                                                                                           repair.symbol,
945                                                                                           repair.bufferPosition + 1);
946                                         if (name_index != Parser.terminal_index[repair.symbol])
947                                                 repair.code = INVALID_CODE;
948                                 }
949                                 reportError(repair.code, name_index, curtok, curtok);
950                                 break;
951                         }
952                         case MERGE_CODE: {
953                                 reportError(repair.code,
954                                                          Parser.terminal_index[repair.symbol],
955                                                          curtok,
956                                                          lexStream.next(curtok));
957                                 break;
958                         }
959                         case SCOPE_CODE: {
960                     for (int i = 0; i < scopeStackTop; i++) {
961                         reportError(repair.code,
962                                     -scopeIndex[i],
963                                     locationStack[scopePosition[i]],
964                                     prevtok,
965                                     Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
966                     }
967         
968                     repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
969                     stateStackTop = scopePosition[scopeStackTop];
970                     reportError(repair.code,
971                                 -scopeIndex[scopeStackTop],
972                                 locationStack[scopePosition[scopeStackTop]],
973                                 prevtok,
974                                 getNtermIndex(stack[stateStackTop],
975                                               repair.symbol,
976                                               repair.bufferPosition)
977                                );
978                     break;
979                 }
980                         default: {// deletion
981                                 reportError(repair.code, Parser.terminal_index[ERROR_SYMBOL], curtok, curtok);
982                         }
983                 }
984
985                 //
986                 //  Update buffer.
987                 //
988                 RepairCandidate candidate = new RepairCandidate();
989                 switch (repair.code) {
990                         case INSERTION_CODE:
991                         case BEFORE_CODE:
992                         case SCOPE_CODE: {
993                                 candidate.symbol = repair.symbol;
994                                 candidate.location = buffer[repair.bufferPosition];
995                                 lexStream.reset(buffer[repair.bufferPosition]);
996                                 break;
997                         }
998                         case INVALID_CODE:
999                         case SUBSTITUTION_CODE: {
1000                                 candidate.symbol = repair.symbol;
1001                                 candidate.location = buffer[repair.bufferPosition];
1002                                 lexStream.reset(buffer[repair.bufferPosition + 1]);
1003                                 break;
1004                         }
1005                         case MERGE_CODE: {
1006                                 candidate.symbol = repair.symbol;
1007                                 candidate.location = buffer[repair.bufferPosition];
1008                                 lexStream.reset(buffer[repair.bufferPosition + 2]);
1009                                 break;
1010                         }
1011                         default: {// deletion
1012                                 candidate.location = buffer[repair.bufferPosition + 1];
1013                                 candidate.symbol =
1014                                                   lexStream.kind(buffer[repair.bufferPosition + 1]);
1015                                 lexStream.reset(buffer[repair.bufferPosition + 2]);
1016                                 break;
1017                         }
1018                 }
1019
1020                 return candidate;
1021         }
1022
1023
1024 //
1025 //         This function takes as parameter an integer STACK_TOP that
1026 //         points to a STACK element containing the state on which a
1027 //         primary recovery will be made; the terminal candidate on which
1028 //         to recover; and an integer: buffer_position, which points to
1029 //         the position of the next input token in the BUFFER.  The
1030 //         parser is simulated until a shift (or shift-reduce) action
1031 //         is computed on the candidate.  Then we proceed to compute the
1032 //         the name index of the highest level nonterminal that can
1033 //         directly or indirectly produce the candidate.
1034 //
1035         private int getTermIndex(int stck[], int stack_top, int tok, int buffer_position) {
1036                 //
1037                 // Initialize stack index of temp_stack and initialize maximum
1038                 // position of state stack that is still useful.
1039                 //
1040                 int act = stck[stack_top],
1041                         max_pos = stack_top,
1042                         highest_symbol = tok;
1043
1044                 tempStackTop = stack_top - 1;
1045
1046                 //
1047                 // Compute all reduce and associated actions induced by the
1048                 // candidate until a SHIFT or SHIFT-REDUCE is computed. ERROR
1049                 // and ACCEPT actions cannot be computed on the candidate in
1050                 // this context, since we know that it is suitable for recovery.
1051                 //
1052                 lexStream.reset(buffer[buffer_position]);
1053                 act = Parser.tAction(act, tok);
1054                 while(act <= NUM_RULES) {
1055                         //
1056                         // Process all goto-reduce actions following reduction,
1057                         // until a goto action is computed ...
1058                         //
1059                         do {
1060                                 tempStackTop -= (Parser.rhs[act]-1);
1061                                 int lhs_symbol = Parser.lhs[act];
1062                                 act = (tempStackTop > max_pos
1063                                                                           ? tempStack[tempStackTop]
1064                                                                           : stck[tempStackTop]);
1065                                 act = Parser.ntAction(act, lhs_symbol);
1066                         } while(act <= NUM_RULES);
1067
1068                         //
1069                         // Compute new maximum useful position of (STATE_)stack,
1070                         // push goto state into the stack, and compute next
1071                         // action on candidate ...
1072                         //
1073                         max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1074                         tempStack[tempStackTop + 1] = act;
1075                         act = Parser.tAction(act, tok);
1076                 }
1077
1078                 //
1079                 // At this stage, we have simulated all actions induced by the
1080                 // candidate and we are ready to shift or shift-reduce it. First,
1081                 // set tok and next_ptr appropriately and identify the candidate
1082                 // as the initial highest_symbol. If a shift action was computed
1083                 // on the candidate, update the stack and compute the next
1084                 // action. Next, simulate all actions possible on the next input
1085                 // token until we either have to shift it or are about to reduce
1086                 // below the initial starting point in the stack (indicated by
1087                 // max_pos as computed in the previous loop).  At that point,
1088                 // return the highest_symbol computed.
1089                 //
1090                 tempStackTop++; // adjust top of stack to reflect last goto
1091                                                   // next move is shift or shift-reduce.
1092                 int threshold = tempStackTop;
1093
1094                 tok = lexStream.kind(buffer[buffer_position]);
1095                 lexStream.reset(buffer[buffer_position + 1]);
1096
1097                 if (act > ERROR_ACTION) {  // shift-reduce on candidate?
1098                         act -= ERROR_ACTION;
1099                 } else {
1100                         tempStack[tempStackTop + 1] = act;
1101                         act = Parser.tAction(act, tok);
1102                 }
1103
1104                 while(act <= NUM_RULES) {
1105                         //
1106                         // Process all goto-reduce actions following reduction,
1107                         // until a goto action is computed ...
1108                         //
1109                         do {
1110                                 tempStackTop -= (Parser.rhs[act]-1);
1111
1112                                 if (tempStackTop < threshold) {
1113                                         return (highest_symbol > NT_OFFSET
1114                                                  ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1115                                                  : Parser.terminal_index[highest_symbol]);
1116                                 }
1117
1118                                 int lhs_symbol = Parser.lhs[act];
1119                                 if (tempStackTop == threshold)
1120                                         highest_symbol = lhs_symbol + NT_OFFSET;
1121                                 act = (tempStackTop > max_pos
1122                                                                           ? tempStack[tempStackTop]
1123                                                                           : stck[tempStackTop]);
1124                                 act = Parser.ntAction(act, lhs_symbol);
1125                         } while(act <= NUM_RULES);
1126
1127                         tempStack[tempStackTop + 1] = act;
1128                         act = Parser.tAction(act, tok);
1129                 }
1130
1131                 return (highest_symbol > NT_OFFSET
1132                                                          ? Parser.non_terminal_index[highest_symbol - NT_OFFSET]
1133                                                          : Parser.terminal_index[highest_symbol]);
1134         }
1135
1136 //
1137 //         This function takes as parameter a starting state number:
1138 //         start, a nonterminal symbol, A (candidate), and an integer,
1139 //         buffer_position,  which points to the position of the next
1140 //         input token in the BUFFER.
1141 //         It returns the highest level non-terminal B such that
1142 //         B =>*rm A.  I.e., there does not exists a nonterminal C such
1143 //         that C =>+rm B. (Recall that for an LALR(k) grammar if
1144 //         C =>+rm B, it cannot be the case that B =>+rm C)
1145 //
1146         private int getNtermIndex(int start, int sym, int buffer_position) {
1147                 int highest_symbol = sym - NT_OFFSET,
1148                         tok = lexStream.kind(buffer[buffer_position]);
1149                 lexStream.reset(buffer[buffer_position + 1]);
1150
1151                 //
1152                 // Initialize stack index of temp_stack and initialize maximum
1153                 // position of state stack that is still useful.
1154                 //
1155                 tempStackTop = 0;
1156                 tempStack[tempStackTop] = start;
1157
1158                 int act = Parser.ntAction(start, highest_symbol);
1159                 if (act > NUM_RULES) { // goto action?
1160                         tempStack[tempStackTop + 1] = act;
1161                         act = Parser.tAction(act, tok);
1162                 }
1163
1164                 while(act <= NUM_RULES) {
1165                         //
1166                         // Process all goto-reduce actions following reduction,
1167                         // until a goto action is computed ...
1168                         //
1169                         do {
1170                                 tempStackTop -= (Parser.rhs[act]-1);
1171                                 if (tempStackTop < 0)
1172                                         return Parser.non_terminal_index[highest_symbol];
1173                                 if (tempStackTop == 0)
1174                                         highest_symbol = Parser.lhs[act];
1175                                 act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]);
1176                         } while(act <= NUM_RULES);
1177                         tempStack[tempStackTop + 1] = act;
1178                         act = Parser.tAction(act, tok);
1179                 }
1180
1181                 return Parser.non_terminal_index[highest_symbol];
1182         }
1183
1184         private boolean isBetterSymbol(int symbol, int actualSymbol) {
1185 //              switch (actualSymbol) {
1186 //                      case TokenNameinterface :
1187 //                              if(symbol == TokenNameclass) {
1188 //                                      return true;
1189 //                              }
1190 //                              break;
1191 //              }
1192                 return false;
1193         }
1194
1195 //
1196 //                 Check whether or not there is a high probability that a
1197 //         given string is a misspelling of another.
1198 //         Certain singleton symbols (such as ":" and ";") are also
1199 //         considered to be misspelling of each other.
1200 //
1201         private int misspell(int sym, int tok) {
1202                 
1203
1204                 //
1205                 //
1206                 //
1207                 char[] name = Parser.name[Parser.terminal_index[sym]].toCharArray();
1208                 int n = name.length;
1209                 char[] s1 = new char[n + 1];
1210                 for (int k = 0; k < n; k++) {
1211                         char c = name[k];
1212                         s1[k] = Character.toLowerCase(c);
1213                 }
1214                 s1[n] = '\0';
1215
1216                 //
1217                 //
1218                 //
1219                 char[] tokenName = lexStream.name(tok);
1220                 int len = tokenName.length;
1221                 int m = len < MAX_NAME_LENGTH ? len : MAX_NAME_LENGTH;
1222                 char[] s2 = new char[m + 1];
1223                 for (int k = 0; k < m; k++) {
1224                         char c = tokenName[k];
1225                         s2[k] = Character.toLowerCase(c);
1226                 }
1227                 s2[m] = '\0';
1228
1229                 //
1230                 //  Singleton mispellings:
1231                 //
1232                 //  ;      <---->     ,
1233                 //
1234                 //  ;      <---->     :
1235                 //
1236                 //  .      <---->     ,
1237                 //
1238                 //  '      <---->     "
1239                 //
1240                 //
1241                 if (n == 1  &&  m == 1) {
1242                         if ((s1[0] == ';'  &&  s2[0] == ',')  ||
1243                                 (s1[0] == ','  &&  s2[0] == ';')  ||
1244                                 (s1[0] == ';'  &&  s2[0] == ':')  ||
1245                                 (s1[0] == ':'  &&  s2[0] == ';')  ||
1246                                 (s1[0] == '.'  &&  s2[0] == ',')  ||
1247                                 (s1[0] == ','  &&  s2[0] == '.')  ||
1248                                 (s1[0] == '\'' &&  s2[0] == '\"')  ||
1249                                 (s1[0] == '\"'  &&  s2[0] == '\'')) {
1250                                         return 3;
1251                         }
1252                 }
1253
1254                 //
1255                 // Scan the two strings. Increment "match" count for each match.
1256                 // When a transposition is encountered, increase "match" count
1257                 // by two but count it as an error. When a typo is found, skip
1258                 // it and count it as an error. Otherwise we have a mismatch; if
1259                 // one of the strings is longer, increment its index, otherwise,
1260                 // increment both indices and continue.
1261                 //
1262                 // This algorithm is an adaptation of a boolean misspelling
1263                 // algorithm proposed by Juergen Uhl.
1264                 //
1265                 int count = 0;
1266                 int prefix_length = 0;
1267                 int num_errors = 0;
1268
1269                 int i = 0;
1270                 int j = 0;
1271                 while ((i < n)  &&  (j < m)) {
1272                         if (s1[i] == s2[j]) {
1273                                 count++;
1274                                 i++;
1275                                 j++;
1276                                 if (num_errors == 0) {
1277                                         prefix_length++;
1278                                 }
1279                         } else if (s1[i+1] == s2[j]  &&  s1[i] == s2[j+1]) {
1280                                 count += 2;
1281                                 i += 2;
1282                                 j += 2;
1283                                 num_errors++;
1284                         } else if (s1[i+1] == s2[j+1]) {
1285                                 i++;
1286                                 j++;
1287                                 num_errors++;
1288                         } else {
1289                                 if ((n - i) > (m - j)) {
1290                                          i++;
1291                                 } else if ((m - j) > (n - i)) {
1292                                          j++;
1293                                 } else {
1294                                         i++;
1295                                         j++;
1296                                 }
1297                                 num_errors++;
1298                         }
1299                 }
1300
1301                 if (i < n  ||  j < m)
1302                         num_errors++;
1303
1304                 if (num_errors > ((n < m ? n : m) / 6 + 1))
1305                          count = prefix_length;
1306
1307                 return(count * 10 / ((n < len ? len : n) + num_errors));
1308         }
1309         
1310         private PrimaryRepairInfo scopeTrial(int stck[], int stack_top, PrimaryRepairInfo repair) {
1311             stateSeen = new int[stackLength];
1312             for (int i = 0; i < stackLength; i++)
1313                 stateSeen[i] = NIL;
1314             
1315             statePoolTop = 0;
1316             statePool = new StateInfo[stackLength];
1317         
1318             scopeTrialCheck(stck, stack_top, repair, 0);
1319         
1320             stateSeen = null;
1321             statePoolTop = 0;
1322         
1323             repair.code = SCOPE_CODE;
1324             repair.misspellIndex = 10;
1325         
1326             return repair;
1327         }
1328         
1329         private void scopeTrialCheck(int stck[], int stack_top, PrimaryRepairInfo repair, int indx) {
1330                 if(indx > 20) return; // avoid too much recursive call to improve performance
1331                 
1332                 int act = stck[stack_top];
1333         
1334             for (int i = stateSeen[stack_top]; i != NIL; i = statePool[i].next) {
1335                 if (statePool[i].state == act) return;
1336             }
1337
1338             int old_state_pool_top = statePoolTop++;
1339             if(statePoolTop >= statePool.length) {
1340                 System.arraycopy(statePool, 0, statePool = new StateInfo[statePoolTop * 2], 0, statePoolTop);
1341             }
1342             
1343             statePool[old_state_pool_top] = new StateInfo(act, stateSeen[stack_top]);
1344             stateSeen[stack_top] = old_state_pool_top;
1345         
1346             for (int i = 0; i < SCOPE_SIZE; i++) {
1347                 //
1348                 // Use the scope lookahead symbol to force all reductions
1349                 // inducible by that symbol.
1350                 //
1351                 act = stck[stack_top];
1352                 tempStackTop = stack_top - 1;
1353                 int max_pos = stack_top;
1354                 int tok = Parser.scope_la[i];
1355                 lexStream.reset(buffer[repair.bufferPosition]);
1356                 act = Parser.tAction(act, tok);
1357                 while(act <= NUM_RULES) {
1358                     //
1359                     // ... Process all goto-reduce actions following
1360                     // reduction, until a goto action is computed ...
1361                     //
1362                     do  {
1363                         tempStackTop -= (Parser.rhs[act]-1);
1364                         int lhs_symbol = Parser.lhs[act];
1365                         act =  (tempStackTop > max_pos
1366                                     ?  tempStack[tempStackTop]
1367                                     :  stck[tempStackTop]);
1368                         act = Parser.ntAction(act, lhs_symbol);
1369                     }  while(act <= NUM_RULES);
1370                     if (tempStackTop + 1 >= stackLength)
1371                         return;
1372                     max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1373                     tempStack[tempStackTop + 1] = act;
1374                     act = Parser.tAction(act, tok);
1375                 }
1376         
1377                 //
1378                 // If the lookahead symbol is parsable, then we check
1379                 // whether or not we have a match between the scope
1380                 // prefix and the transition symbols corresponding to
1381                 // the states on top of the stack.
1382                 //
1383                 if (act != ERROR_ACTION) {
1384                         int j, k;
1385                     k = Parser.scope_prefix[i];
1386                     for (j = tempStackTop + 1;
1387                          j >= (max_pos + 1) &&
1388                          Parser.in_symbol(tempStack[j]) == Parser.scope_rhs[k]; j--) {
1389                          k++;
1390                     }
1391                     if (j == max_pos) {
1392                         for (j = max_pos;
1393                              j >= 1 && Parser.in_symbol(stck[j]) == Parser.scope_rhs[k];
1394                              j--) {
1395                             k++;
1396                         }
1397                     }
1398                     //
1399                     // If the prefix matches, check whether the state
1400                     // newly exposed on top of the stack, (after the
1401                     // corresponding prefix states are popped from the
1402                     // stack), is in the set of "source states" for the
1403                     // scope in question and that it is at a position
1404                     // below the threshold indicated by MARKED_POS.
1405                     //
1406                     int marked_pos = (max_pos < stack_top ? max_pos + 1 : stack_top);
1407                     if (Parser.scope_rhs[k] == 0 && j < marked_pos) { // match?
1408                         int stack_position = j;
1409                         for (j = Parser.scope_state_set[i];
1410                              stck[stack_position] != Parser.scope_state[j] &&
1411                              Parser.scope_state[j] != 0;
1412                              j++){/*empty*/}
1413                         //
1414                         // If the top state is valid for scope recovery,
1415                         // the left-hand side of the scope is used as
1416                         // starting symbol and we calculate how far the
1417                         // parser can advance within the forward context
1418                         // after parsing the left-hand symbol.
1419                         //
1420                         if (Parser.scope_state[j] != 0) {     // state was found
1421                             int previous_distance = repair.distance;
1422                             int distance = parseCheck(stck,
1423                                                   stack_position,
1424                                                   Parser.scope_lhs[i]+NT_OFFSET,
1425                                                   repair.bufferPosition);
1426                             //
1427                             // if the recovery is not successful, we
1428                             // update the stack with all actions induced
1429                             // by the left-hand symbol, and recursively
1430                             // call SCOPE_TRIAL_CHECK to try again.
1431                             // Otherwise, the recovery is successful. If
1432                             // the new distance is greater than the
1433                             // initial SCOPE_DISTANCE, we update
1434                             // SCOPE_DISTANCE and set scope_stack_top to INDX
1435                             // to indicate the number of scopes that are
1436                             // to be applied for a succesful  recovery.
1437                             // NOTE that this procedure cannot get into
1438                             // an infinite loop, since each prefix match
1439                             // is guaranteed to take us to a lower point
1440                             // within the stack.
1441                             //
1442                             if ((distance - repair.bufferPosition + 1) < MIN_DISTANCE) {
1443                                 int top = stack_position;
1444                                 act = Parser.ntAction(stck[top], Parser.scope_lhs[i]);
1445                                 while(act <= NUM_RULES) {
1446                                     top -= (Parser.rhs[act]-1);
1447                                     act = Parser.ntAction(stck[top], Parser.lhs[act]);
1448                                 }
1449                                 top++;
1450         
1451                                 j = act;
1452                                 act = stck[top];  // save
1453                                 stck[top] = j;    // swap
1454                                 scopeTrialCheck(stck, top, repair, indx+1);
1455                                 stck[top] = act; // restore
1456                             } else if (distance > repair.distance) {
1457                                 scopeStackTop = indx;
1458                                 repair.distance = distance;
1459                             }
1460         
1461                             if (lexStream.kind(buffer[repair.bufferPosition]) == EOFT_SYMBOL &&
1462                                 repair.distance == previous_distance) {
1463                                 scopeStackTop = indx;
1464                                 repair.distance = MAX_DISTANCE;
1465                             }
1466         
1467                             //
1468                             // If this scope recovery has beaten the
1469                             // previous distance, then we have found a
1470                             // better recovery (or this recovery is one
1471                             // of a list of scope recoveries). Record
1472                             // its information at the proper location
1473                             // (INDX) in SCOPE_INDEX and SCOPE_STACK.
1474                             //
1475                             if (repair.distance > previous_distance) {
1476                                 scopeIndex[indx] = i;
1477                                 scopePosition[indx] = stack_position;
1478                                 return;
1479                             }
1480                         }
1481                     }
1482                 }
1483             }
1484         }
1485 //
1486 //         This function computes the ParseCheck distance for the best
1487 //         possible secondary recovery for a given configuration that
1488 //         either deletes none or only one symbol in the forward context.
1489 //         If the recovery found is more effective than the best primary
1490 //         recovery previously computed, then the function returns true.
1491 //         Only misplacement, scope and manual recoveries are attempted;
1492 //         simple insertion or substitution of a nonterminal are tried
1493 //         in CHECK_PRIMARY_DISTANCE as part of primary recovery.
1494 //
1495         private boolean secondaryCheck(int stck[], int stack_top, int buffer_position, int distance) {
1496                 int top, j;
1497
1498                 for (top = stack_top - 1; top >= 0; top--) {
1499                         j = parseCheck(stck, top,
1500                                                    lexStream.kind(buffer[buffer_position]),
1501                                                    buffer_position + 1);
1502                         if (((j - buffer_position + 1) > MIN_DISTANCE) && (j > distance))
1503                                 return true;
1504                 }
1505                 
1506                 PrimaryRepairInfo repair = new PrimaryRepairInfo();
1507             repair.bufferPosition = buffer_position + 1;
1508             repair.distance = distance;
1509             repair = scopeTrial(stck, stack_top, repair);
1510             if ((repair.distance - buffer_position) > MIN_DISTANCE && repair.distance > distance)
1511                  return true;
1512                 return false;
1513         }
1514
1515
1516 //
1517 //         Secondary_phase is a boolean function that checks whether or
1518 //         not some form of secondary recovery is applicable to one of
1519 //         the error configurations. First, if "next_stack" is available,
1520 //         misplacement and secondary recoveries are attempted on it.
1521 //         Then, in any case, these recoveries are attempted on "stack".
1522 //         If a successful recovery is found, a diagnosis is issued, the
1523 //         configuration is updated and the function returns "true".
1524 //         Otherwise, the function returns false.
1525 //
1526         private RepairCandidate secondaryPhase(int error_token) {
1527                 SecondaryRepairInfo repair = new SecondaryRepairInfo();
1528                 SecondaryRepairInfo misplaced = new SecondaryRepairInfo();
1529
1530                 RepairCandidate candidate = new RepairCandidate();
1531
1532                 int i, j, k, top;
1533                 int     next_last_index = 0;
1534                 int     last_index;
1535
1536                 candidate.symbol = 0;
1537
1538                 repair.code = 0;
1539                 repair.distance = 0;
1540                 repair.recoveryOnNextStack = false;
1541
1542                 misplaced.distance = 0;
1543                 misplaced.recoveryOnNextStack = false;
1544
1545                 //
1546                 // If the next_stack is available, try misplaced and secondary
1547                 // recovery on it first.
1548                 //
1549                 if (nextStackTop >= 0) {
1550                         int  save_location;
1551
1552                         buffer[2] = error_token;
1553                         buffer[1] = lexStream.previous(buffer[2]);
1554                         buffer[0] = lexStream.previous(buffer[1]);
1555
1556                         for (k = 3; k < BUFF_UBOUND; k++)
1557                                 buffer[k] = lexStream.next(buffer[k - 1]);
1558
1559                         buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1560
1561                         //
1562                         // If we are at the end of the input stream, compute the
1563                         // index position of the first EOFT symbol (last useful
1564                         // index).
1565                         //
1566                         for (next_last_index = MAX_DISTANCE - 1;
1567                                  next_last_index >= 1 &&
1568                                  lexStream.kind(buffer[next_last_index]) == EOFT_SYMBOL;
1569                                  next_last_index--){/*empty*/}
1570                         next_last_index = next_last_index + 1;
1571
1572                         save_location = locationStack[nextStackTop];
1573                         int save_location_start = locationStartStack[nextStackTop];
1574                         locationStack[nextStackTop] = buffer[2];
1575                         locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1576                         misplaced.numDeletions = nextStackTop;
1577                         misplaced = misplacementRecovery(nextStack, nextStackTop,
1578                                                                                          next_last_index,
1579                                                                                          misplaced, true);
1580                         if (misplaced.recoveryOnNextStack)
1581                                 misplaced.distance++;
1582
1583                         repair.numDeletions = nextStackTop + BUFF_UBOUND;
1584                         repair = secondaryRecovery(nextStack, nextStackTop,
1585                                                                            next_last_index,
1586                                                                            repair, true);
1587                         if (repair.recoveryOnNextStack)
1588                                 repair.distance++;
1589
1590                         locationStack[nextStackTop] = save_location;
1591                         locationStartStack[nextStackTop] = save_location_start;
1592                 } else {            // next_stack not available, initialize ...
1593                         misplaced.numDeletions = stateStackTop;
1594                         repair.numDeletions = stateStackTop + BUFF_UBOUND;
1595                 }
1596
1597                 //
1598                 // Try secondary recovery on the "stack" configuration.
1599                 //
1600                 buffer[3] = error_token;
1601
1602                 buffer[2] = lexStream.previous(buffer[3]);
1603                 buffer[1] = lexStream.previous(buffer[2]);
1604                 buffer[0] = lexStream.previous(buffer[1]);
1605
1606                 for (k = 4; k < BUFF_SIZE; k++)
1607                         buffer[k] = lexStream.next(buffer[k - 1]);
1608
1609                 for (last_index = MAX_DISTANCE - 1;
1610                          last_index >= 1 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL;
1611                          last_index--){/*empty*/}
1612                 last_index++;
1613
1614                 misplaced = misplacementRecovery(stack, stateStackTop,
1615                                                                                  last_index,
1616                                                                                  misplaced, false);
1617
1618                 repair = secondaryRecovery(stack, stateStackTop,
1619                                                                    last_index, repair, false);
1620
1621                 //
1622                 // If a successful misplaced recovery was found, compare it with
1623                 // the most successful secondary recovery.  If the misplaced
1624                 // recovery either deletes fewer symbols or parse-checks further
1625                 // then it is chosen.
1626                 //
1627                 if (misplaced.distance > MIN_DISTANCE) {
1628                         if (misplaced.numDeletions <= repair.numDeletions ||
1629                            (misplaced.distance - misplaced.numDeletions) >=
1630                            (repair.distance - repair.numDeletions)) {
1631                                 repair.code = MISPLACED_CODE;
1632                                 repair.stackPosition = misplaced.stackPosition;
1633                                 repair.bufferPosition = 2;
1634                                 repair.numDeletions = misplaced.numDeletions;
1635                                 repair.distance = misplaced.distance;
1636                                 repair.recoveryOnNextStack = misplaced.recoveryOnNextStack;
1637                         }
1638                 }
1639
1640                 //
1641                 // If the successful recovery was on next_stack, update: stack,
1642                 // buffer, location_stack and last_index.
1643                 //
1644                 if (repair.recoveryOnNextStack) {
1645                         stateStackTop = nextStackTop;
1646                         for (i = 0; i <= stateStackTop; i++)
1647                                 stack[i] = nextStack[i];
1648
1649                         buffer[2] = error_token;
1650                         buffer[1] = lexStream.previous(buffer[2]);
1651                         buffer[0] = lexStream.previous(buffer[1]);
1652
1653                         for (k = 3; k < BUFF_UBOUND; k++)
1654                                 buffer[k] = lexStream.next(buffer[k - 1]);
1655
1656                         buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available
1657
1658                         locationStack[nextStackTop] = buffer[2];
1659                         locationStartStack[nextStackTop] = lexStream.start(buffer[2]);
1660                         last_index = next_last_index;
1661                 }
1662
1663             //
1664             // Next, try scope recoveries after deletion of one, two, three,
1665             // four ... buffer_position tokens from the input stream.
1666             //
1667             if (repair.code == SECONDARY_CODE || repair.code == DELETION_CODE) {
1668                 PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1669         
1670                 scope_repair.distance = 0;
1671                 for (scope_repair.bufferPosition = 2;
1672                      scope_repair.bufferPosition <= repair.bufferPosition &&
1673                      repair.code != SCOPE_CODE; scope_repair.bufferPosition++) {
1674                     scope_repair = scopeTrial(stack, stateStackTop, scope_repair);
1675                     j = (scope_repair.distance == MAX_DISTANCE
1676                                                 ? last_index
1677                                                 : scope_repair.distance);
1678                     k = scope_repair.bufferPosition - 1;
1679                     if ((j - k) > MIN_DISTANCE && (j - k) > (repair.distance - repair.numDeletions)) {
1680                         repair.code = SCOPE_CODE;
1681                         i = scopeIndex[scopeStackTop];       // upper bound
1682                         repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1683                         repair.stackPosition = stateStackTop;
1684                         repair.bufferPosition = scope_repair.bufferPosition;
1685                     }
1686                 }
1687             }
1688         
1689             //
1690             // If no successful recovery is found and we have reached the
1691             // end of the file, check whether or not scope recovery is
1692             // applicable at the end of the file after discarding some
1693             // states.
1694             //
1695             if (repair.code == 0 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL) {
1696                 PrimaryRepairInfo scope_repair = new PrimaryRepairInfo();
1697         
1698                 scope_repair.bufferPosition = last_index;
1699                 scope_repair.distance = 0;
1700                 for (top = stateStackTop;
1701                      top >= 0 && repair.code == 0; top--)
1702                 {
1703                     scope_repair = scopeTrial(stack, top, scope_repair);
1704                     if (scope_repair.distance > 0)
1705                     {
1706                         repair.code = SCOPE_CODE;
1707                         i = scopeIndex[scopeStackTop];    // upper bound
1708                         repair.symbol = Parser.scope_lhs[i] + NT_OFFSET;
1709                         repair.stackPosition = top;
1710                         repair.bufferPosition = scope_repair.bufferPosition;
1711                     }
1712                 }
1713             }
1714
1715                 //
1716                 // If a successful repair was not found, quit!  Otherwise, issue
1717                 // diagnosis and adjust configuration...
1718                 //
1719                 if (repair.code == 0)
1720                         return candidate;
1721
1722                 secondaryDiagnosis(repair);
1723
1724                 //
1725                 // Update buffer based on number of elements that are deleted.
1726                 //
1727                 switch(repair.code) {
1728                         case MISPLACED_CODE:
1729                                  candidate.location = buffer[2];
1730                                  candidate.symbol = lexStream.kind(buffer[2]);
1731                                  lexStream.reset(lexStream.next(buffer[2]));
1732
1733                                  break;
1734
1735                         case DELETION_CODE:
1736                                  candidate.location = buffer[repair.bufferPosition];
1737                                  candidate.symbol =
1738                                                    lexStream.kind(buffer[repair.bufferPosition]);
1739                                  lexStream.reset(lexStream.next(buffer[repair.bufferPosition]));
1740
1741                                  break;
1742
1743                 default: // SCOPE_CODE || SECONDARY_CODE
1744                                  candidate.symbol = repair.symbol;
1745                                  candidate.location = buffer[repair.bufferPosition];
1746                                  lexStream.reset(buffer[repair.bufferPosition]);
1747
1748                                  break;
1749                 }
1750
1751                 return candidate;
1752         }
1753
1754
1755 //
1756 //         This boolean function checks whether or not a given
1757 //         configuration yields a better misplacement recovery than
1758 //         the best misplacement recovery computed previously.
1759 //
1760         private SecondaryRepairInfo misplacementRecovery(int stck[], int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1761                 int  previous_loc = buffer[2];
1762                 int stack_deletions = 0;
1763
1764                 for (int top = stack_top - 1; top >= 0; top--) {
1765                         if (locationStack[top] < previous_loc) {
1766                                 stack_deletions++;
1767                         }
1768                         previous_loc = locationStack[top];
1769
1770                         int j = parseCheck(stck, top, lexStream.kind(buffer[2]), 3);
1771                         if (j == MAX_DISTANCE) {
1772                                  j = last_index;
1773                         }
1774                         if ((j > MIN_DISTANCE) && (j - stack_deletions) > (repair.distance - repair.numDeletions)) {
1775                                 repair.stackPosition = top;
1776                                 repair.distance = j;
1777                                 repair.numDeletions = stack_deletions;
1778                                 repair.recoveryOnNextStack = stack_flag;
1779                         }
1780                 }
1781
1782                 return repair;
1783         }
1784
1785
1786 //
1787 //         This boolean function checks whether or not a given
1788 //         configuration yields a better secondary recovery than the
1789 //         best misplacement recovery computed previously.
1790 //
1791         private SecondaryRepairInfo secondaryRecovery(int stck[],int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) {
1792                 int previous_loc;
1793                 int stack_deletions = 0;
1794                 
1795                 previous_loc = buffer[2];
1796                 for (int top = stack_top; top >= 0 && repair.numDeletions >= stack_deletions; top--) {
1797                         if (locationStack[top] < previous_loc) {
1798                                 stack_deletions++;
1799                         }
1800                         previous_loc = locationStack[top];
1801
1802                         for (int i = 2;
1803                                  i <= (last_index - MIN_DISTANCE + 1) &&
1804                                  (repair.numDeletions >= (stack_deletions + i - 1)); i++) {
1805                                 int j = parseCheck(stck, top, lexStream.kind(buffer[i]), i + 1);
1806
1807                                 if (j == MAX_DISTANCE) {
1808                                          j = last_index;
1809                                 }
1810                                 if ((j - i + 1) > MIN_DISTANCE) {
1811                                         int k = stack_deletions + i - 1;
1812                                         if ((k < repair.numDeletions) ||
1813                                                 (j - k) > (repair.distance - repair.numDeletions) ||
1814                                                 ((repair.code == SECONDARY_CODE) && (j - k) == (repair.distance - repair.numDeletions))) {
1815                                                 repair.code = DELETION_CODE;
1816                                                 repair.distance = j;
1817                                                 repair.stackPosition = top;
1818                                                 repair.bufferPosition = i;
1819                                                 repair.numDeletions = k;
1820                                                 repair.recoveryOnNextStack = stack_flag;
1821                                         }
1822                                 }
1823
1824                                 for (int l = Parser.nasi(stck[top]); l >= 0 && Parser.nasr[l] != 0; l++) {
1825                                         int symbol = Parser.nasr[l] + NT_OFFSET;
1826                                         j = parseCheck(stck, top, symbol, i);
1827                                         if (j == MAX_DISTANCE) {
1828                                                  j = last_index;
1829                                         }
1830                                         if ((j - i + 1) > MIN_DISTANCE) {
1831                                                 int k = stack_deletions + i - 1;
1832                                                 if (k < repair.numDeletions || (j - k) > (repair.distance - repair.numDeletions)) {
1833                                                         repair.code = SECONDARY_CODE;
1834                                                         repair.symbol = symbol;
1835                                                         repair.distance = j;
1836                                                         repair.stackPosition = top;
1837                                                         repair.bufferPosition = i;
1838                                                         repair.numDeletions = k;
1839                                                         repair.recoveryOnNextStack = stack_flag;
1840                                                 }
1841                                         }
1842                                 }
1843                         }
1844                 }
1845
1846                 return repair;
1847         }
1848
1849
1850 //
1851 //         This procedure is invoked to issue a secondary diagnosis and
1852 //         adjust the input buffer.  The recovery in question is either
1853 //         an automatic scope recovery, a manual scope recovery, a
1854 //         secondary substitution or a secondary deletion.
1855 //
1856         private void secondaryDiagnosis(SecondaryRepairInfo repair) {
1857                 switch(repair.code) {
1858                         case SCOPE_CODE: {
1859                     if (repair.stackPosition < stateStackTop) {
1860                         reportError(DELETION_CODE,
1861                                     Parser.terminal_index[ERROR_SYMBOL],
1862                                     locationStack[repair.stackPosition],
1863                                     buffer[1]);
1864                     }
1865                     for (int i = 0; i < scopeStackTop; i++) {
1866                         reportError(SCOPE_CODE,
1867                                     -scopeIndex[i],
1868                                     locationStack[scopePosition[i]],
1869                                     buffer[1],
1870                                     Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]);
1871                     }
1872         
1873                     repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET;
1874                     stateStackTop = scopePosition[scopeStackTop];
1875                     reportError(SCOPE_CODE,
1876                                 -scopeIndex[scopeStackTop],
1877                                 locationStack[scopePosition[scopeStackTop]],
1878                                 buffer[1],
1879                                 getNtermIndex(stack[stateStackTop],
1880                                               repair.symbol,
1881                                               repair.bufferPosition)
1882                                );
1883                     break;
1884                 }
1885                         default: {
1886                                 reportError(repair.code,
1887                                                         (repair.code == SECONDARY_CODE
1888                                                                                   ? getNtermIndex(stack[repair.stackPosition],
1889                                                                                                                   repair.symbol,
1890                                                                                                                   repair.bufferPosition)
1891                                                                                   : Parser.terminal_index[ERROR_SYMBOL]),
1892                                                         locationStack[repair.stackPosition],
1893                                                         buffer[repair.bufferPosition - 1]);
1894                                 stateStackTop = repair.stackPosition;
1895                         }
1896                 }
1897         }
1898
1899
1900
1901
1902 //
1903 //         Try to parse until first_token and all tokens in BUFFER have
1904 //         been consumed, or an error is encountered. Return the number
1905 //         of tokens that were expended before the parse blocked.
1906 //
1907         private int parseCheck(int stck[], int stack_top, int first_token, int buffer_position) {
1908                 int max_pos;
1909                 int indx;
1910                 int ct;
1911                 int act;
1912
1913                 //
1914                 // Initialize pointer for temp_stack and initialize maximum
1915                 // position of state stack that is still useful.
1916                 //
1917                 act = stck[stack_top];
1918                 if (first_token > NT_OFFSET) {
1919                         tempStackTop = stack_top;
1920                         if(DEBUG_PARSECHECK) {
1921                                 System.out.println(tempStackTop);
1922                         }
1923                         max_pos = stack_top;
1924                         indx = buffer_position;
1925                         ct = lexStream.kind(buffer[indx]);
1926                         lexStream.reset(lexStream.next(buffer[indx]));
1927                         int lhs_symbol = first_token - NT_OFFSET;
1928                         act = Parser.ntAction(act, lhs_symbol);
1929                         if (act <= NUM_RULES) {
1930                                 // same loop as 'process_non_terminal'
1931                                 do {
1932                                         tempStackTop -= (Parser.rhs[act]-1);
1933                                         
1934                                         if(DEBUG_PARSECHECK) {
1935                                                 System.out.print(tempStackTop);
1936                                                 System.out.print(" ("); //$NON-NLS-1$
1937                                                 System.out.print(-(Parser.rhs[act]-1));
1938                                                 System.out.print(") [max:"); //$NON-NLS-1$
1939                                                 System.out.print(max_pos);
1940                                                 System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
1941                                                 System.out.print(act);
1942                                                 System.out.print("\t"); //$NON-NLS-1$
1943                                                 System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
1944                                                 System.out.println();
1945                                         }
1946                                         
1947                                         if(Parser.rules_compliance[act] > this.options.sourceLevel) {
1948                                                 return 0;
1949                                         }
1950                                         lhs_symbol = Parser.lhs[act];
1951                                         act = (tempStackTop > max_pos
1952                                                                                   ? tempStack[tempStackTop]
1953                                                                                   : stck[tempStackTop]);
1954                                         act = Parser.ntAction(act, lhs_symbol);
1955                                 } while(act <= NUM_RULES);
1956         
1957                                 max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
1958                         }
1959                 } else {
1960                         tempStackTop = stack_top - 1;
1961                         
1962                         if(DEBUG_PARSECHECK) {
1963                                 System.out.println(tempStackTop);
1964                         }
1965                         
1966                         max_pos = tempStackTop;
1967                         indx = buffer_position - 1;
1968                         ct = first_token;
1969                         lexStream.reset(buffer[buffer_position]);
1970                 }
1971
1972                 process_terminal: for (;;) {
1973                         if(DEBUG_PARSECHECK) {
1974                                 System.out.print(tempStackTop + 1);
1975                                 System.out.print(" (+1) [max:"); //$NON-NLS-1$
1976                                 System.out.print(max_pos);
1977                                 System.out.print("]\tprocess_terminal    \t"); //$NON-NLS-1$
1978                                 System.out.print(ct);
1979                                 System.out.print("\t"); //$NON-NLS-1$
1980                                 System.out.print(Parser.name[Parser.terminal_index[ct]]);
1981                                 System.out.println();
1982                         }
1983                         
1984                         if (++tempStackTop >= stackLength)  // Stack overflow!!!
1985                                 return indx;
1986                         tempStack[tempStackTop] = act;
1987
1988                         act = Parser.tAction(act, ct);
1989
1990                         if (act <= NUM_RULES) {               // reduce action
1991                                 tempStackTop--;
1992                                 
1993                                 if(DEBUG_PARSECHECK) {
1994                                         System.out.print(tempStackTop);
1995                                         System.out.print(" (-1) [max:"); //$NON-NLS-1$
1996                                         System.out.print(max_pos);
1997                                         System.out.print("]\treduce"); //$NON-NLS-1$
1998                                         System.out.println();
1999                                 }
2000                         } else if (act < ACCEPT_ACTION ||     // shift action
2001                                          act > ERROR_ACTION) {        // shift-reduce action
2002                                 if (indx == MAX_DISTANCE)
2003                                         return indx;
2004                                 indx++;
2005                                 ct = lexStream.kind(buffer[indx]);
2006                                 lexStream.reset(lexStream.next(buffer[indx]));
2007                                 if (act > ERROR_ACTION) {
2008                                         act -= ERROR_ACTION;
2009                                         
2010                                         if(DEBUG_PARSECHECK) {
2011                                                 System.out.print(tempStackTop);
2012                                                 System.out.print("\tshift reduce"); //$NON-NLS-1$
2013                                                 System.out.println();
2014                                         }
2015                                 } else {
2016                                         if(DEBUG_PARSECHECK) {
2017                                                 System.out.println("\tshift"); //$NON-NLS-1$
2018                                         }
2019                                         continue process_terminal;
2020                                 }
2021                         } else if (act == ACCEPT_ACTION) {           // accept action
2022                                  return MAX_DISTANCE;
2023                         } else {
2024                                 return indx;                         // error action
2025                         }
2026
2027                         // same loop as first token initialization
2028                         process_non_terminal:
2029                         do {
2030                                 tempStackTop -= (Parser.rhs[act]-1);
2031                                 
2032                                 if(DEBUG_PARSECHECK) {
2033                                         System.out.print(tempStackTop);
2034                                         System.out.print(" ("); //$NON-NLS-1$
2035                                         System.out.print(-(Parser.rhs[act]-1));
2036                                         System.out.print(") [max:"); //$NON-NLS-1$
2037                                         System.out.print(max_pos);
2038                                         System.out.print("]\tprocess_non_terminal\t"); //$NON-NLS-1$
2039                                         System.out.print(act);
2040                                         System.out.print("\t"); //$NON-NLS-1$
2041                                         System.out.print(Parser.name[Parser.non_terminal_index[Parser.lhs[act]]]);
2042                                         System.out.println();
2043                                 }
2044                                 
2045                                 if(act <= NUM_RULES) {
2046                                         if(Parser.rules_compliance[act] > this.options.sourceLevel) {
2047                                                 return 0;
2048                                         }
2049                                 }
2050                                 int lhs_symbol = Parser.lhs[act];
2051                                 act = (tempStackTop > max_pos
2052                                                                           ? tempStack[tempStackTop]
2053                                                                           : stck[tempStackTop]);
2054                                 act = Parser.ntAction(act, lhs_symbol);
2055                         } while(act <= NUM_RULES);
2056
2057                         max_pos = max_pos < tempStackTop ? max_pos : tempStackTop;
2058                 } // process_terminal;
2059         }
2060         private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken) {
2061                 reportError(msgCode, nameIndex, leftToken, rightToken, 0);
2062         }
2063
2064         private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) {
2065                 int lToken = (leftToken > rightToken ? rightToken : leftToken);
2066
2067                 if (lToken < rightToken) {
2068                         reportSecondaryError(msgCode, nameIndex, lToken, rightToken, scopeNameIndex);
2069                 } else {
2070                         reportPrimaryError(msgCode, nameIndex, rightToken, scopeNameIndex);
2071                 }
2072         }
2073         private void reportPrimaryError(int msgCode, int nameIndex, int token, int scopeNameIndex) {
2074                 String name;
2075                 if (nameIndex >= 0) {
2076                         name = Parser.readableName[nameIndex];
2077                 } else {
2078                         name = EMPTY_STRING;
2079                 }
2080
2081                 int errorStart = lexStream.start(token);
2082                 int errorEnd = lexStream.end(token);
2083                 int currentKind = lexStream.kind(token);
2084                 String errorTokenName = Parser.name[Parser.terminal_index[lexStream.kind(token)]];
2085                 char[] errorTokenSource = lexStream.name(token);
2086
2087                 switch(msgCode) {
2088                         case BEFORE_CODE:
2089                                 problemReporter().parseErrorInsertBeforeToken(
2090                                         errorStart, 
2091                                         errorEnd, 
2092                                         currentKind,
2093                                         errorTokenSource, 
2094                                         errorTokenName, 
2095                                         name);
2096                                  break;
2097                         case INSERTION_CODE:
2098                                 problemReporter().parseErrorInsertAfterToken(
2099                                         errorStart, 
2100                                         errorEnd, 
2101                                         currentKind,
2102                                         errorTokenSource, 
2103                                         errorTokenName, 
2104                                         name);  
2105                                  break;
2106                         case DELETION_CODE:
2107                                 problemReporter().parseErrorDeleteToken(
2108                                         errorStart, 
2109                                         errorEnd, 
2110                                         currentKind,
2111                                         errorTokenSource, 
2112                                         errorTokenName);
2113                                 break;
2114                         case INVALID_CODE:
2115                                 if (name.length() == 0) {
2116                                         problemReporter().parseErrorReplaceToken(
2117                                                 errorStart, 
2118                                                 errorEnd, 
2119                                                 currentKind,
2120                                                 errorTokenSource, 
2121                                                 errorTokenName, 
2122                                                 name);
2123                                 } else {
2124                                         problemReporter().parseErrorInvalidToken(
2125                                                 errorStart, 
2126                                                 errorEnd, 
2127                                                 currentKind,
2128                                                 errorTokenSource, 
2129                                                 errorTokenName, 
2130                                                 name);
2131                                 }
2132                                 break;
2133                         case SUBSTITUTION_CODE:
2134                                 problemReporter().parseErrorReplaceToken(
2135                                         errorStart, 
2136                                         errorEnd, 
2137                                         currentKind,
2138                                         errorTokenSource, 
2139                                         errorTokenName, 
2140                                         name); 
2141                                  break;
2142                         case SCOPE_CODE:
2143                                 StringBuffer buf = new StringBuffer();
2144                                 for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2145                                         buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2146                                         if (Parser.scope_rhs[i + 1] != 0) // any more symbols to print?
2147                                                 buf.append(' ');
2148                                                 
2149                                 }
2150
2151                                 if (scopeNameIndex != 0) {
2152                                         problemReporter().parseErrorInsertToComplete(
2153                                                 errorStart, 
2154                                                 errorEnd,
2155                                                 buf.toString(),
2156                                                 Parser.readableName[scopeNameIndex]);
2157                                 } else {
2158                                         problemReporter().parseErrorInsertToCompleteScope(
2159                                                 errorStart, 
2160                                                 errorEnd,
2161                                                 buf.toString()); 
2162                                 }
2163                                 
2164                                 break;
2165                         case EOF_CODE:
2166                                 problemReporter().parseErrorUnexpectedEnd(
2167                                         errorStart, 
2168                                         errorEnd); 
2169                                 break;
2170                         case MERGE_CODE:
2171                                 problemReporter().parseErrorMergeTokens(
2172                                         errorStart, 
2173                                         errorEnd,
2174                                         name);
2175                                 break;
2176                         case MISPLACED_CODE:
2177                                 problemReporter().parseErrorMisplacedConstruct(
2178                                         errorStart, 
2179                                         errorEnd);
2180                                 break;
2181                         default:
2182                                 if (name.length() == 0) {
2183                                         problemReporter().parseErrorNoSuggestion(
2184                                                 errorStart, 
2185                                                 errorEnd, 
2186                                                 currentKind,
2187                                                 errorTokenSource, 
2188                                                 errorTokenName);
2189                                 } else {
2190                                         problemReporter().parseErrorReplaceToken(
2191                                                 errorStart, 
2192                                                 errorEnd, 
2193                                                 currentKind,
2194                                                 errorTokenSource, 
2195                                                 errorTokenName, 
2196                                                 name); 
2197                                 }
2198                                 break;
2199                 }
2200         }
2201
2202         private void reportSecondaryError(int msgCode,  int nameIndex,  int leftToken,  int rightToken, int scopeNameIndex) {
2203                 String name;
2204                 if (nameIndex >= 0) {
2205                         name = Parser.readableName[nameIndex];
2206                 } else {
2207                         name = EMPTY_STRING;    
2208                 }
2209
2210                 int errorStart = -1;
2211                 if(lexStream.isInsideStream(leftToken)) {
2212                         if(leftToken == 0) {
2213                                 errorStart = lexStream.start(leftToken + 1);
2214                         } else {
2215                                 errorStart = lexStream.start(leftToken);
2216                         }
2217                 } else {
2218                         if(leftToken == errorToken) {
2219                                 errorStart = errorTokenStart;
2220                         } else {
2221                                 for (int i = 0; i <= stateStackTop; i++) {
2222                                         if(locationStack[i] == leftToken) {
2223                                                 errorStart = locationStartStack[i];
2224                                         }
2225                                 }
2226                         }
2227                         if(errorStart == -1) {
2228                                 errorStart = lexStream.start(rightToken);
2229                         }
2230                 }
2231                 int errorEnd = lexStream.end(rightToken);
2232                 
2233                 switch(msgCode) {
2234                         case MISPLACED_CODE:
2235                                 problemReporter().parseErrorMisplacedConstruct(
2236                                         errorStart, 
2237                                         errorEnd); 
2238                                 break;
2239                         case SCOPE_CODE:
2240                                 // error start is on the last token start
2241                                 errorStart = lexStream.start(rightToken);
2242                         
2243                     StringBuffer buf = new StringBuffer();
2244                     for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) {
2245                         buf.append(Parser.readableName[Parser.scope_rhs[i]]);
2246                         if (Parser.scope_rhs[i+1] != 0)
2247                              buf.append(' ');
2248                     }
2249                     if (scopeNameIndex != 0) {
2250                         problemReporter().parseErrorInsertToComplete(
2251                                                 errorStart, 
2252                                                 errorEnd,
2253                                                 buf.toString(),
2254                                                 Parser.readableName[scopeNameIndex]);
2255                     } else {
2256                         problemReporter().parseErrorInsertToCompletePhrase(
2257                                                 errorStart, 
2258                                                 errorEnd,
2259                                                 buf.toString()); 
2260                     }
2261                     break;
2262                         case MERGE_CODE:
2263                                 problemReporter().parseErrorMergeTokens(
2264                                         errorStart, 
2265                                         errorEnd,
2266                                         name);
2267                                 break;
2268                         case DELETION_CODE:
2269                                 problemReporter().parseErrorDeleteTokens(
2270                                         errorStart, 
2271                                         errorEnd);
2272                                 break;
2273                         default:
2274                                 if (name.length() == 0) {
2275                                         problemReporter().parseErrorNoSuggestionForTokens(
2276                                                 errorStart, 
2277                                                 errorEnd);
2278                                 } else {
2279                                         problemReporter().parseErrorReplaceTokens(
2280                                                 errorStart, 
2281                                                 errorEnd,
2282                                                 name);
2283                                 }
2284                 }
2285                 return;
2286         }
2287
2288         public String toString() {
2289                 StringBuffer res = new StringBuffer();
2290                 
2291                 res.append(lexStream.toString());
2292                 
2293                 return res.toString();
2294         }
2295 }