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.analysis.DFA; 31 import org.antlr.analysis.DFAOptimizer; 32 import org.antlr.codegen.CodeGenerator; 33 import org.antlr.tool.*; 34 import org.junit.Test; 35 36 import java.util.List; 37 38 public class TestCharDFAConversion extends BaseTest { 39 40 /** Public default constructor used by TestRig */ TestCharDFAConversion()41 public TestCharDFAConversion() { 42 } 43 44 // R A N G E S & S E T S 45 testSimpleRangeVersusChar()46 @Test public void testSimpleRangeVersusChar() throws Exception { 47 Grammar g = new Grammar( 48 "lexer grammar t;\n"+ 49 "A : 'a'..'z' '@' | 'k' '$' ;"); 50 g.createLookaheadDFAs(); 51 String expecting = 52 ".s0-'k'->.s1\n" + 53 ".s0-{'a'..'j', 'l'..'z'}->:s2=>1\n" + 54 ".s1-'$'->:s3=>2\n" + 55 ".s1-'@'->:s2=>1\n"; 56 checkDecision(g, 1, expecting, null); 57 } 58 testRangeWithDisjointSet()59 @Test public void testRangeWithDisjointSet() throws Exception { 60 Grammar g = new Grammar( 61 "lexer grammar t;\n"+ 62 "A : 'a'..'z' '@'\n" + 63 " | ('k'|'9'|'p') '$'\n" + 64 " ;\n"); 65 g.createLookaheadDFAs(); 66 // must break up a..z into {'a'..'j', 'l'..'o', 'q'..'z'} 67 String expecting = 68 ".s0-'9'->:s3=>2\n" + 69 ".s0-{'a'..'j', 'l'..'o', 'q'..'z'}->:s2=>1\n" + 70 ".s0-{'k', 'p'}->.s1\n" + 71 ".s1-'$'->:s3=>2\n" + 72 ".s1-'@'->:s2=>1\n"; 73 checkDecision(g, 1, expecting, null); 74 } 75 testDisjointSetCollidingWithTwoRanges()76 @Test public void testDisjointSetCollidingWithTwoRanges() throws Exception { 77 Grammar g = new Grammar( 78 "lexer grammar t;\n"+ 79 "A : ('a'..'z'|'0'..'9') '@'\n" + 80 " | ('k'|'9'|'p') '$'\n" + 81 " ;\n"); 82 g.createLookaheadDFAs(false); 83 // must break up a..z into {'a'..'j', 'l'..'o', 'q'..'z'} and 0..9 84 // into 0..8 85 String expecting = 86 ".s0-{'0'..'8', 'a'..'j', 'l'..'o', 'q'..'z'}->:s2=>1\n" + 87 ".s0-{'9', 'k', 'p'}->.s1\n" + 88 ".s1-'$'->:s3=>2\n" + 89 ".s1-'@'->:s2=>1\n"; 90 checkDecision(g, 1, expecting, null); 91 } 92 testDisjointSetCollidingWithTwoRangesCharsFirst()93 @Test public void testDisjointSetCollidingWithTwoRangesCharsFirst() throws Exception { 94 Grammar g = new Grammar( 95 "lexer grammar t;\n"+ 96 "A : ('k'|'9'|'p') '$'\n" + 97 " | ('a'..'z'|'0'..'9') '@'\n" + 98 " ;\n"); 99 // must break up a..z into {'a'..'j', 'l'..'o', 'q'..'z'} and 0..9 100 // into 0..8 101 String expecting = 102 ".s0-{'0'..'8', 'a'..'j', 'l'..'o', 'q'..'z'}->:s3=>2\n" + 103 ".s0-{'9', 'k', 'p'}->.s1\n" + 104 ".s1-'$'->:s2=>1\n" + 105 ".s1-'@'->:s3=>2\n"; 106 checkDecision(g, 1, expecting, null); 107 } 108 testDisjointSetCollidingWithTwoRangesAsSeparateAlts()109 @Test public void testDisjointSetCollidingWithTwoRangesAsSeparateAlts() throws Exception { 110 Grammar g = new Grammar( 111 "lexer grammar t;\n"+ 112 "A : 'a'..'z' '@'\n" + 113 " | 'k' '$'\n" + 114 " | '9' '$'\n" + 115 " | 'p' '$'\n" + 116 " | '0'..'9' '@'\n" + 117 " ;\n"); 118 // must break up a..z into {'a'..'j', 'l'..'o', 'q'..'z'} and 0..9 119 // into 0..8 120 String expecting = 121 ".s0-'0'..'8'->:s8=>5\n" + 122 ".s0-'9'->.s6\n" + 123 ".s0-'k'->.s1\n" + 124 ".s0-'p'->.s4\n" + 125 ".s0-{'a'..'j', 'l'..'o', 'q'..'z'}->:s2=>1\n" + 126 ".s1-'$'->:s3=>2\n" + 127 ".s1-'@'->:s2=>1\n" + 128 ".s4-'$'->:s5=>4\n" + 129 ".s4-'@'->:s2=>1\n" + 130 ".s6-'$'->:s7=>3\n" + 131 ".s6-'@'->:s8=>5\n"; 132 checkDecision(g, 1, expecting, null); 133 } 134 testKeywordVersusID()135 @Test public void testKeywordVersusID() throws Exception { 136 Grammar g = new Grammar( 137 "lexer grammar t;\n"+ 138 "IF : 'if' ;\n" + // choose this over ID 139 "ID : ('a'..'z')+ ;\n"); 140 String expecting = 141 ".s0-'a'..'z'->:s2=>1\n" + 142 ".s0-<EOT>->:s1=>2\n"; 143 checkDecision(g, 1, expecting, null); 144 expecting = 145 ".s0-'i'->.s1\n" + 146 ".s0-{'a'..'h', 'j'..'z'}->:s4=>2\n" + 147 ".s1-'f'->.s2\n" + 148 ".s1-<EOT>->:s4=>2\n" + 149 ".s2-'a'..'z'->:s4=>2\n" + 150 ".s2-<EOT>->:s3=>1\n"; 151 checkDecision(g, 2, expecting, null); 152 } 153 testIdenticalRules()154 @Test public void testIdenticalRules() throws Exception { 155 Grammar g = new Grammar( 156 "lexer grammar t;\n"+ 157 "A : 'a' ;\n" + 158 "B : 'a' ;\n"); // can't reach this 159 String expecting = 160 ".s0-'a'->.s1\n" + 161 ".s1-<EOT>->:s2=>1\n"; 162 163 ErrorQueue equeue = new ErrorQueue(); 164 ErrorManager.setErrorListener(equeue); 165 166 checkDecision(g, 1, expecting, new int[] {2}); 167 168 assertEquals("unexpected number of expected problems", 169 1, equeue.size()); 170 Message msg = (Message)equeue.errors.get(0); 171 assertTrue("warning must be an unreachable alt", 172 msg instanceof GrammarUnreachableAltsMessage); 173 GrammarUnreachableAltsMessage u = (GrammarUnreachableAltsMessage)msg; 174 assertEquals("[2]", u.alts.toString()); 175 176 } 177 testAdjacentNotCharLoops()178 @Test public void testAdjacentNotCharLoops() throws Exception { 179 Grammar g = new Grammar( 180 "lexer grammar t;\n"+ 181 "A : (~'r')+ ;\n" + 182 "B : (~'s')+ ;\n"); 183 String expecting = 184 ".s0-'r'->:s3=>2\n" + 185 ".s0-'s'->:s2=>1\n" + 186 ".s0-{'\\u0000'..'q', 't'..'\\uFFFF'}->.s1\n" + 187 ".s1-'r'->:s3=>2\n" + 188 ".s1-<EOT>->:s2=>1\n" + 189 ".s1-{'\\u0000'..'q', 't'..'\\uFFFF'}->.s1\n"; 190 checkDecision(g, 3, expecting, null); 191 } 192 testNonAdjacentNotCharLoops()193 @Test public void testNonAdjacentNotCharLoops() throws Exception { 194 Grammar g = new Grammar( 195 "lexer grammar t;\n"+ 196 "A : (~'r')+ ;\n" + 197 "B : (~'t')+ ;\n"); 198 String expecting = 199 ".s0-'r'->:s3=>2\n" + 200 ".s0-'t'->:s2=>1\n" + 201 ".s0-{'\\u0000'..'q', 's', 'u'..'\\uFFFF'}->.s1\n" + 202 ".s1-'r'->:s3=>2\n" + 203 ".s1-<EOT>->:s2=>1\n" + 204 ".s1-{'\\u0000'..'q', 's', 'u'..'\\uFFFF'}->.s1\n"; 205 checkDecision(g, 3, expecting, null); 206 } 207 testLoopsWithOptimizedOutExitBranches()208 @Test public void testLoopsWithOptimizedOutExitBranches() throws Exception { 209 Grammar g = new Grammar( 210 "lexer grammar t;\n"+ 211 "A : 'x'* ~'x'+ ;\n"); 212 String expecting = 213 ".s0-'x'->:s1=>1\n" + 214 ".s0-{'\\u0000'..'w', 'y'..'\\uFFFF'}->:s2=>2\n"; 215 checkDecision(g, 1, expecting, null); 216 217 // The optimizer yanks out all exit branches from EBNF blocks 218 // This is ok because we've already verified there are no problems 219 // with the enter/exit decision 220 DFAOptimizer optimizer = new DFAOptimizer(g); 221 optimizer.optimize(); 222 FASerializer serializer = new FASerializer(g); 223 DFA dfa = g.getLookaheadDFA(1); 224 String result = serializer.serialize(dfa.startState); 225 expecting = ".s0-'x'->:s1=>1\n"; 226 assertEquals(expecting, result); 227 } 228 229 // N O N G R E E D Y 230 testNonGreedy()231 @Test public void testNonGreedy() throws Exception { 232 Grammar g = new Grammar( 233 "lexer grammar t;\n"+ 234 "CMT : '/*' ( options {greedy=false;} : . )* '*/' ;"); 235 String expecting = 236 ".s0-'*'->.s1\n" + 237 ".s0-{'\\u0000'..')', '+'..'\\uFFFF'}->:s3=>1\n" + 238 ".s1-'/'->:s2=>2\n" + 239 ".s1-{'\\u0000'..'.', '0'..'\\uFFFF'}->:s3=>1\n"; 240 checkDecision(g, 1, expecting, null); 241 } 242 testNonGreedyWildcardStar()243 @Test public void testNonGreedyWildcardStar() throws Exception { 244 Grammar g = new Grammar( 245 "lexer grammar t;\n"+ 246 "SLCMT : '//' ( options {greedy=false;} : . )* '\n' ;"); 247 String expecting = 248 ".s0-'\\n'->:s1=>2\n" + 249 ".s0-{'\\u0000'..'\\t', '\\u000B'..'\\uFFFF'}->:s2=>1\n"; 250 checkDecision(g, 1, expecting, null); 251 } 252 testNonGreedyByDefaultWildcardStar()253 @Test public void testNonGreedyByDefaultWildcardStar() throws Exception { 254 Grammar g = new Grammar( 255 "lexer grammar t;\n"+ 256 "SLCMT : '//' .* '\n' ;"); 257 String expecting = 258 ".s0-'\\n'->:s1=>2\n" + 259 ".s0-{'\\u0000'..'\\t', '\\u000B'..'\\uFFFF'}->:s2=>1\n"; 260 checkDecision(g, 1, expecting, null); 261 } 262 testNonGreedyWildcardPlus()263 @Test public void testNonGreedyWildcardPlus() throws Exception { 264 // same DFA as nongreedy .* but code gen checks number of 265 // iterations at runtime 266 Grammar g = new Grammar( 267 "lexer grammar t;\n"+ 268 "SLCMT : '//' ( options {greedy=false;} : . )+ '\n' ;"); 269 String expecting = 270 ".s0-'\\n'->:s1=>2\n" + 271 ".s0-{'\\u0000'..'\\t', '\\u000B'..'\\uFFFF'}->:s2=>1\n"; 272 checkDecision(g, 1, expecting, null); 273 } 274 testNonGreedyByDefaultWildcardPlus()275 @Test public void testNonGreedyByDefaultWildcardPlus() throws Exception { 276 Grammar g = new Grammar( 277 "lexer grammar t;\n"+ 278 "SLCMT : '//' .+ '\n' ;"); 279 String expecting = 280 ".s0-'\\n'->:s1=>2\n" + 281 ".s0-{'\\u0000'..'\\t', '\\u000B'..'\\uFFFF'}->:s2=>1\n"; 282 checkDecision(g, 1, expecting, null); 283 } 284 testNonGreedyByDefaultWildcardPlusWithParens()285 @Test public void testNonGreedyByDefaultWildcardPlusWithParens() throws Exception { 286 Grammar g = new Grammar( 287 "lexer grammar t;\n"+ 288 "SLCMT : '//' (.)+ '\n' ;"); 289 String expecting = 290 ".s0-'\\n'->:s1=>2\n" + 291 ".s0-{'\\u0000'..'\\t', '\\u000B'..'\\uFFFF'}->:s2=>1\n"; 292 checkDecision(g, 1, expecting, null); 293 } 294 testNonWildcardNonGreedy()295 @Test public void testNonWildcardNonGreedy() throws Exception { 296 Grammar g = new Grammar( 297 "lexer grammar t;\n"+ 298 "DUH : (options {greedy=false;}:'x'|'y')* 'xy' ;"); 299 String expecting = 300 ".s0-'x'->.s1\n" + 301 ".s0-'y'->:s4=>2\n" + 302 ".s1-'x'->:s3=>1\n" + 303 ".s1-'y'->:s2=>3\n"; 304 checkDecision(g, 1, expecting, null); 305 } 306 testNonWildcardEOTMakesItWorkWithoutNonGreedyOption()307 @Test public void testNonWildcardEOTMakesItWorkWithoutNonGreedyOption() throws Exception { 308 Grammar g = new Grammar( 309 "lexer grammar t;\n"+ 310 "DUH : ('x'|'y')* 'xy' ;"); 311 String expecting = 312 ".s0-'x'->.s1\n" + 313 ".s0-'y'->:s4=>1\n" + 314 ".s1-'x'->:s4=>1\n" + 315 ".s1-'y'->.s2\n" + 316 ".s2-'x'..'y'->:s4=>1\n" + 317 ".s2-<EOT>->:s3=>2\n"; 318 checkDecision(g, 1, expecting, null); 319 } 320 testAltConflictsWithLoopThenExit()321 @Test public void testAltConflictsWithLoopThenExit() throws Exception { 322 // \" predicts alt 1, but wildcard then " can predict exit also 323 Grammar g = new Grammar( 324 "lexer grammar t;\n"+ 325 "STRING : '\"' (options {greedy=false;}: '\\\\\"' | .)* '\"' ;\n" 326 ); 327 String expecting = 328 ".s0-'\"'->:s1=>3\n" + 329 ".s0-'\\\\'->.s2\n" + 330 ".s0-{'\\u0000'..'!', '#'..'[', ']'..'\\uFFFF'}->:s4=>2\n" + 331 ".s2-'\"'->:s3=>1\n" + 332 ".s2-{'\\u0000'..'!', '#'..'\\uFFFF'}->:s4=>2\n"; 333 checkDecision(g, 1, expecting, null); 334 } 335 testNonGreedyLoopThatNeverLoops()336 @Test public void testNonGreedyLoopThatNeverLoops() throws Exception { 337 Grammar g = new Grammar( 338 "lexer grammar t;\n"+ 339 "DUH : (options {greedy=false;}:'x')+ ;"); // loop never matched 340 String expecting = 341 ":s0=>2\n"; 342 343 ErrorQueue equeue = new ErrorQueue(); 344 ErrorManager.setErrorListener(equeue); 345 346 checkDecision(g, 1, expecting, new int[] {1}); 347 348 assertEquals("unexpected number of expected problems", 349 1, equeue.size()); 350 Message msg = (Message)equeue.errors.get(0); 351 assertTrue("warning must be an unreachable alt", 352 msg instanceof GrammarUnreachableAltsMessage); 353 GrammarUnreachableAltsMessage u = (GrammarUnreachableAltsMessage)msg; 354 assertEquals("[1]", u.alts.toString()); 355 } 356 testRecursive()357 @Test public void testRecursive() throws Exception { 358 // this is cool because the 3rd alt includes !(all other possibilities) 359 Grammar g = new Grammar( 360 "lexer grammar duh;\n" + 361 "SUBTEMPLATE\n" + 362 " : '{'\n" + 363 " ( SUBTEMPLATE\n" + 364 " | ESC\n" + 365 " | ~('}'|'\\\\'|'{')\n" + 366 " )*\n" + 367 " '}'\n" + 368 " ;\n" + 369 "fragment\n" + 370 "ESC : '\\\\' . ;"); 371 g.createLookaheadDFAs(); 372 String expecting = 373 ".s0-'\\\\'->:s2=>2\n" + 374 ".s0-'{'->:s1=>1\n" + 375 ".s0-'}'->:s4=>4\n" + 376 ".s0-{'\\u0000'..'[', ']'..'z', '|', '~'..'\\uFFFF'}->:s3=>3\n"; 377 checkDecision(g, 1, expecting, null); 378 } 379 testRecursive2()380 @Test public void testRecursive2() throws Exception { 381 // this is also cool because it resolves \\ to be ESC alt; it's just 382 // less efficient of a DFA 383 Grammar g = new Grammar( 384 "lexer grammar duh;\n" + 385 "SUBTEMPLATE\n" + 386 " : '{'\n" + 387 " ( SUBTEMPLATE\n" + 388 " | ESC\n" + 389 " | ~('}'|'{')\n" + 390 " )*\n" + 391 " '}'\n" + 392 " ;\n" + 393 "fragment\n" + 394 "ESC : '\\\\' . ;"); 395 g.createLookaheadDFAs(); 396 String expecting = 397 ".s0-'\\\\'->.s3\n" + 398 ".s0-'{'->:s2=>1\n" + 399 ".s0-'}'->:s1=>4\n" + 400 ".s0-{'\\u0000'..'[', ']'..'z', '|', '~'..'\\uFFFF'}->:s5=>3\n" + 401 ".s3-'\\\\'->:s8=>2\n" + 402 ".s3-'{'->:s7=>2\n" + 403 ".s3-'}'->.s4\n" + 404 ".s3-{'\\u0000'..'[', ']'..'z', '|', '~'..'\\uFFFF'}->:s6=>2\n" + 405 ".s4-'\\u0000'..'\\uFFFF'->:s6=>2\n" + 406 ".s4-<EOT>->:s5=>3\n"; 407 checkDecision(g, 1, expecting, null); 408 } 409 testNotFragmentInLexer()410 @Test public void testNotFragmentInLexer() throws Exception { 411 Grammar g = new Grammar( 412 "lexer grammar T;\n"+ 413 "A : 'a' | ~B {;} ;\n" + 414 "fragment B : 'a' ;\n"); 415 g.createLookaheadDFAs(); 416 String expecting = 417 ".s0-'a'->:s1=>1\n" + 418 ".s0-{'\\u0000'..'`', 'b'..'\\uFFFF'}->:s2=>2\n"; 419 checkDecision(g, 1, expecting, null); 420 } 421 testNotSetFragmentInLexer()422 @Test public void testNotSetFragmentInLexer() throws Exception { 423 Grammar g = new Grammar( 424 "lexer grammar T;\n"+ 425 "A : B | ~B {;} ;\n" + 426 "fragment B : 'a'|'b' ;\n"); 427 g.createLookaheadDFAs(); 428 String expecting = 429 ".s0-'a'..'b'->:s1=>1\n" + 430 ".s0-{'\\u0000'..'`', 'c'..'\\uFFFF'}->:s2=>2\n"; 431 checkDecision(g, 1, expecting, null); 432 } 433 testNotTokenInLexer()434 @Test public void testNotTokenInLexer() throws Exception { 435 Grammar g = new Grammar( 436 "lexer grammar T;\n"+ 437 "A : 'x' ('a' | ~B {;}) ;\n" + 438 "B : 'a' ;\n"); 439 g.createLookaheadDFAs(); 440 String expecting = 441 ".s0-'a'->:s1=>1\n" + 442 ".s0-{'\\u0000'..'`', 'b'..'\\uFFFF'}->:s2=>2\n"; 443 checkDecision(g, 1, expecting, null); 444 } 445 testNotComplicatedSetRuleInLexer()446 @Test public void testNotComplicatedSetRuleInLexer() throws Exception { 447 Grammar g = new Grammar( 448 "lexer grammar T;\n"+ 449 "A : B | ~B {;} ;\n" + 450 "fragment B : 'a'|'b'|'c'..'e'|C ;\n" + 451 "fragment C : 'f' ;\n"); // has to seen from B to C 452 String expecting = 453 ".s0-'a'..'f'->:s1=>1\n" + 454 ".s0-{'\\u0000'..'`', 'g'..'\\uFFFF'}->:s2=>2\n"; 455 checkDecision(g, 1, expecting, null); 456 } 457 testNotSetWithRuleInLexer()458 @Test public void testNotSetWithRuleInLexer() throws Exception { 459 Grammar g = new Grammar( 460 "lexer grammar T;\n"+ 461 "T : ~('a' | B) | 'a';\n" + 462 "fragment\n" + 463 "B : 'b' ;\n" + 464 "C : ~'x'{;} ;"); // force Tokens to not collapse T|C 465 String expecting = 466 ".s0-'b'->:s3=>2\n" + 467 ".s0-'x'->:s2=>1\n" + 468 ".s0-{'\\u0000'..'a', 'c'..'w', 'y'..'\\uFFFF'}->.s1\n" + 469 ".s1-<EOT>->:s2=>1\n"; 470 checkDecision(g, 1, expecting, null); 471 } 472 testSetCallsRuleWithNot()473 @Test public void testSetCallsRuleWithNot() throws Exception { 474 Grammar g = new Grammar( 475 "lexer grammar A;\n" + 476 "T : ~'x' ;\n" + 477 "S : 'x' (T | 'x') ;\n"); 478 String expecting = 479 ".s0-'x'->:s2=>2\n" + 480 ".s0-{'\\u0000'..'w', 'y'..'\\uFFFF'}->:s1=>1\n"; 481 checkDecision(g, 1, expecting, null); 482 } 483 testSynPredInLexer()484 @Test public void testSynPredInLexer() throws Exception { 485 Grammar g = new Grammar( 486 "lexer grammar T;\n"+ 487 "LT: '<' ' '*\n" + 488 " | ('<' IDENT) => '<' IDENT '>'\n" + // this was causing syntax error 489 " ;\n" + 490 "IDENT: 'a'+;\n"); 491 // basically, Tokens rule should not do set compression test 492 String expecting = 493 ".s0-'<'->:s1=>1\n" + 494 ".s0-'a'->:s2=>2\n"; 495 checkDecision(g, 4, expecting, null); // 4 is Tokens rule 496 } 497 498 // S U P P O R T 499 _template()500 public void _template() throws Exception { 501 Grammar g = new Grammar( 502 "grammar T;\n"+ 503 "a : A | B;"); 504 String expecting = 505 "\n"; 506 checkDecision(g, 1, expecting, null); 507 } 508 checkDecision(Grammar g, int decision, String expecting, int[] expectingUnreachableAlts)509 protected void checkDecision(Grammar g, 510 int decision, 511 String expecting, 512 int[] expectingUnreachableAlts) 513 throws Exception 514 { 515 516 // mimic actions of org.antlr.Tool first time for grammar g 517 if ( g.getCodeGenerator()==null ) { 518 CodeGenerator generator = new CodeGenerator(null, g, "Java"); 519 g.setCodeGenerator(generator); 520 g.buildNFA(); 521 g.createLookaheadDFAs(false); 522 } 523 524 DFA dfa = g.getLookaheadDFA(decision); 525 assertNotNull("unknown decision #"+decision, dfa); 526 FASerializer serializer = new FASerializer(g); 527 String result = serializer.serialize(dfa.startState); 528 //System.out.print(result); 529 List nonDetAlts = dfa.getUnreachableAlts(); 530 //System.out.println("alts w/o predict state="+nonDetAlts); 531 532 // first make sure nondeterministic alts are as expected 533 if ( expectingUnreachableAlts==null ) { 534 if ( nonDetAlts!=null && nonDetAlts.size()!=0 ) { 535 System.err.println("nondeterministic alts (should be empty): "+nonDetAlts); 536 } 537 assertEquals("unreachable alts mismatch", 0, nonDetAlts!=null?nonDetAlts.size():0); 538 } 539 else { 540 for (int i=0; i<expectingUnreachableAlts.length; i++) { 541 assertTrue("unreachable alts mismatch", 542 nonDetAlts!=null?nonDetAlts.contains(new Integer(expectingUnreachableAlts[i])):false); 543 } 544 } 545 assertEquals(expecting, result); 546 } 547 548 } 549