1 21 22 package net.percederberg.grammatica.parser; 23 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.HashMap ; 27 28 35 public abstract class Parser { 36 37 40 private boolean initialized = false; 41 42 45 private Tokenizer tokenizer; 46 47 50 private Analyzer analyzer; 51 52 55 private ArrayList patterns = new ArrayList (); 56 57 61 private HashMap patternIds = new HashMap (); 62 63 67 private ArrayList tokens = new ArrayList (); 68 69 75 private ParserLogException errorLog = new ParserLogException(); 76 77 84 private int errorRecovery = -1; 85 86 91 Parser(Tokenizer tokenizer) { 92 this(tokenizer, null); 93 } 94 95 101 Parser(Tokenizer tokenizer, Analyzer analyzer) { 102 this.tokenizer = tokenizer; 103 if (analyzer == null) { 104 this.analyzer = new Analyzer(); 105 } else { 106 this.analyzer = analyzer; 107 } 108 } 109 110 117 public Tokenizer getTokenizer() { 118 return tokenizer; 119 } 120 121 128 public Analyzer getAnalyzer() { 129 return analyzer; 130 } 131 132 139 void setInitialized(boolean initialized) { 140 this.initialized = initialized; 141 } 142 143 153 public void addPattern(ProductionPattern pattern) 154 throws ParserCreationException { 155 156 Integer id = new Integer (pattern.getId()); 157 158 if (pattern.getAlternativeCount() <= 0) { 159 throw new ParserCreationException( 160 ParserCreationException.INVALID_PRODUCTION_ERROR, 161 pattern.getName(), 162 "no production alternatives are present (must have at " + 163 "least one)"); 164 } 165 if (patternIds.containsKey(id)) { 166 throw new ParserCreationException( 167 ParserCreationException.INVALID_PRODUCTION_ERROR, 168 pattern.getName(), 169 "another pattern with the same id (" + id + 170 ") has already been added"); 171 } 172 patterns.add(pattern); 173 patternIds.put(id, pattern); 174 setInitialized(false); 175 } 176 177 185 public void prepare() throws ParserCreationException { 186 if (patterns.size() <= 0) { 187 throw new ParserCreationException( 188 ParserCreationException.INVALID_PARSER_ERROR, 189 "no production patterns have been added"); 190 } 191 for (int i = 0; i < patterns.size(); i++) { 192 checkPattern((ProductionPattern) patterns.get(i)); 193 } 194 setInitialized(true); 195 } 196 197 207 private void checkPattern(ProductionPattern pattern) 208 throws ParserCreationException { 209 210 for (int i = 0; i < pattern.getAlternativeCount(); i++) { 211 checkAlternative(pattern.getName(), pattern.getAlternative(i)); 212 } 213 } 214 215 227 private void checkAlternative(String name, 228 ProductionPatternAlternative alt) 229 throws ParserCreationException { 230 231 for (int i = 0; i < alt.getElementCount(); i++) { 232 checkElement(name, alt.getElement(i)); 233 } 234 } 235 236 247 private void checkElement(String name, ProductionPatternElement elem) 248 throws ParserCreationException { 249 250 if (elem.isProduction() && getPattern(elem.getId()) == null) { 251 throw new ParserCreationException( 252 ParserCreationException.INVALID_PRODUCTION_ERROR, 253 name, 254 "an undefined production pattern id (" + elem.getId() + 255 ") is referenced"); 256 } 257 } 258 259 269 public void reset() { 270 this.tokens.clear(); 271 this.errorLog = new ParserLogException(); 272 this.errorRecovery = -1; 273 } 274 275 296 public Node parse() throws ParserCreationException, ParserLogException { 297 Node root = null; 298 299 if (!initialized) { 301 prepare(); 302 } 303 reset(); 304 305 try { 307 root = parseStart(); 308 } catch (ParseException e) { 309 addError(e, true); 310 } 311 312 if (errorLog.getErrorCount() > 0) { 314 throw errorLog; 315 } 316 317 return root; 318 } 319 320 328 protected abstract Node parseStart() throws ParseException; 329 330 341 void addError(ParseException e, boolean recovery) { 342 if (errorRecovery <= 0) { 343 errorLog.addError(e); 344 } 345 if (recovery) { 346 errorRecovery = 3; 347 } 348 } 349 350 358 ProductionPattern getPattern(int id) { 359 Integer value = new Integer (id); 360 361 return (ProductionPattern) patternIds.get(value); 362 } 363 364 370 ProductionPattern getStartPattern() { 371 if (patterns.size() <= 0) { 372 return null; 373 } else { 374 return (ProductionPattern) patterns.get(0); 375 } 376 } 377 378 383 Collection getPatterns() { 384 return patterns; 385 } 386 387 395 void enterNode(Node node) { 396 if (!node.isHidden() && errorRecovery < 0) { 397 try { 398 analyzer.enter(node); 399 } catch (ParseException e) { 400 addError(e, false); 401 } 402 } 403 } 404 405 416 Node exitNode(Node node) { 417 if (!node.isHidden() && errorRecovery < 0) { 418 try { 419 return analyzer.exit(node); 420 } catch (ParseException e) { 421 addError(e, false); 422 } 423 } 424 return node; 425 } 426 427 436 void addNode(Production node, Node child) { 437 if (errorRecovery >= 0) { 438 } else if (node.isHidden()) { 440 node.addChild(child); 441 } else if (child != null && child.isHidden()) { 442 for (int i = 0; i < child.getChildCount(); i++) { 443 addNode(node, child.getChildAt(i)); 444 } 445 } else { 446 try { 447 analyzer.child(node, child); 448 } catch (ParseException e) { 449 addError(e, false); 450 } 451 } 452 } 453 454 463 Token nextToken() throws ParseException { 464 Token token = peekToken(0); 465 466 if (token != null) { 467 tokens.remove(0); 468 return token; 469 } else { 470 throw new ParseException( 471 ParseException.UNEXPECTED_EOF_ERROR, 472 null, 473 tokenizer.getCurrentLine(), 474 tokenizer.getCurrentColumn()); 475 } 476 } 477 478 491 Token nextToken(int id) throws ParseException { 492 Token token = nextToken(); 493 ArrayList list; 494 495 if (token.getId() == id) { 496 if (errorRecovery > 0) { 497 errorRecovery--; 498 } 499 return token; 500 } else { 501 list = new ArrayList (1); 502 list.add(tokenizer.getPatternDescription(id)); 503 throw new ParseException( 504 ParseException.UNEXPECTED_TOKEN_ERROR, 505 token.toShortString(), 506 list, 507 token.getStartLine(), 508 token.getStartColumn()); 509 } 510 } 511 512 522 Token peekToken(int steps) { 523 Token token; 524 525 while (steps >= tokens.size()) { 526 try { 527 token = tokenizer.next(); 528 if (token == null) { 529 return null; 530 } else { 531 tokens.add(token); 532 } 533 } catch (ParseException e) { 534 addError(e, true); 535 } 536 } 537 return (Token) tokens.get(steps); 538 } 539 540 547 public String toString() { 548 StringBuffer buffer = new StringBuffer (); 549 550 for (int i = 0; i < patterns.size(); i++) { 551 buffer.append(toString((ProductionPattern) patterns.get(i))); 552 buffer.append("\n"); 553 } 554 return buffer.toString(); 555 } 556 557 564 private String toString(ProductionPattern prod) { 565 StringBuffer buffer = new StringBuffer (); 566 StringBuffer indent = new StringBuffer (); 567 LookAheadSet set; 568 int i; 569 570 buffer.append(prod.getName()); 571 buffer.append(" ("); 572 buffer.append(prod.getId()); 573 buffer.append(") "); 574 for (i = 0; i < buffer.length(); i++) { 575 indent.append(" "); 576 } 577 buffer.append("= "); 578 indent.append("| "); 579 for (i = 0; i < prod.getAlternativeCount(); i++) { 580 if (i > 0) { 581 buffer.append(indent); 582 } 583 buffer.append(toString(prod.getAlternative(i))); 584 buffer.append("\n"); 585 } 586 for (i = 0; i < prod.getAlternativeCount(); i++) { 587 set = prod.getAlternative(i).getLookAhead(); 588 if (set.getMaxLength() > 1) { 589 buffer.append("Using "); 590 buffer.append(set.getMaxLength()); 591 buffer.append(" token look-ahead for alternative "); 592 buffer.append(i + 1); 593 buffer.append(": "); 594 buffer.append(set.toString(tokenizer)); 595 buffer.append("\n"); 596 } 597 } 598 return buffer.toString(); 599 } 600 601 609 private String toString(ProductionPatternAlternative alt) { 610 StringBuffer buffer = new StringBuffer (); 611 612 for (int i = 0; i < alt.getElementCount(); i++) { 613 if (i > 0) { 614 buffer.append(" "); 615 } 616 buffer.append(toString(alt.getElement(i))); 617 } 618 return buffer.toString(); 619 } 620 621 629 private String toString(ProductionPatternElement elem) { 630 StringBuffer buffer = new StringBuffer (); 631 int min = elem.getMinCount(); 632 int max = elem.getMaxCount(); 633 634 if (min == 0 && max == 1) { 635 buffer.append("["); 636 } 637 if (elem.isToken()) { 638 buffer.append(getTokenDescription(elem.getId())); 639 } else { 640 buffer.append(getPattern(elem.getId()).getName()); 641 } 642 if (min == 0 && max == 1) { 643 buffer.append("]"); 644 } else if (min == 0 && max == Integer.MAX_VALUE) { 645 buffer.append("*"); 646 } else if (min == 1 && max == Integer.MAX_VALUE) { 647 buffer.append("+"); 648 } else if (min != 1 || max != 1) { 649 buffer.append("{"); 650 buffer.append(min); 651 buffer.append(","); 652 buffer.append(max); 653 buffer.append("}"); 654 } 655 return buffer.toString(); 656 } 657 658 665 String getTokenDescription(int token) { 666 if (tokenizer == null) { 667 return ""; 668 } else { 669 return tokenizer.getPatternDescription(token); 670 } 671 } 672 } 673 | Popular Tags |