1 21 22 package net.percederberg.grammatica; 23 24 import java.io.BufferedReader ; 25 import java.io.File ; 26 import java.io.FileNotFoundException ; 27 import java.io.FileReader ; 28 import java.io.IOException ; 29 30 import net.percederberg.grammatica.output.CSharpParserGenerator; 31 import net.percederberg.grammatica.output.JavaParserGenerator; 32 import net.percederberg.grammatica.output.VisualBasicParserGenerator; 33 import net.percederberg.grammatica.parser.Analyzer; 34 import net.percederberg.grammatica.parser.Node; 35 import net.percederberg.grammatica.parser.ParseException; 36 import net.percederberg.grammatica.parser.Parser; 37 import net.percederberg.grammatica.parser.ParserCreationException; 38 import net.percederberg.grammatica.parser.ParserLogException; 39 import net.percederberg.grammatica.parser.Token; 40 import net.percederberg.grammatica.parser.Tokenizer; 41 42 50 public class Grammatica extends Object { 51 52 55 private static final String COMMAND_HELP = 56 "Generates source code for a C#, Java or Visual Basic parser from\n" + 57 "a grammar file. This program comes with ABSOLUTELY NO WARRANTY;\n" + 58 "for details see the LICENSE.txt file.\n" + 59 "\n" + 60 "Syntax: Grammatica <grammarfile> <action> [<options>]\n" + 61 "\n" + 62 "Actions:\n" + 63 " --debug\n" + 64 " Debugs the grammar by validating it and printing the\n" + 65 " internal representation.\n" + 66 " --tokenize <file>\n" + 67 " Debugs the grammar by using it to tokenize the specified\n" + 68 " file. No code has to be generated for this.\n" + 69 " --parse <file>\n" + 70 " Debugs the grammar by using it to parse the specified\n" + 71 " file. No code has to be generated for this.\n" + 72 " --profile <file>\n" + 73 " Profiles the grammar by using it to parse the specified\n" + 74 " file and printing a statistic summary.\n" + 75 " --csoutput <dir>\n" + 76 " Creates a C# parser for the grammar (in source code).\n" + 77 " The specified directory will be used as output directory\n" + 78 " for the source code files.\n" + 79 " --javaoutput <dir>\n" + 80 " Creates a Java parser for the grammar (in source code).\n" + 81 " The specified directory will be used as the base output\n" + 82 " directory for the source code files.\n" + 83 " --vboutput <dir>\n" + 84 " Creates a Visual Basic (.NET) parser for the grammar (in\n" + 85 " source code). The specified directory will be used as\n" + 86 " output directory for the source code files.\n" + 87 "\n" + 88 "C# Output Options:\n" + 89 " --csnamespace <package>\n" + 90 " Sets the C# namespace to use in generated source code\n" + 91 " files. By default no namespace declaration is included.\n" + 92 " --csclassname <name>\n" + 93 " Sets the C# class name prefix to use in generated source\n" + 94 " code files. By default the grammar file name is used.\n" + 95 " --cspublic\n" + 96 " Sets public access for all C# types generated. By default\n" + 97 " type access is internal.\n" + 98 "\n" + 99 "Java Output Options:\n" + 100 " --javapackage <package>\n" + 101 " Sets the Java package to use in generated source code\n" + 102 " files. By default no package declaration is included.\n" + 103 " --javaclassname <name>\n" + 104 " Sets the Java class name prefix to use in generated source\n" + 105 " code files. By default the grammar file name is used.\n" + 106 " --javapublic\n" + 107 " Sets public access for all Java types. By default type\n" + 108 " access is package local.\n" + 109 "\n" + 110 "Visual Basic Output Options:\n" + 111 " --vbnamespace <package>\n" + 112 " Sets the namespace to use in generated source code files.\n" + 113 " By default no namespace declaration is included.\n" + 114 " --vbclassname <name>\n" + 115 " Sets the class name prefix to use in generated source code\n" + 116 " files. By default the grammar file name is used.\n" + 117 " --vbpublic\n" + 118 " Sets public access for all types generated. By default type\n" + 119 " access is friend."; 120 121 124 private static final String INTERNAL_ERROR = 125 "INTERNAL ERROR: An internal error in Grammatica has been found.\n" + 126 " Please report this error to the maintainers (see the web\n" + 127 " site for instructions). Be sure to include the Grammatica\n" + 128 " version number, as well as the information below:\n"; 129 130 135 public static void main(String [] args) { 136 Grammar grammar = null; 137 138 if (args.length == 1 && args[0].equals("--help")) { 140 printHelp(null); 141 System.exit(1); 142 } 143 if (args.length < 2) { 144 printHelp("Missing grammar file and/or action"); 145 System.exit(1); 146 } 147 148 try { 150 grammar = new Grammar(new File (args[0])); 151 } catch (FileNotFoundException e) { 152 printError(args[0], e); 153 System.exit(1); 154 } catch (ParserLogException e) { 155 printError(args[0], e); 156 System.exit(1); 157 } catch (GrammarException e) { 158 printError(e); 159 System.exit(1); 160 } catch (SecurityException e) { 161 throw e; 162 } catch (RuntimeException e) { 163 printInternalError(e); 164 System.exit(2); 165 } 166 167 try { 169 if (args[1].equals("--debug")) { 170 debug(grammar); 171 } else if (args.length < 3) { 172 printHelp("missing action file parameter"); 173 System.exit(1); 174 } else if (args[1].equals("--tokenize")) { 175 tokenize(grammar, new File (args[2])); 176 } else if (args[1].equals("--parse")) { 177 parse(grammar, new File (args[2])); 178 } else if (args[1].equals("--profile")) { 179 profile(grammar, new File (args[2])); 180 } else if (args[1].equals("--javaoutput")) { 181 writeJavaCode(args, grammar); 182 } else if (args[1].equals("--csoutput")) { 183 writeCSharpCode(args, grammar); 184 } else if (args[1].equals("--vboutput")) { 185 writeVisualBasicCode(args, grammar); 186 } else { 187 printHelp("unrecognized option: " + args[1]); 188 System.exit(1); 189 } 190 } catch (SecurityException e) { 191 throw e; 192 } catch (RuntimeException e) { 193 printInternalError(e); 194 System.exit(2); 195 } 196 } 197 198 203 private static void printHelp(String error) { 204 System.err.println(COMMAND_HELP); 205 System.err.println(); 206 if (error != null) { 207 System.err.print("Error: "); 208 System.err.println(error); 209 System.err.println(); 210 } 211 } 212 213 218 private static void printError(Exception e) { 219 StringBuffer buffer = new StringBuffer (); 220 221 buffer.append("Error: "); 222 buffer.append(e.getMessage()); 223 System.err.println(buffer.toString()); 224 } 225 226 232 private static void printError(String file, FileNotFoundException e) { 233 StringBuffer buffer = new StringBuffer (); 234 235 buffer.append("Error: couldn't open file:"); 236 buffer.append("\n "); 237 buffer.append(file); 238 System.err.println(buffer.toString()); 239 } 240 241 247 private static void printError(String file, ParseException e) { 248 StringBuffer buffer = new StringBuffer (); 249 String line; 250 251 buffer.append("Error: in "); 253 buffer.append(file); 254 if (e.getLine() > 0) { 255 buffer.append(": line "); 256 buffer.append(e.getLine()); 257 } 258 buffer.append(":\n"); 259 buffer.append(linebreakString(e.getErrorMessage(), " ", 70)); 260 line = readLines(file, e.getLine(), e.getLine()); 261 if (line != null) { 262 buffer.append("\n\n"); 263 buffer.append(line); 264 for (int i = 1; i < e.getColumn(); i++) { 265 if (line.charAt(i - 1) == '\t') { 266 buffer.append("\t"); 267 } else { 268 buffer.append(" "); 269 } 270 } 271 buffer.append("^"); 272 } 273 System.err.println(buffer.toString()); 274 } 275 276 282 private static void printError(String file, ParserLogException e) { 283 for (int i = 0; i < e.getErrorCount(); i++) { 284 printError(file, e.getError(i)); 285 } 286 } 287 288 293 private static void printError(GrammarException e) { 294 StringBuffer buffer = new StringBuffer (); 295 String lines; 296 297 buffer.append("Error: in "); 298 buffer.append(e.getFile()); 299 if (e.getStartLine() > 0) { 300 if (e.getStartLine() == e.getEndLine()) { 301 buffer.append(": line "); 302 buffer.append(e.getStartLine()); 303 } else { 304 buffer.append(": lines "); 305 buffer.append(e.getStartLine()); 306 buffer.append("-"); 307 buffer.append(e.getEndLine()); 308 } 309 } 310 buffer.append(":\n"); 311 buffer.append(linebreakString(e.getErrorMessage(), " ", 70)); 312 lines = readLines(e.getFile(), e.getStartLine(), e.getEndLine()); 313 if (lines != null) { 314 buffer.append("\n\n"); 315 buffer.append(lines); 316 } 317 System.err.println(buffer.toString()); 318 } 319 320 328 private static void printInternalError(Exception e) { 329 System.err.println(INTERNAL_ERROR); 330 e.printStackTrace(); 331 } 332 333 346 private static String linebreakString(String str, 347 String prefix, 348 int length) { 349 350 StringBuffer buffer = new StringBuffer (); 351 int pos; 352 353 while (str.length() + prefix.length() > length) { 354 pos = str.lastIndexOf(' ', length - prefix.length()); 355 if (pos < 0) { 356 pos = str.indexOf(' '); 357 if (pos < 0) { 358 break; 359 } 360 } 361 buffer.append(prefix); 362 buffer.append(str.substring(0, pos)); 363 str = str.substring(pos + 1); 364 buffer.append("\n"); 365 } 366 buffer.append(prefix); 367 buffer.append(str); 368 return buffer.toString(); 369 } 370 371 381 private static String readLines(String file, int start, int end) { 382 BufferedReader input; 383 StringBuffer buffer = new StringBuffer (); 384 String str; 385 386 if (start < 1 || end < start) { 388 return null; 389 } 390 391 try { 393 input = new BufferedReader (new FileReader (file)); 394 for (int i = 0; i < end; i++) { 395 str = input.readLine(); 396 if (str == null) { 397 input.close(); 398 return null; 399 } else if (start <= i + 1) { 400 buffer.append(str); 401 buffer.append("\n"); 402 } 403 } 404 input.close(); 405 } catch (IOException e) { 406 return null; 407 } 408 409 return buffer.toString(); 410 } 411 412 417 private static void debug(Grammar grammar) { 418 Tokenizer tokenizer = null; 419 Parser parser = null; 420 421 try { 423 tokenizer = grammar.createTokenizer(null); 424 parser = grammar.createParser(tokenizer); 425 } catch (GrammarException e) { 426 printInternalError(e); 427 System.exit(2); 428 } 429 430 System.out.println("Contents of " + grammar.getFileName() + ":"); 432 System.out.println(); 433 System.out.println("Token Declarations:"); 434 System.out.println("-------------------"); 435 System.out.print(tokenizer); 436 System.out.println("Production Declarations:"); 437 System.out.println("------------------------"); 438 System.out.print(parser); 439 } 440 441 448 private static void tokenize(Grammar grammar, File file) { 449 Tokenizer tokenizer; 450 Token token; 451 452 try { 453 tokenizer = grammar.createTokenizer(new FileReader (file)); 454 System.out.println("Tokens from " + file + ":"); 455 while ((token = tokenizer.next()) != null) { 456 System.out.println(token); 457 } 458 } catch (FileNotFoundException e) { 459 printError(file.toString(), e); 460 System.exit(1); 461 } catch (GrammarException e) { 462 printInternalError(e); 463 System.exit(2); 464 } catch (ParseException e) { 465 printError(file.toString(), e); 466 System.exit(1); 467 } 468 } 469 470 476 private static void parse(Grammar grammar, File file) { 477 Tokenizer tokenizer; 478 Analyzer analyzer; 479 Parser parser; 480 481 try { 482 tokenizer = grammar.createTokenizer(new FileReader (file)); 483 analyzer = new TreePrinter(System.out); 484 parser = grammar.createParser(tokenizer, analyzer); 485 System.out.println("Parse tree from " + file + ":"); 486 parser.parse(); 487 } catch (FileNotFoundException e) { 488 printError(file.toString(), e); 489 System.exit(1); 490 } catch (GrammarException e) { 491 printInternalError(e); 492 System.exit(2); 493 } catch (ParserCreationException e) { 494 printInternalError(e); 495 System.exit(2); 496 } catch (ParserLogException e) { 497 printError(file.toString(), e); 498 System.exit(1); 499 } 500 } 501 502 509 private static void profile(Grammar grammar, File file) { 510 Tokenizer tokenizer; 511 Parser parser; 512 Node node; 513 long time; 514 int counter; 515 516 try { 518 tokenizer = grammar.createTokenizer(new FileReader (file)); 519 System.out.println("Tokenizing " + file); 520 time = System.currentTimeMillis(); 521 counter = 0; 522 while (tokenizer.next() != null) { 523 counter++; 524 } 525 time = System.currentTimeMillis() - time + 1; 526 System.out.println(" Time elapsed: " + time + " millisec"); 527 System.out.println(" Tokens found: " + counter); 528 System.out.println(" Average speed: " + (counter / time) + 529 " tokens/millisec"); 530 System.out.println(); 531 } catch (FileNotFoundException e) { 532 printError(file.toString(), e); 533 System.exit(1); 534 } catch (GrammarException e) { 535 printInternalError(e); 536 System.exit(2); 537 } catch (ParseException e) { 538 printError(file.toString(), e); 539 System.exit(1); 540 } 541 542 try { 544 tokenizer = grammar.createTokenizer(new FileReader (file)); 545 parser = grammar.createParser(tokenizer); 546 System.out.println("Parsing " + file); 547 time = System.currentTimeMillis(); 548 node = parser.parse(); 549 time = System.currentTimeMillis() - time + 1; 550 counter = 1 + node.getDescendantCount(); 551 System.out.println(" Time elapsed: " + time + " millisec"); 552 System.out.println(" Nodes found: " + counter); 553 System.out.println(" Average speed: " + (counter / time) + 554 " nodes/millisec"); 555 System.out.println(); 556 } catch (FileNotFoundException e) { 557 printError(file.toString(), e); 558 System.exit(1); 559 } catch (GrammarException e) { 560 printInternalError(e); 561 System.exit(2); 562 } catch (ParserCreationException e) { 563 printInternalError(e); 564 System.exit(2); 565 } catch (ParserLogException e) { 566 printError(file.toString(), e); 567 System.exit(1); 568 } 569 } 570 571 578 private static void writeJavaCode(String [] args, Grammar grammar) { 579 JavaParserGenerator gen = new JavaParserGenerator(grammar); 580 581 for (int i = 1; i < args.length; i++) { 583 if (args[i].equals("--javaoutput")) { 584 gen.setBaseDir(new File (args[++i])); 585 } else if (args[i].equals("--javapackage")) { 586 gen.setBasePackage(args[++i]); 587 } else if (args[i].equals("--javaclassname")) { 588 gen.setBaseName(args[++i]); 589 } else if (args[i].equals("--javapublic")) { 590 gen.setPublicAccess(true); 591 } else { 592 printHelp("unrecognized option: " + args[i]); 593 System.exit(1); 594 } 595 } 596 597 try { 599 System.out.println("Writing Java parser source code..."); 600 gen.write(); 601 System.out.println("Done."); 602 } catch (IOException e) { 603 printError(e); 604 System.exit(1); 605 } 606 } 607 608 615 private static void writeCSharpCode(String [] args, Grammar grammar) { 616 CSharpParserGenerator gen = new CSharpParserGenerator(grammar); 617 618 for (int i = 1; i < args.length; i++) { 620 if (args[i].equals("--csoutput")) { 621 gen.setBaseDir(new File (args[++i])); 622 } else if (args[i].equals("--csnamespace")) { 623 gen.setNamespace(args[++i]); 624 } else if (args[i].equals("--csclassname")) { 625 gen.setBaseName(args[++i]); 626 } else if (args[i].equals("--cspublic")) { 627 gen.setPublicAccess(true); 628 } else { 629 printHelp("unrecognized option: " + args[i]); 630 System.exit(1); 631 } 632 } 633 634 try { 636 System.out.println("Writing C# parser source code..."); 637 gen.write(); 638 System.out.println("Done."); 639 } catch (IOException e) { 640 printError(e); 641 System.exit(1); 642 } 643 } 644 645 652 private static void writeVisualBasicCode(String [] args, Grammar grammar) { 653 VisualBasicParserGenerator gen; 654 655 gen = new VisualBasicParserGenerator(grammar); 657 for (int i = 1; i < args.length; i++) { 658 if (args[i].equals("--vboutput")) { 659 gen.setBaseDir(new File (args[++i])); 660 } else if (args[i].equals("--vbnamespace")) { 661 gen.setNamespace(args[++i]); 662 } else if (args[i].equals("--vbclassname")) { 663 gen.setBaseName(args[++i]); 664 } else if (args[i].equals("--vbpublic")) { 665 gen.setPublicAccess(true); 666 } else { 667 printHelp("unrecognized option: " + args[i]); 668 System.exit(1); 669 } 670 } 671 672 try { 674 System.out.println("Writing Visual Basic parser source code..."); 675 gen.write(); 676 System.out.println("Done."); 677 } catch (IOException e) { 678 printError(e); 679 System.exit(1); 680 } 681 } 682 } 683 | Popular Tags |