Home | History | Annotate | Download | only in test
      1 /*
      2  * [The "BSD license"]
      3  *  Copyright (c) 2010 Terence Parr
      4  *  All rights reserved.
      5  *
      6  *  Redistribution and use in source and binary forms, with or without
      7  *  modification, are permitted provided that the following conditions
      8  *  are met:
      9  *  1. Redistributions of source code must retain the above copyright
     10  *      notice, this list of conditions and the following disclaimer.
     11  *  2. Redistributions in binary form must reproduce the above copyright
     12  *      notice, this list of conditions and the following disclaimer in the
     13  *      documentation and/or other materials provided with the distribution.
     14  *  3. The name of the author may not be used to endorse or promote products
     15  *      derived from this software without specific prior written permission.
     16  *
     17  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 package org.antlr.test;
     29 
     30 import org.antlr.Tool;
     31 import org.antlr.analysis.DFA;
     32 import org.antlr.analysis.DecisionProbe;
     33 import org.antlr.codegen.CodeGenerator;
     34 import org.antlr.misc.BitSet;
     35 import org.antlr.tool.*;
     36 import org.junit.Test;
     37 
     38 import java.util.*;
     39 
     40 public class TestDFAConversion extends BaseTest {
     41 
     42 	@Test public void testA() throws Exception {
     43 		Grammar g = new Grammar(
     44 			"parser grammar t;\n"+
     45 			"a : A C | B;");
     46 		String expecting =
     47 			".s0-A->:s1=>1\n" +
     48 			".s0-B->:s2=>2\n";
     49 		checkDecision(g, 1, expecting, null, null, null, null, 0);
     50 	}
     51 
     52 	@Test public void testAB_or_AC() throws Exception {
     53 		Grammar g = new Grammar(
     54 			"parser grammar t;\n"+
     55 			"a : A B | A C;");
     56 		String expecting =
     57 			".s0-A->.s1\n" +
     58 			".s1-B->:s2=>1\n" +
     59 			".s1-C->:s3=>2\n";
     60 		checkDecision(g, 1, expecting, null, null, null, null, 0);
     61 	}
     62 
     63 	@Test public void testAB_or_AC_k2() throws Exception {
     64 		Grammar g = new Grammar(
     65 			"parser grammar t;\n" +
     66 			"options {k=2;}\n"+
     67 			"a : A B | A C;");
     68 		String expecting =
     69 			".s0-A->.s1\n" +
     70 			".s1-B->:s2=>1\n" +
     71 			".s1-C->:s3=>2\n";
     72 		checkDecision(g, 1, expecting, null, null, null, null, 0);
     73 	}
     74 
     75 	@Test public void testAB_or_AC_k1() throws Exception {
     76 		Grammar g = new Grammar(
     77 			"parser grammar t;\n" +
     78 			"options {k=1;}\n"+
     79 			"a : A B | A C;");
     80 		String expecting =
     81 			".s0-A->:s1=>1\n";
     82 		int[] unreachableAlts = new int[] {2};
     83 		int[] nonDetAlts = new int[] {1,2};
     84 		String ambigInput = "A" ;
     85 		int[] danglingAlts = new int[] {2};
     86 		int numWarnings = 2; // ambig upon A
     87 		checkDecision(g, 1, expecting, unreachableAlts,
     88 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
     89 	}
     90 
     91 	@Test public void testselfRecurseNonDet() throws Exception {
     92 		Grammar g = new Grammar(
     93 			"parser grammar t;\n"+
     94 			"s : a ;\n" +
     95 			"a : A a X | A a Y;");
     96 		List altsWithRecursion = Arrays.asList(new Object[] {1,2});
     97 		assertNonLLStar(g, altsWithRecursion);
     98 	}
     99 
    100 	@Test public void testRecursionOverflow() throws Exception {
    101 		Grammar g = new Grammar(
    102 			"parser grammar t;\n"+
    103 			"s : a Y | A A A A A X ;\n" + // force recursion past m=4
    104 			"a : A a | Q;");
    105 		List expectedTargetRules = Arrays.asList(new Object[] {"a"});
    106 		int expectedAlt = 1;
    107 		assertRecursionOverflow(g, expectedTargetRules, expectedAlt);
    108 	}
    109 
    110 	@Test public void testRecursionOverflow2() throws Exception {
    111 		Grammar g = new Grammar(
    112 			"parser grammar t;\n"+
    113 			"s : a Y | A+ X ;\n" + // force recursion past m=4
    114 			"a : A a | Q;");
    115 		List expectedTargetRules = Arrays.asList(new Object[] {"a"});
    116 		int expectedAlt = 1;
    117 		assertRecursionOverflow(g, expectedTargetRules, expectedAlt);
    118 	}
    119 
    120 	@Test public void testRecursionOverflowWithPredOk() throws Exception {
    121 		// overflows with k=*, but resolves with pred
    122 		// no warnings/errors
    123 		Grammar g = new Grammar(
    124 			"parser grammar t;\n"+
    125 			"s : (a Y)=> a Y | A A A A A X ;\n" + // force recursion past m=4
    126 			"a : A a | Q;");
    127 		String expecting =
    128 			".s0-A->.s1\n" +
    129 			".s0-Q&&{synpred1_t}?->:s11=>1\n" +
    130 			".s1-A->.s2\n" +
    131 			".s1-Q&&{synpred1_t}?->:s10=>1\n" +
    132 			".s2-A->.s3\n" +
    133 			".s2-Q&&{synpred1_t}?->:s9=>1\n" +
    134 			".s3-A->.s4\n" +
    135 			".s3-Q&&{synpred1_t}?->:s8=>1\n" +
    136 			".s4-A->.s5\n" +
    137 			".s4-Q&&{synpred1_t}?->:s6=>1\n" +
    138 			".s5-{synpred1_t}?->:s6=>1\n" +
    139 			".s5-{true}?->:s7=>2\n";
    140 		int[] unreachableAlts = null;
    141 		int[] nonDetAlts = null;
    142 		String ambigInput = null;
    143 		int[] danglingAlts = null;
    144 		int numWarnings = 0;
    145 		checkDecision(g, 1, expecting, unreachableAlts,
    146 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    147 	}
    148 
    149 	@Test public void testRecursionOverflowWithPredOk2() throws Exception {
    150 		// must predict Z w/o predicate
    151 		Grammar g = new Grammar(
    152 			"parser grammar t;\n"+
    153 			"s : (a Y)=> a Y | A A A A A X | Z;\n" + // force recursion past m=4
    154 			"a : A a | Q;");
    155 		String expecting =
    156 			".s0-A->.s1\n" +
    157 			".s0-Q&&{synpred1_t}?->:s11=>1\n" +
    158 			".s0-Z->:s12=>3\n" +
    159 			".s1-A->.s2\n" +
    160 			".s1-Q&&{synpred1_t}?->:s10=>1\n" +
    161 			".s2-A->.s3\n" +
    162 			".s2-Q&&{synpred1_t}?->:s9=>1\n" +
    163 			".s3-A->.s4\n" +
    164 			".s3-Q&&{synpred1_t}?->:s8=>1\n" +
    165 			".s4-A->.s5\n" +
    166 			".s4-Q&&{synpred1_t}?->:s6=>1\n" +
    167 			".s5-{synpred1_t}?->:s6=>1\n" +
    168 			".s5-{true}?->:s7=>2\n";
    169 		int[] unreachableAlts = null;
    170 		int[] nonDetAlts = null;
    171 		String ambigInput = null;
    172 		int[] danglingAlts = null;
    173 		int numWarnings = 0;
    174 		checkDecision(g, 1, expecting, unreachableAlts,
    175 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    176 	}
    177 
    178 	@Test public void testCannotSeePastRecursion() throws Exception {
    179 		Grammar g = new Grammar(
    180 			"parser grammar t;\n"+
    181 			"x   : y X\n" +
    182 			"    | y Y\n" +
    183 			"    ;\n" +
    184 			"y   : L y R\n" +
    185 			"    | B\n" +
    186 			"    ;");
    187 		List altsWithRecursion = Arrays.asList(new Object[] {1,2});
    188 		assertNonLLStar(g, altsWithRecursion);
    189 	}
    190 
    191 	@Test public void testSynPredResolvesRecursion() throws Exception {
    192 		Grammar g = new Grammar(
    193 			"parser grammar t;\n"+
    194 			"x   : (y X)=> y X\n" +
    195 			"    | y Y\n" +
    196 			"    ;\n" +
    197 			"y   : L y R\n" +
    198 			"    | B\n" +
    199 			"    ;");
    200 		String expecting =
    201 			".s0-B->.s4\n" +
    202 			".s0-L->.s1\n" +
    203 			".s1-{synpred1_t}?->:s2=>1\n" +
    204 			".s1-{true}?->:s3=>2\n" +
    205 			".s4-{synpred1_t}?->:s2=>1\n" +
    206 			".s4-{true}?->:s3=>2\n";
    207 		int[] unreachableAlts = null;
    208 		int[] nonDetAlts = null;
    209 		String ambigInput = null;
    210 		int[] danglingAlts = null;
    211 		int numWarnings = 0;
    212 		checkDecision(g, 1, expecting, unreachableAlts,
    213 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    214 	}
    215 
    216 	@Test public void testSynPredMissingInMiddle() throws Exception {
    217 		Grammar g = new Grammar(
    218 			"parser grammar t;\n"+
    219 			"x   : (A)=> X\n" +
    220 			"    | X\n" +  // assume missing synpred is true also
    221 			"	 | (C)=> X" +
    222 			"    ;\n");
    223 		String expecting =
    224 			".s0-X->.s1\n" +
    225 			".s1-{synpred1_t}?->:s2=>1\n" +
    226 			".s1-{synpred2_t}?->:s4=>3\n" +
    227 			".s1-{true}?->:s3=>2\n";
    228 		int[] unreachableAlts = null;
    229 		int[] nonDetAlts = null;
    230 		String ambigInput = null;
    231 		int[] danglingAlts = null;
    232 		int numWarnings = 0;
    233 		checkDecision(g, 1, expecting, unreachableAlts,
    234 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    235 	}
    236 
    237 	@Test public void testAutoBacktrackAndPredMissingInMiddle() throws Exception {
    238 		Grammar g = new Grammar(
    239 			"parser grammar t;\n" +
    240 			"options {backtrack=true;}\n"+
    241 			"x   : (A)=> X\n" +
    242 			"    | X\n" +  // assume missing synpred is true also
    243 			"	 | (C)=> X" +
    244 			"    ;\n");
    245 		String expecting =
    246 			".s0-X->.s1\n" +
    247 			".s1-{synpred1_t}?->:s2=>1\n" +  // gen code should have this as (A)=>
    248 			".s1-{synpred2_t}?->:s3=>2\n" + // gen code should have this as (X)=>
    249 			".s1-{synpred3_t}?->:s4=>3\n"; // gen code should have this as (C)=>
    250 		int[] unreachableAlts = null;
    251 		int[] nonDetAlts = null;
    252 		String ambigInput = null;
    253 		int[] danglingAlts = null;
    254 		int numWarnings = 0;
    255 		checkDecision(g, 1, expecting, unreachableAlts,
    256 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    257 	}
    258 
    259 	@Test public void testSemPredResolvesRecursion() throws Exception {
    260 		Grammar g = new Grammar(
    261 			"parser grammar t;\n"+
    262 			"x   : {p}? y X\n" +
    263 			"    | y Y\n" +
    264 			"    ;\n" +
    265 			"y   : L y R\n" +
    266 			"    | B\n" +
    267 			"    ;");
    268 		String expecting =
    269 			".s0-B->.s4\n" +
    270 			".s0-L->.s1\n" +
    271 			".s1-{p}?->:s2=>1\n" +
    272 			".s1-{true}?->:s3=>2\n" +
    273 			".s4-{p}?->:s2=>1\n" +
    274 			".s4-{true}?->:s3=>2\n";
    275 		int[] unreachableAlts = null;
    276 		int[] nonDetAlts = null;
    277 		String ambigInput = null;
    278 		int[] danglingAlts = null;
    279 		int numWarnings = 0;
    280 		checkDecision(g, 1, expecting, unreachableAlts,
    281 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    282 	}
    283 
    284 	@Test public void testSemPredResolvesRecursion2() throws Exception {
    285 		Grammar g = new Grammar(
    286 			"parser grammar t;\n"+
    287 			"x\n" +
    288 			"options {k=1;}\n" +
    289 			"   : {p}? y X\n" +
    290 			"    | y Y\n" +
    291 			"    ;\n" +
    292 			"y   : L y R\n" +
    293 			"    | B\n" +
    294 			"    ;");
    295 		String expecting =
    296 			".s0-B->.s4\n" +
    297 			".s0-L->.s1\n" +
    298 			".s1-{p}?->:s2=>1\n" +
    299 			".s1-{true}?->:s3=>2\n" +
    300 			".s4-{p}?->:s2=>1\n" +
    301 			".s4-{true}?->:s3=>2\n";
    302 		int[] unreachableAlts = null;
    303 		int[] nonDetAlts = null;
    304 		String ambigInput = null;
    305 		int[] danglingAlts = null;
    306 		int numWarnings = 0;
    307 		checkDecision(g, 1, expecting, unreachableAlts,
    308 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    309 	}
    310 
    311 	@Test public void testSemPredResolvesRecursion3() throws Exception {
    312 		Grammar g = new Grammar(
    313 			"parser grammar t;\n"+
    314 			"x\n" +
    315 			"options {k=2;}\n" + // just makes bigger DFA
    316 			"   : {p}? y X\n" +
    317 			"    | y Y\n" +
    318 			"    ;\n" +
    319 			"y   : L y R\n" +
    320 			"    | B\n" +
    321 			"    ;");
    322 		String expecting =
    323 			".s0-B->.s6\n" +
    324 			".s0-L->.s1\n" +
    325 			".s1-B->.s5\n" +
    326 			".s1-L->.s2\n" +
    327 			".s2-{p}?->:s3=>1\n" +
    328 			".s2-{true}?->:s4=>2\n" +
    329 			".s5-{p}?->:s3=>1\n" +
    330 			".s5-{true}?->:s4=>2\n" +
    331 			".s6-X->:s3=>1\n" +
    332 			".s6-Y->:s4=>2\n";
    333 		int[] unreachableAlts = null;
    334 		int[] nonDetAlts = null;
    335 		String ambigInput = null;
    336 		int[] danglingAlts = null;
    337 		int numWarnings = 0;
    338 		checkDecision(g, 1, expecting, unreachableAlts,
    339 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    340 	}
    341 
    342 	@Test public void testSynPredResolvesRecursion2() throws Exception {
    343 		// k=* fails and it retries/succeeds with k=1 silently
    344 		// because of predicate
    345 		Grammar g = new Grammar(
    346 			"parser grammar t;\n"+
    347 			"statement\n" +
    348 			"    :     (reference ASSIGN)=> reference ASSIGN expr\n" +
    349 			"    |     expr\n" +
    350 			"    ;\n" +
    351 			"expr:     reference\n" +
    352 			"    |     INT\n" +
    353 			"    |     FLOAT\n" +
    354 			"    ;\n" +
    355 			"reference\n" +
    356 			"    :     ID L argument_list R\n" +
    357 			"    ;\n" +
    358 			"argument_list\n" +
    359 			"    :     expr COMMA expr\n" +
    360 			"    ;");
    361 		String expecting =
    362 			".s0-ID->.s1\n" +
    363 			".s0-{FLOAT, INT}->:s3=>2\n" +
    364 			".s1-{synpred1_t}?->:s2=>1\n" +
    365 			".s1-{true}?->:s3=>2\n";
    366 		int[] unreachableAlts = null;
    367 		int[] nonDetAlts = null;
    368 		String ambigInput = null;
    369 		int[] danglingAlts = null;
    370 		int numWarnings = 0;
    371 		checkDecision(g, 1, expecting, unreachableAlts,
    372 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    373 	}
    374 
    375 	@Test public void testSynPredResolvesRecursion3() throws Exception {
    376 		// No errors with k=1; don't try k=* first
    377 		Grammar g = new Grammar(
    378 			"parser grammar t;\n"+
    379 			"statement\n" +
    380 			"options {k=1;}\n" +
    381 			"    :     (reference ASSIGN)=> reference ASSIGN expr\n" +
    382 			"    |     expr\n" +
    383 			"    ;\n" +
    384 			"expr:     reference\n" +
    385 			"    |     INT\n" +
    386 			"    |     FLOAT\n" +
    387 			"    ;\n" +
    388 			"reference\n" +
    389 			"    :     ID L argument_list R\n" +
    390 			"    ;\n" +
    391 			"argument_list\n" +
    392 			"    :     expr COMMA expr\n" +
    393 			"    ;");
    394 		String expecting =
    395 			".s0-ID->.s1\n" +
    396 			".s0-{FLOAT, INT}->:s3=>2\n" +
    397 			".s1-{synpred1_t}?->:s2=>1\n" +
    398 			".s1-{true}?->:s3=>2\n";
    399 		int[] unreachableAlts = null;
    400 		int[] nonDetAlts = null;
    401 		String ambigInput = null;
    402 		int[] danglingAlts = null;
    403 		int numWarnings = 0;
    404 		checkDecision(g, 1, expecting, unreachableAlts,
    405 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    406 	}
    407 
    408 	@Test public void testSynPredResolvesRecursion4() throws Exception {
    409 		// No errors with k=2; don't try k=* first
    410 		// Should be ok like k=1 'except bigger DFA
    411 		Grammar g = new Grammar(
    412 			"parser grammar t;\n"+
    413 			"statement\n" +
    414 			"options {k=2;}\n" +
    415 			"    :     (reference ASSIGN)=> reference ASSIGN expr\n" +
    416 			"    |     expr\n" +
    417 			"    ;\n" +
    418 			"expr:     reference\n" +
    419 			"    |     INT\n" +
    420 			"    |     FLOAT\n" +
    421 			"    ;\n" +
    422 			"reference\n" +
    423 			"    :     ID L argument_list R\n" +
    424 			"    ;\n" +
    425 			"argument_list\n" +
    426 			"    :     expr COMMA expr\n" +
    427 			"    ;");
    428 		String expecting =
    429 			".s0-ID->.s1\n" +
    430 			".s0-{FLOAT, INT}->:s4=>2\n" +
    431 			".s1-L->.s2\n" +
    432 			".s2-{synpred1_t}?->:s3=>1\n" +
    433 			".s2-{true}?->:s4=>2\n";
    434 		int[] unreachableAlts = null;
    435 		int[] nonDetAlts = null;
    436 		String ambigInput = null;
    437 		int[] danglingAlts = null;
    438 		int numWarnings = 0;
    439 		checkDecision(g, 1, expecting, unreachableAlts,
    440 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    441 	}
    442 
    443 	@Test public void testSynPredResolvesRecursionInLexer() throws Exception {
    444 		Grammar g = new Grammar(
    445 			"lexer grammar t;\n"+
    446 			"A :     (B ';')=> B ';'\n" +
    447 			"  |     B '.'\n" +
    448 			"  ;\n" +
    449 			"fragment\n" +
    450 			"B :     '(' B ')'\n" +
    451 			"  |     'x'\n" +
    452 			"  ;\n");
    453 		String expecting =
    454 			".s0-'('->.s1\n" +
    455 			".s0-'x'->.s4\n" +
    456 			".s1-{synpred1_t}?->:s2=>1\n" +
    457 			".s1-{true}?->:s3=>2\n" +
    458 			".s4-{synpred1_t}?->:s2=>1\n" +
    459 			".s4-{true}?->:s3=>2\n";
    460 		int[] unreachableAlts = null;
    461 		int[] nonDetAlts = null;
    462 		String ambigInput = null;
    463 		int[] danglingAlts = null;
    464 		int numWarnings = 0;
    465 		checkDecision(g, 1, expecting, unreachableAlts,
    466 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    467 	}
    468 
    469 	@Test public void testAutoBacktrackResolvesRecursionInLexer() throws Exception {
    470 		Grammar g = new Grammar(
    471 			"lexer grammar t;\n"+
    472 			"options {backtrack=true;}\n"+
    473 			"A :     B ';'\n" +
    474 			"  |     B '.'\n" +
    475 			"  ;\n" +
    476 			"fragment\n" +
    477 			"B :     '(' B ')'\n" +
    478 			"  |     'x'\n" +
    479 			"  ;\n");
    480 		String expecting =
    481 			".s0-'('->.s1\n" +
    482 			".s0-'x'->.s4\n" +
    483 			".s1-{synpred1_t}?->:s2=>1\n" +
    484 			".s1-{true}?->:s3=>2\n" +
    485 			".s4-{synpred1_t}?->:s2=>1\n" +
    486 			".s4-{true}?->:s3=>2\n";
    487 		int[] unreachableAlts = null;
    488 		int[] nonDetAlts = null;
    489 		String ambigInput = null;
    490 		int[] danglingAlts = null;
    491 		int numWarnings = 0;
    492 		checkDecision(g, 1, expecting, unreachableAlts,
    493 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    494 	}
    495 
    496 	@Test public void testAutoBacktrackResolvesRecursion() throws Exception {
    497 		Grammar g = new Grammar(
    498 			"parser grammar t;\n" +
    499 			"options {backtrack=true;}\n"+
    500 			"x   : y X\n" +
    501 			"    | y Y\n" +
    502 			"    ;\n" +
    503 			"y   : L y R\n" +
    504 			"    | B\n" +
    505 			"    ;");
    506 		String expecting =
    507 			".s0-B->.s4\n" +
    508 			".s0-L->.s1\n" +
    509 			".s1-{synpred1_t}?->:s2=>1\n" +
    510 			".s1-{true}?->:s3=>2\n" +
    511 			".s4-{synpred1_t}?->:s2=>1\n" +
    512 			".s4-{true}?->:s3=>2\n";
    513 		int[] unreachableAlts = null;
    514 		int[] nonDetAlts = null;
    515 		String ambigInput = null;
    516 		int[] danglingAlts = null;
    517 		int numWarnings = 0;
    518 		checkDecision(g, 1, expecting, unreachableAlts,
    519 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    520 	}
    521 
    522 	@Test public void testselfRecurseNonDet2() throws Exception {
    523 		Grammar g = new Grammar(
    524 			"parser grammar t;\n"+
    525 			"s : a ;\n" +
    526 			"a : P a P | P;");
    527 		// nondeterministic from left edge
    528 		String expecting =
    529 			".s0-P->.s1\n" +
    530 			".s1-EOF->:s3=>2\n"+
    531 			".s1-P->:s2=>1\n";
    532 		int[] unreachableAlts = null;
    533 		int[] nonDetAlts = new int[] {1,2};
    534 		String ambigInput = "P P";
    535 		int[] danglingAlts = null;
    536 		int numWarnings = 1;
    537 		checkDecision(g, 1, expecting, unreachableAlts,
    538 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    539 	}
    540 
    541 	@Test public void testIndirectRecursionLoop() throws Exception {
    542 		Grammar g = new Grammar(
    543 			"parser grammar t;\n"+
    544 			"s : a ;\n" +
    545 			"a : b X ;\n"+
    546 			"b : a B ;\n");
    547 
    548 		DecisionProbe.verbose=true; // make sure we get all error info
    549 		ErrorQueue equeue = new ErrorQueue();
    550 		ErrorManager.setErrorListener(equeue);
    551 
    552 		Set<Rule> leftRecursive = g.getLeftRecursiveRules();
    553 		Set expectedRules =
    554 			new HashSet() {{add("a"); add("b");}};
    555 		assertEquals(expectedRules, ruleNames(leftRecursive));
    556 
    557 		assertEquals(1, equeue.errors.size());
    558 		Message msg = (Message)equeue.errors.get(0);
    559 		assertTrue("expecting left recursion cycles; found "+msg.getClass().getName(),
    560 				    msg instanceof LeftRecursionCyclesMessage);
    561 		LeftRecursionCyclesMessage cyclesMsg = (LeftRecursionCyclesMessage)msg;
    562 
    563 		// cycle of [a, b]
    564 		Collection result = cyclesMsg.cycles;
    565 		Set expecting = new HashSet() {{add("a"); add("b");}};
    566 		assertEquals(expecting, ruleNames2(result));
    567 	}
    568 
    569 	@Test public void testIndirectRecursionLoop2() throws Exception {
    570 		Grammar g = new Grammar(
    571 			"parser grammar t;\n"+
    572 			"s : a ;\n" +
    573 			"a : i b X ;\n"+ // should see through i
    574 			"b : a B ;\n" +
    575 			"i : ;\n");
    576 
    577 		DecisionProbe.verbose=true; // make sure we get all error info
    578 		ErrorQueue equeue = new ErrorQueue();
    579 		ErrorManager.setErrorListener(equeue);
    580 
    581 		Set leftRecursive = g.getLeftRecursiveRules();
    582 		Set expectedRules =
    583 			new HashSet() {{add("a"); add("b");}};
    584 		assertEquals(expectedRules, ruleNames(leftRecursive));
    585 
    586 		assertEquals(1, equeue.errors.size());
    587 		Message msg = (Message)equeue.errors.get(0);
    588 		assertTrue("expecting left recursion cycles; found "+msg.getClass().getName(),
    589 				    msg instanceof LeftRecursionCyclesMessage);
    590 		LeftRecursionCyclesMessage cyclesMsg = (LeftRecursionCyclesMessage)msg;
    591 
    592 		// cycle of [a, b]
    593 		Collection result = cyclesMsg.cycles;
    594 		Set expecting = new HashSet() {{add("a"); add("b");}};
    595 		assertEquals(expecting, ruleNames2(result));
    596 	}
    597 
    598 	@Test public void testIndirectRecursionLoop3() throws Exception {
    599 		Grammar g = new Grammar(
    600 			"parser grammar t;\n"+
    601 			"s : a ;\n" +
    602 			"a : i b X ;\n"+ // should see through i
    603 			"b : a B ;\n" +
    604 			"i : ;\n" +
    605 			"d : e ;\n" +
    606 			"e : d ;\n");
    607 
    608 		DecisionProbe.verbose=true; // make sure we get all error info
    609 		ErrorQueue equeue = new ErrorQueue();
    610 		ErrorManager.setErrorListener(equeue);
    611 
    612 		Set leftRecursive = g.getLeftRecursiveRules();
    613 		Set expectedRules =
    614 			new HashSet() {{add("a"); add("b"); add("e"); add("d");}};
    615 		assertEquals(expectedRules, ruleNames(leftRecursive));
    616 
    617 		assertEquals(1, equeue.errors.size());
    618 		Message msg = (Message)equeue.errors.get(0);
    619 		assertTrue("expecting left recursion cycles; found "+msg.getClass().getName(),
    620 				    msg instanceof LeftRecursionCyclesMessage);
    621 		LeftRecursionCyclesMessage cyclesMsg = (LeftRecursionCyclesMessage)msg;
    622 
    623 		// cycle of [a, b]
    624 		Collection result = cyclesMsg.cycles;
    625 		Set expecting = new HashSet() {{add("a"); add("b"); add("d"); add("e");}};
    626 		assertEquals(expecting, ruleNames2(result));
    627 	}
    628 
    629 	@Test public void testifThenElse() throws Exception {
    630 		Grammar g = new Grammar(
    631 			"parser grammar t;\n"+
    632 			"s : IF s (E s)? | B;\n" +
    633 			"slist: s SEMI ;");
    634 		String expecting =
    635 			".s0-E->:s1=>1\n" +
    636 			".s0-SEMI->:s2=>2\n";
    637 		int[] unreachableAlts = null;
    638 		int[] nonDetAlts = new int[] {1,2};
    639 		String ambigInput = "E";
    640 		int[] danglingAlts = null;
    641 		int numWarnings = 1;
    642 		checkDecision(g, 1, expecting, unreachableAlts,
    643 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    644 		expecting =
    645 			".s0-B->:s2=>2\n" +
    646 			".s0-IF->:s1=>1\n";
    647 		checkDecision(g, 2, expecting, null, null, null, null, 0);
    648 	}
    649 
    650 	@Test public void testifThenElseChecksStackSuffixConflict() throws Exception {
    651 		// if you don't check stack soon enough, this finds E B not just E
    652 		// as ambig input
    653 		Grammar g = new Grammar(
    654 			"parser grammar t;\n"+
    655 			"slist: s SEMI ;\n"+
    656 			"s : IF s el | B;\n" +
    657 			"el: (E s)? ;\n");
    658 		String expecting =
    659 			".s0-E->:s1=>1\n" +
    660 			".s0-SEMI->:s2=>2\n";
    661 		int[] unreachableAlts = null;
    662 		int[] nonDetAlts = new int[] {1,2};
    663 		String ambigInput = "E";
    664 		int[] danglingAlts = null;
    665 		int numWarnings = 1;
    666 		checkDecision(g, 2, expecting, unreachableAlts,
    667 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    668 		expecting =
    669 			".s0-B->:s2=>2\n" +
    670 			".s0-IF->:s1=>1\n";
    671 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    672 	}
    673 
    674     @Test
    675     public void testInvokeRule() throws Exception {
    676 		Grammar g = new Grammar(
    677 			"parser grammar t;\n"+
    678 			"a : b A\n" +
    679 			"  | b B\n" +
    680 			"  | C\n" +
    681 			"  ;\n" +
    682 			"b : X\n" +
    683 			"  ;\n");
    684 		String expecting =
    685 			".s0-C->:s4=>3\n" +
    686             ".s0-X->.s1\n" +
    687             ".s1-A->:s2=>1\n" +
    688             ".s1-B->:s3=>2\n";
    689 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    690 	}
    691 
    692 	@Test
    693     public void testDoubleInvokeRuleLeftEdge() throws Exception {
    694 		Grammar g = new Grammar(
    695 			"parser grammar t;\n"+
    696 			"a : b X\n" +
    697 			"  | b Y\n" +
    698 			"  ;\n" +
    699 			"b : c B\n" +
    700 			"  | c\n" +
    701 			"  ;\n" +
    702 			"c : C ;\n");
    703 		String expecting =
    704 			".s0-C->.s1\n" +
    705 			".s1-B->.s2\n" +
    706 			".s1-X->:s3=>1\n" +
    707 			".s1-Y->:s4=>2\n" +
    708 			".s2-X->:s3=>1\n" +
    709 			".s2-Y->:s4=>2\n";
    710 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    711 		expecting =
    712 			".s0-C->.s1\n" +
    713             ".s1-B->:s2=>1\n" +
    714             ".s1-X..Y->:s3=>2\n";
    715 		checkDecision(g, 2, expecting, null, null, null, null, 0);
    716 	}
    717 
    718 	@Test public void testimmediateTailRecursion() throws Exception {
    719 		Grammar g = new Grammar(
    720 			"parser grammar t;\n"+
    721 			"s : a ;\n" +
    722 			"a : A a | A B;");
    723 		String expecting =
    724 			".s0-A->.s1\n" +
    725 			".s1-A->:s3=>1\n" +
    726 			".s1-B->:s2=>2\n";
    727 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    728 	}
    729 
    730 	@Test
    731     public void testAStar_immediateTailRecursion() throws Exception {
    732 		Grammar g = new Grammar(
    733 			"parser grammar t;\n"+
    734 			"s : a ;\n" +
    735 			"a : A a | ;");
    736 		String expecting =
    737 			".s0-A->:s1=>1\n" +
    738 			".s0-EOF->:s2=>2\n";
    739 		int[] unreachableAlts = null; // without
    740 		int[] nonDetAlts = null;
    741 		String ambigInput = null;
    742 		int[] danglingAlts = null;
    743 		int numWarnings = 0;
    744 		checkDecision(g, 1, expecting, unreachableAlts,
    745 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    746 	}
    747 
    748 	@Test public void testNoStartRule() throws Exception {
    749 		ErrorQueue equeue = new ErrorQueue();
    750 		ErrorManager.setErrorListener(equeue);
    751 		Grammar g = new Grammar(
    752 			"parser grammar t;\n"+
    753 			"a : A a | X;"); // single rule 'a' refers to itself; no start rule
    754 
    755 		Tool antlr = newTool();
    756 		antlr.setOutputDirectory(null); // write to /dev/null
    757 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    758 		g.setCodeGenerator(generator);
    759 		generator.genRecognizer();
    760 
    761 		Message msg = (Message)equeue.warnings.get(0);
    762 		assertTrue("expecting no start rules; found "+msg.getClass().getName(),
    763 				   msg instanceof GrammarSemanticsMessage);
    764 	}
    765 
    766 	@Test
    767     public void testAStar_immediateTailRecursion2() throws Exception {
    768 		Grammar g = new Grammar(
    769 			"parser grammar t;\n"+
    770 			"s : a ;\n" +
    771 			"a : A a | A ;");
    772 		String expecting =
    773 			".s0-A->.s1\n" +
    774             ".s1-A->:s2=>1\n" +
    775             ".s1-EOF->:s3=>2\n";
    776 		int[] unreachableAlts = null;
    777 		int[] nonDetAlts = null;
    778 		String ambigInput = null;
    779 		int[] danglingAlts = null;
    780 		int numWarnings = 0;
    781 		checkDecision(g, 1, expecting, unreachableAlts,
    782 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    783 	}
    784 
    785 	@Test public void testimmediateLeftRecursion() throws Exception {
    786 		Grammar g = new Grammar(
    787 			"parser grammar t;\n"+
    788 			"s : a ;\n" +
    789 			"a : a A | B;");
    790 		Set leftRecursive = g.getLeftRecursiveRules();
    791 		Set expectedRules = new HashSet() {{add("a");}};
    792 		assertEquals(expectedRules, ruleNames(leftRecursive));
    793 	}
    794 
    795 	@Test public void testIndirectLeftRecursion() throws Exception {
    796 		Grammar g = new Grammar(
    797 			"parser grammar t;\n"+
    798 			"s : a ;\n" +
    799 			"a : b | A ;\n" +
    800 			"b : c ;\n" +
    801 			"c : a | C ;\n");
    802 		Set leftRecursive = g.getLeftRecursiveRules();
    803 		Set expectedRules = new HashSet() {{add("a"); add("b"); add("c");}};
    804 		assertEquals(expectedRules, ruleNames(leftRecursive));
    805 	}
    806 
    807 	@Test public void testLeftRecursionInMultipleCycles() throws Exception {
    808 		Grammar g = new Grammar(
    809 			"parser grammar t;\n"+
    810 				"s : a x ;\n" +
    811 				"a : b | A ;\n" +
    812 				"b : c ;\n" +
    813 				"c : a | C ;\n" +
    814 				"x : y | X ;\n" +
    815 				"y : x ;\n");
    816 		Set leftRecursive = g.getLeftRecursiveRules();
    817 		Set expectedRules =
    818 			new HashSet() {{add("a"); add("b"); add("c"); add("x"); add("y");}};
    819 		assertEquals(expectedRules, ruleNames(leftRecursive));
    820 	}
    821 
    822 	@Test public void testCycleInsideRuleDoesNotForceInfiniteRecursion() throws Exception {
    823 		Grammar g = new Grammar(
    824 			"parser grammar t;\n"+
    825 			"s : a ;\n" +
    826 			"a : (A|)+ B;\n");
    827 		// before I added a visitedStates thing, it was possible to loop
    828 		// forever inside of a rule if there was an epsilon loop.
    829 		Set leftRecursive = g.getLeftRecursiveRules();
    830 		Set expectedRules = new HashSet();
    831 		assertEquals(expectedRules, leftRecursive);
    832 	}
    833 
    834 	// L O O P S
    835 
    836 	@Test public void testAStar() throws Exception {
    837 		Grammar g = new Grammar(
    838 			"parser grammar t;\n"+
    839 			"a : ( A )* ;");
    840 		String expecting =
    841 			".s0-A->:s1=>1\n" +
    842 			".s0-EOF->:s2=>2\n";
    843 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    844 	}
    845 
    846 	@Test public void testAorBorCStar() throws Exception {
    847 		Grammar g = new Grammar(
    848 			"parser grammar t;\n"+
    849 			"a : ( A | B | C )* ;");
    850 		String expecting =
    851 			".s0-A..C->:s1=>1\n" +
    852 			".s0-EOF->:s2=>2\n";
    853 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    854 	}
    855 
    856 	@Test public void testAPlus() throws Exception {
    857 		Grammar g = new Grammar(
    858 			"parser grammar t;\n"+
    859 			"a : ( A )+ ;");
    860 		String expecting =
    861 			".s0-A->:s1=>1\n" +
    862 			".s0-EOF->:s2=>2\n";
    863 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback decision
    864 	}
    865 
    866 	@Test public void testAPlusNonGreedyWhenDeterministic() throws Exception {
    867 		Grammar g = new Grammar(
    868 			"parser grammar t;\n"+
    869 			"a : (options {greedy=false;}:A)+ ;\n");
    870 		// should look the same as A+ since no ambiguity
    871 		String expecting =
    872 			".s0-A->:s1=>1\n" +
    873 			".s0-EOF->:s2=>2\n";
    874 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    875 	}
    876 
    877 	@Test public void testAPlusNonGreedyWhenNonDeterministic() throws Exception {
    878 		Grammar g = new Grammar(
    879 			"parser grammar t;\n"+
    880 			"a : (options {greedy=false;}:A)+ A+ ;\n");
    881 		// should look the same as A+ since no ambiguity
    882 		String expecting =
    883 			".s0-A->:s1=>2\n"; // always chooses to exit
    884 		int[] unreachableAlts = new int[] {1};
    885 		int[] nonDetAlts = new int[] {1,2};
    886 		String ambigInput = "A";
    887 		int[] danglingAlts = null;
    888 		int numWarnings = 2;
    889 		checkDecision(g, 1, expecting, unreachableAlts,
    890 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    891 	}
    892 
    893 	@Test public void testAPlusGreedyWhenNonDeterministic() throws Exception {
    894 		Grammar g = new Grammar(
    895 			"parser grammar t;\n"+
    896 			"a : (options {greedy=true;}:A)+ A+ ;\n");
    897 		// should look the same as A+ since no ambiguity
    898 		String expecting =
    899 			".s0-A->:s1=>1\n"; // always chooses to enter loop upon A
    900 		// turns off 1 of warnings. A can never exit loop now
    901 		int[] unreachableAlts = new int[] {2};
    902 		int[] nonDetAlts = null;
    903 		String ambigInput = null;
    904 		int[] danglingAlts = null;
    905 		int numWarnings = 1;
    906 		checkDecision(g, 1, expecting, unreachableAlts,
    907 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
    908 	}
    909 
    910 	@Test public void testAorBorCPlus() throws Exception {
    911 		Grammar g = new Grammar(
    912 			"parser grammar t;\n"+
    913 			"a : ( A | B | C )+ ;");
    914 		String expecting =
    915 			".s0-A..C->:s1=>1\n" +
    916 			".s0-EOF->:s2=>2\n";
    917 		checkDecision(g, 1, expecting, null, null, null, null, 0);
    918 	}
    919 
    920 	@Test public void testAOptional() throws Exception {
    921 		Grammar g = new Grammar(
    922 			"parser grammar t;\n"+
    923 			"a : ( A )? B ;");
    924 		String expecting =
    925 			".s0-A->:s1=>1\n" +
    926 			".s0-B->:s2=>2\n";
    927 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback decision
    928 	}
    929 
    930 	@Test public void testAorBorCOptional() throws Exception {
    931 		Grammar g = new Grammar(
    932 			"parser grammar t;\n"+
    933 			"a : ( A | B | C )? Z ;");
    934 		String expecting =
    935 			".s0-A..C->:s1=>1\n" +
    936 			".s0-Z->:s2=>2\n";
    937 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback decision
    938 	}
    939 
    940 	// A R B I T R A R Y  L O O K A H E A D
    941 
    942 	@Test
    943     public void testAStarBOrAStarC() throws Exception {
    944 		Grammar g = new Grammar(
    945 			"parser grammar t;\n"+
    946 			"a : (A)* B | (A)* C;");
    947 		String expecting =
    948 			".s0-A->:s1=>1\n" +
    949 			".s0-B->:s2=>2\n";
    950 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback
    951 		expecting =
    952 			".s0-A->:s1=>1\n" +
    953 			".s0-C->:s2=>2\n";
    954 		checkDecision(g, 2, expecting, null, null, null, null, 0); // loopback
    955 		expecting =
    956 			".s0-A->.s1\n" +
    957             ".s0-B->:s2=>1\n" +
    958             ".s0-C->:s3=>2\n" +
    959             ".s1-A->.s1\n" +
    960             ".s1-B->:s2=>1\n" +
    961             ".s1-C->:s3=>2\n";
    962 		checkDecision(g, 3, expecting, null, null, null, null, 0); // rule block
    963 	}
    964 
    965 	@Test
    966     public void testAStarBOrAPlusC() throws Exception {
    967 		Grammar g = new Grammar(
    968 			"parser grammar t;\n"+
    969 			"a : (A)* B | (A)+ C;");
    970 		String expecting =
    971 			".s0-A->:s1=>1\n" +
    972 			".s0-B->:s2=>2\n";
    973 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback
    974 		expecting =
    975 			".s0-A->:s1=>1\n" +
    976 			".s0-C->:s2=>2\n";
    977 		checkDecision(g, 2, expecting, null, null, null, null, 0); // loopback
    978 		expecting =
    979 			".s0-A->.s1\n" +
    980             ".s0-B->:s2=>1\n" +
    981             ".s1-A->.s1\n" +
    982             ".s1-B->:s2=>1\n" +
    983             ".s1-C->:s3=>2\n";
    984 		checkDecision(g, 3, expecting, null, null, null, null, 0); // rule block
    985 	}
    986 
    987 
    988     @Test
    989     public void testAOrBPlusOrAPlus() throws Exception {
    990 		Grammar g = new Grammar(
    991 			"parser grammar t;\n"+
    992 			"a : (A|B)* X | (A)+ Y;");
    993 		String expecting =
    994 			".s0-A..B->:s1=>1\n" +
    995 			".s0-X->:s2=>2\n";
    996 		checkDecision(g, 1, expecting, null, null, null, null, 0); // loopback (A|B)*
    997 		expecting =
    998 			".s0-A->:s1=>1\n" +
    999 			".s0-Y->:s2=>2\n";
   1000 		checkDecision(g, 2, expecting, null, null, null, null, 0); // loopback (A)+
   1001 		expecting =
   1002 			".s0-A->.s1\n" +
   1003             ".s0-B..X->:s2=>1\n" +
   1004             ".s1-A->.s1\n" +
   1005             ".s1-B..X->:s2=>1\n" +
   1006             ".s1-Y->:s3=>2\n";
   1007 		checkDecision(g, 3, expecting, null, null, null, null, 0); // rule
   1008 	}
   1009 
   1010 	@Test public void testLoopbackAndExit() throws Exception {
   1011 		Grammar g = new Grammar(
   1012 			"parser grammar t;\n"+
   1013 			"a : (A|B)+ B;");
   1014 		String expecting =
   1015 			".s0-A->:s3=>1\n" +
   1016 			".s0-B->.s1\n" +
   1017 			".s1-A..B->:s3=>1\n" +
   1018 			".s1-EOF->:s2=>2\n"; // sees A|B as a set
   1019 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1020 	}
   1021 
   1022 	@Test public void testOptionalAltAndBypass() throws Exception {
   1023 		Grammar g = new Grammar(
   1024 			"parser grammar t;\n"+
   1025 			"a : (A|B)? B;");
   1026 		String expecting =
   1027 			".s0-A->:s2=>1\n" +
   1028 			".s0-B->.s1\n" +
   1029 			".s1-B->:s2=>1\n" +
   1030 			".s1-EOF->:s3=>2\n";
   1031 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1032 	}
   1033 
   1034 	// R E S O L V E  S Y N  C O N F L I C T S
   1035 
   1036 	@Test public void testResolveLL1ByChoosingFirst() throws Exception {
   1037 		Grammar g = new Grammar(
   1038 			"parser grammar t;\n"+
   1039 			"a : A C | A C;");
   1040 		String expecting =
   1041 			".s0-A->.s1\n" +
   1042 			".s1-C->:s2=>1\n";
   1043 		int[] unreachableAlts = new int[] {2};
   1044 		int[] nonDetAlts = new int[] {1,2};
   1045 		String ambigInput = "A C";
   1046 		int[] danglingAlts = null;
   1047 		int numWarnings = 2;
   1048 		checkDecision(g, 1, expecting, unreachableAlts,
   1049 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1050 	}
   1051 
   1052 	@Test public void testResolveLL2ByChoosingFirst() throws Exception {
   1053 		Grammar g = new Grammar(
   1054 			"parser grammar t;\n"+
   1055 			"a : A B | A B;");
   1056 		String expecting =
   1057 			".s0-A->.s1\n" +
   1058 			".s1-B->:s2=>1\n";
   1059 		int[] unreachableAlts = new int[] {2};
   1060 		int[] nonDetAlts = new int[] {1,2};
   1061 		String ambigInput = "A B";
   1062 		int[] danglingAlts = null;
   1063 		int numWarnings = 2;
   1064 		checkDecision(g, 1, expecting, unreachableAlts,
   1065 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1066 	}
   1067 
   1068 	@Test public void testResolveLL2MixAlt() throws Exception {
   1069 		Grammar g = new Grammar(
   1070 			"parser grammar t;\n"+
   1071 			"a : A B | A C | A B | Z;");
   1072 		String expecting =
   1073 			".s0-A->.s1\n" +
   1074 			".s0-Z->:s4=>4\n" +
   1075 			".s1-B->:s2=>1\n" +
   1076 			".s1-C->:s3=>2\n";
   1077 		int[] unreachableAlts = new int[] {3};
   1078 		int[] nonDetAlts = new int[] {1,3};
   1079 		String ambigInput = "A B";
   1080 		int[] danglingAlts = null;
   1081 		int numWarnings = 2;
   1082 		checkDecision(g, 1, expecting, unreachableAlts,
   1083 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1084 	}
   1085 
   1086 	@Test public void testIndirectIFThenElseStyleAmbig() throws Exception {
   1087 		// the (c)+ loopback is ambig because it could match "CASE"
   1088 		// by entering the loop or by falling out and ignoring (s)*
   1089 		// back falling back into (cg)* loop which stats over and
   1090 		// calls cg again.  Either choice allows it to get back to
   1091 		// the same node.  The software catches it as:
   1092 		// "avoid infinite closure computation emanating from alt 1
   1093 		// of ():27|2|[8 $]" where state 27 is the first alt of (c)+
   1094 		// and 8 is the first alt of the (cg)* loop.
   1095 		Grammar g = new Grammar(
   1096 			"parser grammar t;\n" +
   1097 			"s : stat ;\n" +
   1098 			"stat : LCURLY ( cg )* RCURLY | E SEMI  ;\n" +
   1099 			"cg : (c)+ (stat)* ;\n" +
   1100 			"c : CASE E ;\n");
   1101 		String expecting =
   1102 			".s0-CASE->:s2=>1\n" +
   1103 			".s0-E..RCURLY->:s1=>2\n";
   1104 		int[] unreachableAlts = null;
   1105 		int[] nonDetAlts = new int[] {1,2};
   1106 		String ambigInput = "CASE";
   1107 		int[] danglingAlts = null;
   1108 		int numWarnings = 1;
   1109 		checkDecision(g, 3, expecting, unreachableAlts,
   1110 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1111 	}
   1112 
   1113 	// S E T S
   1114 
   1115 	@Test public void testComplement() throws Exception {
   1116 		Grammar g = new Grammar(
   1117 			"parser grammar t;\n"+
   1118 			"a : ~(A | B | C) | C {;} ;\n" +
   1119 			"b : X Y Z ;");
   1120 		String expecting =
   1121 			".s0-C->:s2=>2\n" +
   1122 			".s0-X..Z->:s1=>1\n";
   1123 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1124 	}
   1125 
   1126 	@Test public void testComplementToken() throws Exception {
   1127 		Grammar g = new Grammar(
   1128 			"parser grammar t;\n"+
   1129 			"a : ~C | C {;} ;\n" +
   1130 			"b : X Y Z ;");
   1131 		String expecting =
   1132 			".s0-C->:s2=>2\n" +
   1133 			".s0-X..Z->:s1=>1\n";
   1134 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1135 	}
   1136 
   1137 	@Test public void testComplementChar() throws Exception {
   1138 		Grammar g = new Grammar(
   1139 			"lexer grammar t;\n"+
   1140 			"A : ~'x' | 'x' {;} ;\n");
   1141 		String expecting =
   1142 			".s0-'x'->:s2=>2\n" +
   1143 			".s0-{'\\u0000'..'w', 'y'..'\\uFFFF'}->:s1=>1\n";
   1144 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1145 	}
   1146 
   1147 	@Test public void testComplementCharSet() throws Exception {
   1148 		Grammar g = new Grammar(
   1149 			"lexer grammar t;\n"+
   1150 			"A : ~(' '|'\t'|'x'|'y') | 'x';\n" + // collapse into single set
   1151 			"B : 'y' ;");
   1152 		String expecting =
   1153 			".s0-'y'->:s2=>2\n" +
   1154 			".s0-{'\\u0000'..'\\b', '\\n'..'\\u001F', '!'..'x', 'z'..'\\uFFFF'}->:s1=>1\n";
   1155 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1156 	}
   1157 
   1158 	@Test public void testNoSetCollapseWithActions() throws Exception {
   1159 		Grammar g = new Grammar(
   1160 			"parser grammar t;\n"+
   1161 			"a : (A | B {foo}) | C;");
   1162 		String expecting =
   1163 			".s0-A->:s1=>1\n" +
   1164 			".s0-B->:s2=>2\n";
   1165 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1166 	}
   1167 
   1168 	@Test public void testRuleAltsSetCollapse() throws Exception {
   1169 		Grammar g = new Grammar(
   1170 			"parser grammar t;\n"+
   1171 			"a : A | B | C ;"
   1172 		);
   1173 		String expecting = // still looks like block
   1174 			"(grammar t (rule a ARG RET scope (BLOCK (ALT A <end-of-alt>) (ALT B <end-of-alt>) (ALT C <end-of-alt>) <end-of-block>) <end-of-rule>))";
   1175 		assertEquals(expecting, g.getGrammarTree().toStringTree());
   1176 	}
   1177 
   1178 	@Test public void testTokensRuleAltsDoNotCollapse() throws Exception {
   1179 		Grammar g = new Grammar(
   1180 			"lexer grammar t;\n"+
   1181 			"A : 'a';" +
   1182 			"B : 'b';\n"
   1183 		);
   1184 		String expecting =
   1185 			".s0-'a'->:s1=>1\n" +
   1186 			".s0-'b'->:s2=>2\n";
   1187 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1188 	}
   1189 
   1190 	@Test public void testMultipleSequenceCollision() throws Exception {
   1191 		Grammar g = new Grammar(
   1192 			"parser grammar t;\n" +
   1193 			"a : (A{;}|B)\n" +
   1194 			"  | (A{;}|B)\n" +
   1195 			"  | A\n" +
   1196 			"  ;");
   1197 		String expecting =
   1198 			".s0-A->:s1=>1\n" +
   1199 			".s0-B->:s2=>1\n"; // not optimized because states are nondet
   1200 		int[] unreachableAlts = new int[] {2,3};
   1201 		int[] nonDetAlts = new int[] {1,2,3};
   1202 		String ambigInput = "A";
   1203 		int[] danglingAlts = null;
   1204 		int numWarnings = 3;
   1205 		checkDecision(g, 3, expecting, unreachableAlts,
   1206 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1207 		/* There are 2 nondet errors, but the checkDecision only checks first one :(
   1208 		The "B" conflicting input is not checked except by virtue of the
   1209 		result DFA.
   1210 <string>:2:5: Decision can match input such as "A" using multiple alternatives:
   1211 alt 1 via NFA path 7,2,3
   1212 alt 2 via NFA path 14,9,10
   1213 alt 3 via NFA path 16,17
   1214 As a result, alternative(s) 2,3 were disabled for that input,
   1215 <string>:2:5: Decision can match input such as "B" using multiple alternatives:
   1216 alt 1 via NFA path 7,8,4,5
   1217 alt 2 via NFA path 14,15,11,12
   1218 As a result, alternative(s) 2 were disabled for that input
   1219 <string>:2:5: The following alternatives are unreachable: 2,3
   1220 */
   1221 	}
   1222 
   1223 	@Test public void testMultipleAltsSameSequenceCollision() throws Exception {
   1224 		Grammar g = new Grammar(
   1225 			"parser grammar t;\n" +
   1226 			"a : type ID \n" +
   1227 			"  | type ID\n" +
   1228 			"  | type ID\n" +
   1229 			"  | type ID\n" +
   1230 			"  ;\n" +
   1231 			"\n" +
   1232 			"type : I | F;");
   1233 		// nondeterministic from left edge; no stop state
   1234 		String expecting =
   1235 			".s0-F..I->.s1\n" +
   1236 			".s1-ID->:s2=>1\n";
   1237 		int[] unreachableAlts = new int[] {2,3,4};
   1238 		int[] nonDetAlts = new int[] {1,2,3,4};
   1239 		String ambigInput = "F..I ID";
   1240 		int[] danglingAlts = null;
   1241 		int numWarnings = 2;
   1242 		checkDecision(g, 1, expecting, unreachableAlts,
   1243 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1244 	}
   1245 
   1246 	@Test public void testFollowReturnsToLoopReenteringSameRule() throws Exception {
   1247 		// D07 can be matched in the (...)? or fall out of esc back into (..)*
   1248 		// loop in sl.  Note that D07 is matched by ~(R|SLASH).  No good
   1249 		// way to write that grammar I guess
   1250 		Grammar g = new Grammar(
   1251 			"parser grammar t;\n"+
   1252 			"sl : L ( esc | ~(R|SLASH) )* R ;\n" +
   1253 			"\n" +
   1254 			"esc : SLASH ( N | D03 (D07)? ) ;");
   1255 		String expecting =
   1256 			".s0-D03..N->:s2=>2\n" +
   1257 			".s0-R->:s3=>3\n" +
   1258 			".s0-SLASH->:s1=>1\n";
   1259 		int[] unreachableAlts = null;
   1260 		int[] nonDetAlts = new int[] {1,2};
   1261 		String ambigInput = "D07";
   1262 		int[] danglingAlts = null;
   1263 		int numWarnings = 1;
   1264 		checkDecision(g, 1, expecting, unreachableAlts,
   1265 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1266 	}
   1267 
   1268 	@Test public void testTokenCallsAnotherOnLeftEdge() throws Exception {
   1269 		Grammar g = new Grammar(
   1270 			"lexer grammar t;\n"+
   1271 			"F   :   I '.'\n" +
   1272 			"    ;\n" +
   1273 			"I   :   '0'\n" +
   1274 			"    ;\n"
   1275 		);
   1276 		String expecting =
   1277 			".s0-'0'->.s1\n" +
   1278 			".s1-'.'->:s3=>1\n" +
   1279 			".s1-<EOT>->:s2=>2\n";
   1280 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1281 	}
   1282 
   1283 
   1284 	@Test public void testSelfRecursionAmbigAlts() throws Exception {
   1285 		// ambiguous grammar for "L ID R" (alts 1,2 of a)
   1286 		Grammar g = new Grammar(
   1287 			"parser grammar t;\n"+
   1288 			"s : a;\n" +
   1289 			"a   :   L ID R\n" +
   1290 			"    |   L a R\n" + // disabled for L ID R
   1291 			"    |   b\n" +
   1292 			"    ;\n" +
   1293 			"\n" +
   1294 			"b   :   ID\n" +
   1295 			"    ;\n");
   1296 		String expecting =
   1297 			".s0-ID->:s5=>3\n" +
   1298 			".s0-L->.s1\n" +
   1299 			".s1-ID->.s2\n" +
   1300 			".s1-L->:s4=>2\n" +
   1301 			".s2-R->:s3=>1\n";
   1302 		int[] unreachableAlts = null;
   1303 		int[] nonDetAlts = new int[] {1,2};
   1304 		String ambigInput = "L ID R";
   1305 		int[] danglingAlts = null;
   1306 		int numWarnings = 1;
   1307 		checkDecision(g, 1, expecting, unreachableAlts,
   1308 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1309 	}
   1310 
   1311 	@Test public void testIndirectRecursionAmbigAlts() throws Exception {
   1312 		// ambiguous grammar for "L ID R" (alts 1,2 of a)
   1313 		// This was derived from the java grammar 12/4/2004 when it
   1314 		// was not handling a unaryExpression properly.  I traced it
   1315 		// to incorrect closure-busy condition.  It thought that the trace
   1316 		// of a->b->a->b again for "L ID" was an infinite loop, but actually
   1317 		// the repeat call to b only happens *after* an L has been matched.
   1318 		// I added a check to see what the initial stack looks like and it
   1319 		// seems to work now.
   1320 		Grammar g = new Grammar(
   1321 			"parser grammar t;\n"+
   1322 			"s   :   a ;\n" +
   1323 			"a   :   L ID R\n" +
   1324 			"    |   b\n" +
   1325 			"    ;\n" +
   1326 			"\n" +
   1327 			"b   :   ID\n" +
   1328 			"    |   L a R\n" +
   1329 			"    ;");
   1330 		String expecting =
   1331 			".s0-ID->:s4=>2\n" +
   1332 			".s0-L->.s1\n" +
   1333 			".s1-ID->.s2\n" +
   1334 			".s1-L->:s4=>2\n" +
   1335 			".s2-R->:s3=>1\n";
   1336 		int[] unreachableAlts = null;
   1337 		int[] nonDetAlts = new int[] {1,2};
   1338 		String ambigInput = "L ID R";
   1339 		int[] danglingAlts = null;
   1340 		int numWarnings = 1;
   1341 		checkDecision(g, 1, expecting, unreachableAlts,
   1342 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1343 	}
   1344 
   1345 	@Test public void testTailRecursionInvokedFromArbitraryLookaheadDecision() throws Exception {
   1346 		Grammar g = new Grammar(
   1347 			"parser grammar t;\n"+
   1348 			"a : b X\n" +
   1349 			"  | b Y\n" +
   1350 			"  ;\n" +
   1351 			"\n" +
   1352 			"b : A\n" +
   1353 			"  | A b\n" +
   1354 			"  ;\n");
   1355 		List altsWithRecursion = Arrays.asList(new Object[] {1,2});
   1356 		assertNonLLStar(g, altsWithRecursion);
   1357 	}
   1358 
   1359 	@Test public void testWildcardStarK1AndNonGreedyByDefaultInParser() throws Exception {
   1360 		// no error because .* assumes it should finish when it sees R
   1361 		Grammar g = new Grammar(
   1362 			"parser grammar t;\n" +
   1363 			"s : A block EOF ;\n" +
   1364 			"block : L .* R ;");
   1365 		String expecting =
   1366 			".s0-A..L->:s2=>1\n" +
   1367 			".s0-R->:s1=>2\n";
   1368 		int[] unreachableAlts = null;
   1369 		int[] nonDetAlts = null;
   1370 		String ambigInput = null;
   1371 		int[] danglingAlts = null;
   1372 		int numWarnings = 0;
   1373 		checkDecision(g, 1, expecting, unreachableAlts,
   1374 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1375 	}
   1376 
   1377 	@Test public void testWildcardPlusK1AndNonGreedyByDefaultInParser() throws Exception {
   1378 		Grammar g = new Grammar(
   1379 			"parser grammar t;\n" +
   1380 			"s : A block EOF ;\n" +
   1381 			"block : L .+ R ;");
   1382 		String expecting =
   1383 			".s0-A..L->:s2=>1\n" +
   1384 			".s0-R->:s1=>2\n";
   1385 		int[] unreachableAlts = null;
   1386 		int[] nonDetAlts = null;
   1387 		String ambigInput = null;
   1388 		int[] danglingAlts = null;
   1389 		int numWarnings = 0;
   1390 		checkDecision(g, 1, expecting, unreachableAlts,
   1391 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1392 	}
   1393 
   1394 	@Test public void testGatedSynPred() throws Exception {
   1395 		Grammar g = new Grammar(
   1396 			"parser grammar t;\n"+
   1397 			"x   : (X)=> X\n" +
   1398 			"    | Y\n" +
   1399 			"    ;\n");
   1400 		String expecting =
   1401 			".s0-X&&{synpred1_t}?->:s1=>1\n" + // does not hoist; it gates edges
   1402 			".s0-Y->:s2=>2\n";
   1403 		int[] unreachableAlts = null;
   1404 		int[] nonDetAlts = null;
   1405 		String ambigInput = null;
   1406 		int[] danglingAlts = null;
   1407 		int numWarnings = 0;
   1408 		checkDecision(g, 1, expecting, unreachableAlts,
   1409 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1410 
   1411 		Set<String> preds = g.synPredNamesUsedInDFA;
   1412 		Set<String> expectedPreds = new HashSet<String>() {{add("synpred1_t");}};
   1413 		assertEquals("predicate names not recorded properly in grammar", expectedPreds, preds);
   1414 	}
   1415 
   1416 	@Test public void testHoistedGatedSynPred() throws Exception {
   1417 		Grammar g = new Grammar(
   1418 			"parser grammar t;\n"+
   1419 			"x   : (X)=> X\n" +
   1420 			"    | X\n" +
   1421 			"    ;\n");
   1422 		String expecting =
   1423 			".s0-X->.s1\n" +
   1424 			".s1-{synpred1_t}?->:s2=>1\n" + // hoists into decision
   1425 			".s1-{true}?->:s3=>2\n";
   1426 		int[] unreachableAlts = null;
   1427 		int[] nonDetAlts = null;
   1428 		String ambigInput = null;
   1429 		int[] danglingAlts = null;
   1430 		int numWarnings = 0;
   1431 		checkDecision(g, 1, expecting, unreachableAlts,
   1432 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1433 
   1434 		Set<String> preds = g.synPredNamesUsedInDFA;
   1435 		Set<String> expectedPreds = new HashSet<String>() {{add("synpred1_t");}};
   1436 		assertEquals("predicate names not recorded properly in grammar", expectedPreds, preds);
   1437 	}
   1438 
   1439 	@Test public void testHoistedGatedSynPred2() throws Exception {
   1440 		Grammar g = new Grammar(
   1441 			"parser grammar t;\n"+
   1442 			"x   : (X)=> (X|Y)\n" +
   1443 			"    | X\n" +
   1444 			"    ;\n");
   1445 		String expecting =
   1446 			".s0-X->.s1\n" +
   1447 			".s0-Y&&{synpred1_t}?->:s2=>1\n" +
   1448 			".s1-{synpred1_t}?->:s2=>1\n" +
   1449 			".s1-{true}?->:s3=>2\n";
   1450 		int[] unreachableAlts = null;
   1451 		int[] nonDetAlts = null;
   1452 		String ambigInput = null;
   1453 		int[] danglingAlts = null;
   1454 		int numWarnings = 0;
   1455 		checkDecision(g, 1, expecting, unreachableAlts,
   1456 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1457 
   1458 		Set<String> preds = g.synPredNamesUsedInDFA;
   1459 		Set<String> expectedPreds = new HashSet<String>() {{add("synpred1_t");}};
   1460 		assertEquals("predicate names not recorded properly in grammar", expectedPreds, preds);
   1461 	}
   1462 
   1463 	@Test public void testGreedyGetsNoErrorForAmbig() throws Exception {
   1464 		Grammar g = new Grammar(
   1465 			"parser grammar t;\n"+
   1466 			"s : IF s (options {greedy=true;} : E s)? | B;\n" +
   1467 			"slist: s SEMI ;");
   1468 		String expecting =
   1469 			".s0-E->:s1=>1\n" +
   1470 			".s0-SEMI->:s2=>2\n";
   1471 		int[] unreachableAlts = null;
   1472 		int[] nonDetAlts = null;
   1473 		String ambigInput = null;
   1474 		int[] danglingAlts = null;
   1475 		int numWarnings = 0;
   1476 		checkDecision(g, 1, expecting, unreachableAlts,
   1477 					  nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1478 		expecting =
   1479 			".s0-B->:s2=>2\n" +
   1480 			".s0-IF->:s1=>1\n";
   1481 		checkDecision(g, 2, expecting, null, null, null, null, 0);
   1482 	}
   1483 
   1484 	@Test public void testGreedyNonLLStarStillGetsError() throws Exception {
   1485 		Grammar g = new Grammar(
   1486 			"parser grammar t;\n"+
   1487 			"x   : ( options {greedy=true;}\n" +
   1488 			"	   : y X\n" +
   1489 			"      | y Y\n" +
   1490 			"	   )\n" +
   1491 			"    ;\n" +
   1492 			"y   : L y R\n" +
   1493 			"    | B\n" +
   1494 			"    ;");
   1495 		List altsWithRecursion = Arrays.asList(new Object[] {1,2});
   1496 		assertNonLLStar(g, altsWithRecursion);
   1497 	}
   1498 
   1499 	@Test public void testGreedyRecOverflowStillGetsError() throws Exception {
   1500 		Grammar g = new Grammar(
   1501 			"parser grammar t;\n"+
   1502 			"s : (options {greedy=true;} : a Y | A A A A A X) ;\n" + // force recursion past m=4
   1503 			"a : A a | Q;");
   1504 		List expectedTargetRules = Arrays.asList(new Object[] {"a"});
   1505 		int expectedAlt = 1;
   1506 		assertRecursionOverflow(g, expectedTargetRules, expectedAlt);
   1507 	}
   1508 
   1509 
   1510 	// Check state table creation
   1511 
   1512 	@Test public void testCyclicTableCreation() throws Exception {
   1513 		Grammar g = new Grammar(
   1514 			"parser grammar t;\n"+
   1515 			"a : A+ X | A+ Y ;");
   1516 		String expecting =
   1517 			".s0-A->:s1=>1\n" +
   1518 			".s0-B->:s2=>2\n";
   1519 	}
   1520 
   1521 
   1522 	// S U P P O R T
   1523 
   1524 	public void _template() throws Exception {
   1525 		Grammar g = new Grammar(
   1526 			"parser grammar t;\n"+
   1527 			"a : A | B;");
   1528 		String expecting =
   1529 			"\n";
   1530 		checkDecision(g, 1, expecting, null, null, null, null, 0);
   1531 	}
   1532 
   1533 	protected void assertNonLLStar(Grammar g, List expectedBadAlts) {
   1534 		DecisionProbe.verbose=true; // make sure we get all error info
   1535 		ErrorQueue equeue = new ErrorQueue();
   1536 		ErrorManager.setErrorListener(equeue);
   1537 
   1538 		// mimic actions of org.antlr.Tool first time for grammar g
   1539 		if ( g.getNumberOfDecisions()==0 ) {
   1540 			g.buildNFA();
   1541 			g.createLookaheadDFAs(false);
   1542 		}
   1543 		NonRegularDecisionMessage msg = getNonRegularDecisionMessage(equeue.errors);
   1544 		assertTrue("expected fatal non-LL(*) msg", msg!=null);
   1545 		List<Integer> alts = new ArrayList();
   1546 		alts.addAll(msg.altsWithRecursion);
   1547 		Collections.sort(alts);
   1548 		assertEquals(expectedBadAlts,alts);
   1549 	}
   1550 
   1551 	protected void assertRecursionOverflow(Grammar g,
   1552 										   List expectedTargetRules,
   1553 										   int expectedAlt) {
   1554 		DecisionProbe.verbose=true; // make sure we get all error info
   1555 		ErrorQueue equeue = new ErrorQueue();
   1556 		ErrorManager.setErrorListener(equeue);
   1557 
   1558 		// mimic actions of org.antlr.Tool first time for grammar g
   1559 		if ( g.getNumberOfDecisions()==0 ) {
   1560 			g.buildNFA();
   1561 			g.createLookaheadDFAs(false);
   1562 		}
   1563 		RecursionOverflowMessage msg = getRecursionOverflowMessage(equeue.errors);
   1564 		assertTrue("missing expected recursion overflow msg"+msg, msg!=null);
   1565 		assertEquals("target rules mismatch",
   1566 					 expectedTargetRules.toString(), msg.targetRules.toString());
   1567 		assertEquals("mismatched alt", expectedAlt, msg.alt);
   1568 	}
   1569 
   1570     @Test
   1571     public void testWildcardInTreeGrammar() throws Exception {
   1572         Grammar g = new Grammar(
   1573             "tree grammar t;\n" +
   1574             "a : A B | A . ;\n");
   1575         String expecting =
   1576             ".s0-A->.s1\n" +
   1577             ".s1-A->:s3=>2\n" +
   1578             ".s1-B->:s2=>1\n";
   1579         int[] unreachableAlts = null;
   1580         int[] nonDetAlts = new int[] {1,2};
   1581         String ambigInput = null;
   1582         int[] danglingAlts = null;
   1583         int numWarnings = 1;
   1584         checkDecision(g, 1, expecting, unreachableAlts,
   1585                       nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1586     }
   1587 
   1588     @Test
   1589     public void testWildcardInTreeGrammar2() throws Exception {
   1590         Grammar g = new Grammar(
   1591             "tree grammar t;\n" +
   1592             "a : ^(A X Y) | ^(A . .) ;\n");
   1593         String expecting =
   1594             ".s0-A->.s1\n" +
   1595             ".s1-DOWN->.s2\n" +
   1596             ".s2-X->.s3\n" +
   1597             ".s2-{A, Y}->:s6=>2\n" +
   1598             ".s3-Y->.s4\n" +
   1599             ".s3-{DOWN, A..X}->:s6=>2\n" +
   1600             ".s4-DOWN->:s6=>2\n" +
   1601             ".s4-UP->:s5=>1\n";
   1602         int[] unreachableAlts = null;
   1603         int[] nonDetAlts = new int[] {1,2};
   1604         String ambigInput = null;
   1605         int[] danglingAlts = null;
   1606         int numWarnings = 1;
   1607         checkDecision(g, 1, expecting, unreachableAlts,
   1608                       nonDetAlts, ambigInput, danglingAlts, numWarnings);
   1609     }
   1610 
   1611     protected void checkDecision(Grammar g,
   1612 								 int decision,
   1613 								 String expecting,
   1614 								 int[] expectingUnreachableAlts,
   1615 								 int[] expectingNonDetAlts,
   1616 								 String expectingAmbigInput,
   1617 								 int[] expectingDanglingAlts,
   1618 								 int expectingNumWarnings)
   1619 		throws Exception
   1620 	{
   1621 		DecisionProbe.verbose=true; // make sure we get all error info
   1622 		ErrorQueue equeue = new ErrorQueue();
   1623 		ErrorManager.setErrorListener(equeue);
   1624 
   1625 		// mimic actions of org.antlr.Tool first time for grammar g
   1626 		if ( g.getNumberOfDecisions()==0 ) {
   1627 			g.buildNFA();
   1628 			g.createLookaheadDFAs(false);
   1629 		}
   1630 		CodeGenerator generator = new CodeGenerator(newTool(), g, "Java");
   1631 		g.setCodeGenerator(generator);
   1632 
   1633 		if ( equeue.size()!=expectingNumWarnings ) {
   1634 			System.err.println("Warnings issued: "+equeue);
   1635 		}
   1636 
   1637 		assertEquals("unexpected number of expected problems",
   1638 				   expectingNumWarnings, equeue.size());
   1639 
   1640 		DFA dfa = g.getLookaheadDFA(decision);
   1641 		assertNotNull("no DFA for decision "+decision, dfa);
   1642 		FASerializer serializer = new FASerializer(g);
   1643 		String result = serializer.serialize(dfa.startState);
   1644 
   1645 		List unreachableAlts = dfa.getUnreachableAlts();
   1646 
   1647 		// make sure unreachable alts are as expected
   1648 		if ( expectingUnreachableAlts!=null ) {
   1649 			BitSet s = new BitSet();
   1650 			s.addAll(expectingUnreachableAlts);
   1651 			BitSet s2 = new BitSet();
   1652 			s2.addAll(unreachableAlts);
   1653 			assertEquals("unreachable alts mismatch", s, s2);
   1654 		}
   1655 		else {
   1656 			assertEquals("number of unreachable alts", 0,
   1657 						 unreachableAlts!=null?unreachableAlts.size():0);
   1658 		}
   1659 
   1660 		// check conflicting input
   1661 		if ( expectingAmbigInput!=null ) {
   1662 			// first, find nondet message
   1663 			Message msg = (Message)equeue.warnings.get(0);
   1664 			assertTrue("expecting nondeterminism; found "+msg.getClass().getName(),
   1665 					    msg instanceof GrammarNonDeterminismMessage);
   1666 			GrammarNonDeterminismMessage nondetMsg =
   1667 				getNonDeterminismMessage(equeue.warnings);
   1668 			List labels =
   1669 				nondetMsg.probe.getSampleNonDeterministicInputSequence(nondetMsg.problemState);
   1670 			String input = nondetMsg.probe.getInputSequenceDisplay(labels);
   1671 			assertEquals(expectingAmbigInput, input);
   1672 		}
   1673 
   1674 		// check nondet alts
   1675 		if ( expectingNonDetAlts!=null ) {
   1676 			RecursionOverflowMessage recMsg = null;
   1677 			GrammarNonDeterminismMessage nondetMsg =
   1678 				getNonDeterminismMessage(equeue.warnings);
   1679 			List nonDetAlts = null;
   1680 			if ( nondetMsg!=null ) {
   1681 				nonDetAlts =
   1682 					nondetMsg.probe.getNonDeterministicAltsForState(nondetMsg.problemState);
   1683 			}
   1684 			else {
   1685 				recMsg = getRecursionOverflowMessage(equeue.warnings);
   1686 				if ( recMsg!=null ) {
   1687 					//nonDetAlts = new ArrayList(recMsg.alts);
   1688 				}
   1689 			}
   1690 			// compare nonDetAlts with expectingNonDetAlts
   1691 			BitSet s = new BitSet();
   1692 			s.addAll(expectingNonDetAlts);
   1693 			BitSet s2 = new BitSet();
   1694 			s2.addAll(nonDetAlts);
   1695 			assertEquals("nondet alts mismatch", s, s2);
   1696 			assertTrue("found no nondet alts; expecting: "+
   1697 					    str(expectingNonDetAlts),
   1698 					    nondetMsg!=null||recMsg!=null);
   1699 		}
   1700 		else {
   1701 			// not expecting any nondet alts, make sure there are none
   1702 			GrammarNonDeterminismMessage nondetMsg =
   1703 				getNonDeterminismMessage(equeue.warnings);
   1704 			assertNull("found nondet alts, but expecting none", nondetMsg);
   1705 		}
   1706 
   1707 		assertEquals(expecting, result);
   1708 	}
   1709 
   1710 	protected GrammarNonDeterminismMessage getNonDeterminismMessage(List warnings) {
   1711 		for (int i = 0; i < warnings.size(); i++) {
   1712 			Message m = (Message) warnings.get(i);
   1713 			if ( m instanceof GrammarNonDeterminismMessage ) {
   1714 				return (GrammarNonDeterminismMessage)m;
   1715 			}
   1716 		}
   1717 		return null;
   1718 	}
   1719 
   1720 	protected NonRegularDecisionMessage getNonRegularDecisionMessage(List errors) {
   1721 		for (int i = 0; i < errors.size(); i++) {
   1722 			Message m = (Message) errors.get(i);
   1723 			if ( m instanceof NonRegularDecisionMessage ) {
   1724 				return (NonRegularDecisionMessage)m;
   1725 			}
   1726 		}
   1727 		return null;
   1728 	}
   1729 
   1730 	protected RecursionOverflowMessage getRecursionOverflowMessage(List warnings) {
   1731 		for (int i = 0; i < warnings.size(); i++) {
   1732 			Message m = (Message) warnings.get(i);
   1733 			if ( m instanceof RecursionOverflowMessage ) {
   1734 				return (RecursionOverflowMessage)m;
   1735 			}
   1736 		}
   1737 		return null;
   1738 	}
   1739 
   1740 	protected LeftRecursionCyclesMessage getLeftRecursionCyclesMessage(List warnings) {
   1741 		for (int i = 0; i < warnings.size(); i++) {
   1742 			Message m = (Message) warnings.get(i);
   1743 			if ( m instanceof LeftRecursionCyclesMessage ) {
   1744 				return (LeftRecursionCyclesMessage)m;
   1745 			}
   1746 		}
   1747 		return null;
   1748 	}
   1749 
   1750 	protected GrammarDanglingStateMessage getDanglingStateMessage(List warnings) {
   1751 		for (int i = 0; i < warnings.size(); i++) {
   1752 			Message m = (Message) warnings.get(i);
   1753 			if ( m instanceof GrammarDanglingStateMessage ) {
   1754 				return (GrammarDanglingStateMessage)m;
   1755 			}
   1756 		}
   1757 		return null;
   1758 	}
   1759 
   1760 	protected String str(int[] elements) {
   1761 		StringBuffer buf = new StringBuffer();
   1762 		for (int i = 0; i < elements.length; i++) {
   1763 			if ( i>0 ) {
   1764 				buf.append(", ");
   1765 			}
   1766 			int element = elements[i];
   1767 			buf.append(element);
   1768 		}
   1769 		return buf.toString();
   1770 	}
   1771 
   1772 	protected Set<String> ruleNames(Set<Rule> rules) {
   1773 		Set<String> x = new HashSet<String>();
   1774 		for (Rule r : rules) {
   1775 			x.add(r.name);
   1776 		}
   1777 		return x;
   1778 	}
   1779 
   1780 	protected Set<String> ruleNames2(Collection<HashSet> rules) {
   1781 		Set<String> x = new HashSet<String>();
   1782 		for (HashSet s : rules) {
   1783 			x.addAll(ruleNames(s));
   1784 		}
   1785 		return x;
   1786 	}
   1787 }
   1788