1 21 22 package net.percederberg.grammatica.parser; 23 24 import java.util.ArrayList ; 25 import java.util.Iterator ; 26 27 36 public class RecursiveDescentParser extends Parser { 37 38 43 public RecursiveDescentParser(Tokenizer tokenizer) { 44 super(tokenizer); 45 } 46 47 53 public RecursiveDescentParser(Tokenizer tokenizer, Analyzer analyzer) { 54 super(tokenizer, analyzer); 55 } 56 57 68 public void addPattern(ProductionPattern pattern) 69 throws ParserCreationException { 70 71 if (pattern.isMatchingEmpty()) { 73 throw new ParserCreationException( 74 ParserCreationException.INVALID_PRODUCTION_ERROR, 75 pattern.getName(), 76 "zero elements can be matched (minimum is one)"); 77 } 78 79 if (pattern.isLeftRecursive()) { 81 throw new ParserCreationException( 82 ParserCreationException.INVALID_PRODUCTION_ERROR, 83 pattern.getName(), 84 "left recursive patterns are not allowed"); 85 } 86 87 super.addPattern(pattern); 89 } 90 91 100 public void prepare() throws ParserCreationException { 101 Iterator iter; 102 103 super.prepare(); 105 setInitialized(false); 106 107 iter = getPatterns().iterator(); 109 while (iter.hasNext()) { 110 calculateLookAhead((ProductionPattern) iter.next()); 111 } 112 113 setInitialized(true); 115 } 116 117 125 protected Node parseStart() throws ParseException { 126 Token token; 127 Node node; 128 ArrayList list; 129 130 node = parsePattern(getStartPattern()); 131 token = peekToken(0); 132 if (token != null) { 133 list = new ArrayList (1); 134 list.add("<EOF>"); 135 throw new ParseException( 136 ParseException.UNEXPECTED_TOKEN_ERROR, 137 token.toShortString(), 138 list, 139 token.getStartLine(), 140 token.getStartColumn()); 141 } 142 return node; 143 } 144 145 156 private Node parsePattern(ProductionPattern pattern) 157 throws ParseException { 158 159 ProductionPatternAlternative alt; 160 ProductionPatternAlternative defaultAlt; 161 162 defaultAlt = pattern.getDefaultAlternative(); 163 for (int i = 0; i < pattern.getAlternativeCount(); i++) { 164 alt = pattern.getAlternative(i); 165 if (defaultAlt != alt && isNext(alt)) { 166 return parseAlternative(alt); 167 } 168 } 169 if (defaultAlt == null || !isNext(defaultAlt)) { 170 throwParseException(findUnion(pattern)); 171 } 172 return parseAlternative(defaultAlt); 173 } 174 175 186 private Node parseAlternative(ProductionPatternAlternative alt) 187 throws ParseException { 188 189 Production node; 190 191 node = new Production(alt.getPattern()); 192 enterNode(node); 193 for (int i = 0; i < alt.getElementCount(); i++) { 194 try { 195 parseElement(node, alt.getElement(i)); 196 } catch (ParseException e) { 197 addError(e, true); 198 nextToken(); 199 i--; 200 } 201 } 202 return exitNode(node); 203 } 204 205 216 private void parseElement(Production node, 217 ProductionPatternElement elem) 218 throws ParseException { 219 220 Node child; 221 222 for (int i = 0; i < elem.getMaxCount(); i++) { 223 if (i < elem.getMinCount() || isNext(elem)) { 224 if (elem.isToken()) { 225 child = nextToken(elem.getId()); 226 enterNode(child); 227 addNode(node, exitNode(child)); 228 } else { 229 child = parsePattern(getPattern(elem.getId())); 230 addNode(node, child); 231 } 232 } else { 233 break; 234 } 235 } 236 } 237 238 248 private boolean isNext(ProductionPattern pattern) { 249 LookAheadSet set = pattern.getLookAhead(); 250 251 if (set == null) { 252 return false; 253 } else { 254 return set.isNext(this); 255 } 256 } 257 258 268 private boolean isNext(ProductionPatternAlternative alt) { 269 LookAheadSet set = alt.getLookAhead(); 270 271 if (set == null) { 272 return false; 273 } else { 274 return set.isNext(this); 275 } 276 } 277 278 289 private boolean isNext(ProductionPatternElement elem) { 290 LookAheadSet set = elem.getLookAhead(); 291 292 if (set != null) { 293 return set.isNext(this); 294 } else if (elem.isToken()) { 295 return elem.isMatch(peekToken(0)); 296 } else { 297 return isNext(getPattern(elem.getId())); 298 } 299 } 300 301 311 private void calculateLookAhead(ProductionPattern pattern) 312 throws ParserCreationException { 313 314 ProductionPatternAlternative alt; 315 LookAheadSet result; 316 LookAheadSet[] alternatives; 317 LookAheadSet conflicts; 318 LookAheadSet previous = new LookAheadSet(0); 319 int length = 1; 320 int i; 321 CallStack stack = new CallStack(); 322 323 stack.push(pattern.getName(), 1); 325 result = new LookAheadSet(1); 326 alternatives = new LookAheadSet[pattern.getAlternativeCount()]; 327 for (i = 0; i < pattern.getAlternativeCount(); i++) { 328 alt = pattern.getAlternative(i); 329 alternatives[i] = findLookAhead(alt, 1, 0, stack, null); 330 alt.setLookAhead(alternatives[i]); 331 result.addAll(alternatives[i]); 332 } 333 if (pattern.getLookAhead() == null) { 334 pattern.setLookAhead(result); 335 } 336 conflicts = findConflicts(pattern, 1); 337 338 while (!conflicts.isEmpty()) { 340 length++; 341 stack.clear(); 342 stack.push(pattern.getName(), length); 343 conflicts.addAll(previous); 344 for (i = 0; i < pattern.getAlternativeCount(); i++) { 345 alt = pattern.getAlternative(i); 346 if (alternatives[i].hasIntersection(conflicts)) { 347 alternatives[i] = findLookAhead(alt, 348 length, 349 0, 350 stack, 351 conflicts); 352 alt.setLookAhead(alternatives[i]); 353 } 354 if (alternatives[i].hasIntersection(conflicts)) { 355 if (pattern.getDefaultAlternative() == null) { 356 pattern.setDefaultAlternative(i); 357 } else if (pattern.getDefaultAlternative() != alt) { 358 result = alternatives[i].createIntersection(conflicts); 359 throwAmbiguityException(pattern.getName(), 360 null, 361 result); 362 } 363 } 364 } 365 previous = conflicts; 366 conflicts = findConflicts(pattern, length); 367 } 368 369 for (i = 0; i < pattern.getAlternativeCount(); i++) { 371 calculateLookAhead(pattern.getAlternative(i), 0); 372 } 373 } 374 375 387 private void calculateLookAhead(ProductionPatternAlternative alt, 388 int pos) 389 throws ParserCreationException { 390 391 ProductionPattern pattern; 392 ProductionPatternElement elem; 393 LookAheadSet first; 394 LookAheadSet follow; 395 LookAheadSet conflicts; 396 LookAheadSet previous = new LookAheadSet(0); 397 String location; 398 int length = 1; 399 400 if (pos >= alt.getElementCount()) { 402 return; 403 } 404 405 pattern = alt.getPattern(); 407 elem = alt.getElement(pos); 408 if (elem.getMinCount() == elem.getMaxCount()) { 409 calculateLookAhead(alt, pos + 1); 410 return; 411 } 412 413 first = findLookAhead(elem, 1, new CallStack(), null); 415 follow = findLookAhead(alt, 1, pos + 1, new CallStack(), null); 416 417 location = "at position " + (pos + 1); 419 conflicts = findConflicts(pattern.getName(), 420 location, 421 first, 422 follow); 423 while (!conflicts.isEmpty()) { 424 length++; 425 conflicts.addAll(previous); 426 first = findLookAhead(elem, 427 length, 428 new CallStack(), 429 conflicts); 430 follow = findLookAhead(alt, 431 length, 432 pos + 1, 433 new CallStack(), 434 conflicts); 435 first = first.createCombination(follow); 436 elem.setLookAhead(first); 437 if (first.hasIntersection(conflicts)) { 438 first = first.createIntersection(conflicts); 439 throwAmbiguityException(pattern.getName(), location, first); 440 } 441 previous = conflicts; 442 conflicts = findConflicts(pattern.getName(), 443 location, 444 first, 445 follow); 446 } 447 448 calculateLookAhead(alt, pos + 1); 450 } 451 452 468 private LookAheadSet findLookAhead(ProductionPattern pattern, 469 int length, 470 CallStack stack, 471 LookAheadSet filter) 472 throws ParserCreationException { 473 474 LookAheadSet result; 475 LookAheadSet temp; 476 477 if (stack.contains(pattern.getName(), length)) { 479 throw new ParserCreationException( 480 ParserCreationException.INFINITE_LOOP_ERROR, 481 pattern.getName(), 482 (String ) null); 483 } 484 485 stack.push(pattern.getName(), length); 487 result = new LookAheadSet(length); 488 for (int i = 0; i < pattern.getAlternativeCount(); i++) { 489 temp = findLookAhead(pattern.getAlternative(i), 490 length, 491 0, 492 stack, 493 filter); 494 result.addAll(temp); 495 } 496 stack.pop(); 497 498 return result; 499 } 500 501 519 private LookAheadSet findLookAhead(ProductionPatternAlternative alt, 520 int length, 521 int pos, 522 CallStack stack, 523 LookAheadSet filter) 524 throws ParserCreationException { 525 526 LookAheadSet first; 527 LookAheadSet follow; 528 LookAheadSet overlaps; 529 530 if (length <= 0 || pos >= alt.getElementCount()) { 532 return new LookAheadSet(0); 533 } 534 535 first = findLookAhead(alt.getElement(pos), length, stack, filter); 537 if (alt.getElement(pos).getMinCount() == 0) { 538 first.addEmpty(); 539 } 540 541 if (filter == null) { 543 length -= first.getMinLength(); 544 if (length > 0) { 545 follow = findLookAhead(alt, length, pos + 1, stack, null); 546 first = first.createCombination(follow); 547 } 548 } else if (filter.hasOverlap(first)) { 549 overlaps = first.createOverlaps(filter); 550 length -= overlaps.getMinLength(); 551 filter = filter.createFilter(overlaps); 552 follow = findLookAhead(alt, length, pos + 1, stack, filter); 553 first.removeAll(overlaps); 554 first.addAll(overlaps.createCombination(follow)); 555 } 556 557 return first; 558 } 559 560 579 private LookAheadSet findLookAhead(ProductionPatternElement elem, 580 int length, 581 CallStack stack, 582 LookAheadSet filter) 583 throws ParserCreationException { 584 585 LookAheadSet result; 586 LookAheadSet first; 587 LookAheadSet follow; 588 int max; 589 590 first = findLookAhead(elem, length, 0, stack, filter); 592 result = new LookAheadSet(length); 593 result.addAll(first); 594 if (filter == null || !filter.hasOverlap(result)) { 595 return result; 596 } 597 598 if (elem.getMaxCount() == Integer.MAX_VALUE) { 600 first = first.createRepetitive(); 601 } 602 max = Math.min(length, elem.getMaxCount()); 603 for (int i = 1; i < max; i++) { 604 first = first.createOverlaps(filter); 605 if (first.isEmpty() || first.getMinLength() >= length) { 606 break; 607 } 608 follow = findLookAhead(elem, 609 length, 610 0, 611 stack, 612 filter.createFilter(first)); 613 first = first.createCombination(follow); 614 result.addAll(first); 615 } 616 617 return result; 618 } 619 620 639 private LookAheadSet findLookAhead(ProductionPatternElement elem, 640 int length, 641 int dummy, 642 CallStack stack, 643 LookAheadSet filter) 644 throws ParserCreationException { 645 646 LookAheadSet result; 647 ProductionPattern pattern; 648 649 if (elem.isToken()) { 650 result = new LookAheadSet(length); 651 result.add(elem.getId()); 652 } else { 653 pattern = getPattern(elem.getId()); 654 result = findLookAhead(pattern, length, stack, filter); 655 if (stack.contains(pattern.getName())) { 656 result = result.createRepetitive(); 657 } 658 } 659 660 return result; 661 } 662 663 675 private LookAheadSet findConflicts(ProductionPattern pattern, 676 int maxLength) 677 throws ParserCreationException { 678 679 LookAheadSet result = new LookAheadSet(maxLength); 680 LookAheadSet set1; 681 LookAheadSet set2; 682 683 for (int i = 0; i < pattern.getAlternativeCount(); i++) { 684 set1 = pattern.getAlternative(i).getLookAhead(); 685 for (int j = 0; j < i; j++) { 686 set2 = pattern.getAlternative(j).getLookAhead(); 687 result.addAll(set1.createIntersection(set2)); 688 } 689 } 690 if (result.isRepetitive()) { 691 throwAmbiguityException(pattern.getName(), null, result); 692 } 693 return result; 694 } 695 696 710 private LookAheadSet findConflicts(String pattern, 711 String location, 712 LookAheadSet set1, 713 LookAheadSet set2) 714 throws ParserCreationException { 715 716 LookAheadSet result; 717 718 result = set1.createIntersection(set2); 719 if (result.isRepetitive()) { 720 throwAmbiguityException(pattern, location, result); 721 } 722 return result; 723 } 724 725 733 private LookAheadSet findUnion(ProductionPattern pattern) { 734 LookAheadSet result; 735 int length = 0; 736 int i; 737 738 for (i = 0; i < pattern.getAlternativeCount(); i++) { 739 result = pattern.getAlternative(i).getLookAhead(); 740 if (result.getMaxLength() > length) { 741 length = result.getMaxLength(); 742 } 743 } 744 result = new LookAheadSet(length); 745 for (i = 0; i < pattern.getAlternativeCount(); i++) { 746 result.addAll(pattern.getAlternative(i).getLookAhead()); 747 } 748 749 return result; 750 } 751 752 761 private void throwParseException(LookAheadSet set) 762 throws ParseException { 763 764 Token token; 765 ArrayList list = new ArrayList (); 766 int[] initials; 767 768 while (set.isNext(this, 1)) { 770 set = set.createNextSet(nextToken().getId()); 771 } 772 773 initials = set.getInitialTokens(); 775 for (int i = 0; i < initials.length; i++) { 776 list.add(getTokenDescription(initials[i])); 777 } 778 779 token = nextToken(); 781 throw new ParseException(ParseException.UNEXPECTED_TOKEN_ERROR, 782 token.toShortString(), 783 list, 784 token.getStartLine(), 785 token.getStartColumn()); 786 } 787 788 799 private void throwAmbiguityException(String pattern, 800 String location, 801 LookAheadSet set) 802 throws ParserCreationException { 803 804 ArrayList list = new ArrayList (); 805 int[] initials; 806 807 initials = set.getInitialTokens(); 809 for (int i = 0; i < initials.length; i++) { 810 list.add(getTokenDescription(initials[i])); 811 } 812 813 throw new ParserCreationException( 815 ParserCreationException.INHERENT_AMBIGUITY_ERROR, 816 pattern, 817 location, 818 list); 819 } 820 821 822 826 private class CallStack { 827 828 831 private ArrayList nameStack = new ArrayList (); 832 833 836 private ArrayList valueStack = new ArrayList (); 837 838 846 public boolean contains(String name) { 847 return nameStack.contains(name); 848 } 849 850 860 public boolean contains(String name, int value) { 861 Integer obj = new Integer (value); 862 863 for (int i = 0; i < nameStack.size(); i++) { 864 if (nameStack.get(i).equals(name) 865 && valueStack.get(i).equals(obj)) { 866 867 return true; 868 } 869 } 870 return false; 871 } 872 873 877 public void clear() { 878 nameStack.clear(); 879 valueStack.clear(); 880 } 881 882 888 public void push(String name, int value) { 889 nameStack.add(name); 890 valueStack.add(new Integer (value)); 891 } 892 893 896 public void pop() { 897 if (nameStack.size() > 0) { 898 nameStack.remove(nameStack.size() - 1); 899 valueStack.remove(valueStack.size() - 1); 900 } 901 } 902 } 903 } 904 | Popular Tags |