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