1 2 package java_cup; 3 4 import java.io.BufferedInputStream; 5 import java.io.BufferedOutputStream; 6 import java.io.File; 7 import java.io.FileInputStream; 8 import java.io.FileOutputStream; 9 import java.io.PrintStream; 10 import java.util.Enumeration; 11 12 /** This class serves as the main driver for the JavaCup system. 13 * It accepts user options and coordinates overall control flow. 14 * The main flow of control includes the following activities: 15 * <ul> 16 * <li> Parse user supplied arguments and options. 17 * <li> Open output files. 18 * <li> Parse the specification from standard input. 19 * <li> Check for unused terminals, non-terminals, and productions. 20 * <li> Build the state machine, tables, etc. 21 * <li> Output the generated code. 22 * <li> Close output files. 23 * <li> Print a summary if requested. 24 * </ul> 25 * 26 * Options to the main program include: <dl> 27 * <dt> -package name 28 * <dd> specify package generated classes go in [default none] 29 * <dt> -parser name 30 * <dd> specify parser class name [default "parser"] 31 * <dt> -symbols name 32 * <dd> specify name for symbol constant class [default "sym"] 33 * <dt> -nonterms 34 * <dd> put non terminals in symbol constant class 35 * <dt> -expect # 36 * <dd> number of conflicts expected/allowed [default 0] 37 * <dt> -compact_red 38 * <dd> compact tables by defaulting to most frequent reduce 39 * <dt> -nowarn 40 * <dd> don't warn about useless productions, etc. 41 * <dt> -nosummary 42 * <dd> don't print the usual summary of parse states, etc. 43 * <dt> -progress 44 * <dd> print messages to indicate progress of the system 45 * <dt> -time 46 * <dd> print time usage summary 47 * <dt> -dump_grammar 48 * <dd> produce a dump of the symbols and grammar 49 * <dt> -dump_states 50 * <dd> produce a dump of parse state machine 51 * <dt> -dump_tables 52 * <dd> produce a dump of the parse tables 53 * <dt> -dump 54 * <dd> produce a dump of all of the above 55 * <dt> -debug 56 * <dd> turn on debugging messages within JavaCup 57 * </dl> 58 * 59 * @version last updated: 11/25/95 60 * @author Scott Hudson 61 */ 62 63 public class Main { 64 65 /*-----------------------------------------------------------*/ 66 /*--- Constructor(s) ----------------------------------------*/ 67 /*-----------------------------------------------------------*/ 68 /** Only constructor is private, so we do not allocate any instances of this 69 class. */ 70 private Main() { } 71 72 /*-------------------------*/ 73 /* Options set by the user */ 74 /*-------------------------*/ 75 /** User option -- do we print progress messages. */ 76 protected static boolean print_progress = false; 77 /** User option -- do we produce a dump of the state machine */ 78 protected static boolean opt_dump_states = false; 79 /** User option -- do we produce a dump of the parse tables */ 80 protected static boolean opt_dump_tables = false; 81 /** User option -- do we produce a dump of the grammar */ 82 protected static boolean opt_dump_grammar = false; 83 /** User option -- do we show timing information as a part of the summary */ 84 protected static boolean opt_show_timing = false; 85 /** User option -- do we run produce extra debugging messages */ 86 protected static boolean opt_do_debug = false; 87 /** User option -- do we compact tables by making most common reduce the 88 default action */ 89 protected static boolean opt_compact_red = false; 90 /** User option -- should we include non terminal symbol numbers in the 91 symbol constant class. */ 92 protected static boolean include_non_terms = false; 93 /** User option -- do not print a summary. */ 94 protected static boolean no_summary = false; 95 /** User option -- number of conflicts to expect */ 96 protected static int expect_conflicts = 0; 97 98 /*----------------------------------------------------------------------*/ 99 /* Timing data (not all of these time intervals are mutually exclusive) */ 100 /*----------------------------------------------------------------------*/ 101 /** Timing data -- when did we start */ 102 protected static long start_time = 0; 103 /** Timing data -- when did we end preliminaries */ 104 protected static long prelim_end = 0; 105 /** Timing data -- when did we end parsing */ 106 protected static long parse_end = 0; 107 /** Timing data -- when did we end checking */ 108 protected static long check_end = 0; 109 /** Timing data -- when did we end dumping */ 110 protected static long dump_end = 0; 111 /** Timing data -- when did we end state and table building */ 112 protected static long build_end = 0; 113 /** Timing data -- when did we end nullability calculation */ 114 protected static long nullability_end = 0; 115 /** Timing data -- when did we end first set calculation */ 116 protected static long first_end = 0; 117 /** Timing data -- when did we end state machine construction */ 118 protected static long machine_end = 0; 119 /** Timing data -- when did we end table construction */ 120 protected static long table_end = 0; 121 /** Timing data -- when did we end checking for non-reduced productions */ 122 protected static long reduce_check_end = 0; 123 /** Timing data -- when did we finish emitting code */ 124 protected static long emit_end = 0; 125 /** Timing data -- when were we completely done */ 126 protected static long final_time = 0; 127 128 /* Additional timing information is also collected in emit */ 129 130 /** Path to create output files */ 131 private static String out_path = null; 132 133 /*-----------------------------------------------------------*/ 134 /*--- Main Program ------------------------------------------*/ 135 /*-----------------------------------------------------------*/ 136 137 /** The main driver for the system. 138 * @param argv an array of strings containing command line arguments. 139 */ 140 public static void main(String argv[]) 141 throws internal_error, java.io.IOException, java.lang.Exception 142 { 143 boolean did_output = false; 144 145 start_time = System.currentTimeMillis(); 146 147 /* process user options and arguments */ 148 parse_args(argv); 149 150 /* open output files */ 151 if (print_progress) System.err.println("Opening files..."); 152 open_files(); 153 154 prelim_end = System.currentTimeMillis(); 155 156 /* parse spec into internal data structures */ 157 if (print_progress) 158 System.err.println("Parsing specification from standard input..."); 159 parse_grammar_spec(); 160 161 parse_end = System.currentTimeMillis(); 162 163 /* don't proceed unless we are error free */ 164 if (lexer.error_count == 0) 165 { 166 /* check for unused bits */ 167 if (print_progress) System.err.println("Checking specification..."); 168 check_unused(); 169 170 check_end = System.currentTimeMillis(); 171 172 /* build the state machine and parse tables */ 173 if (print_progress) System.err.println("Building parse tables..."); 174 build_parser(); 175 176 build_end = System.currentTimeMillis(); 177 178 /* output the generated code */ 179 if (print_progress) System.err.println("Writing parser..."); 180 emit_parser(); 181 did_output = true; 182 183 emit_end = System.currentTimeMillis(); 184 } 185 else 186 { 187 /* fix up the times to make the summary easier */ 188 emit_end = parse_end; 189 } 190 191 /* do requested dumps */ 192 if (opt_dump_grammar) dump_grammar(); 193 if (opt_dump_states) dump_machine(); 194 if (opt_dump_tables) dump_tables(); 195 196 dump_end = System.currentTimeMillis(); 197 198 /* close output files */ 199 if (print_progress) System.err.println("Closing files..."); 200 close_files(); 201 202 /* produce a summary if desired */ 203 if (!no_summary) emit_summary(did_output); 204 } 205 206 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 207 208 /** Print a "usage message" that described possible command line options, 209 * then exit. 210 * @param message a specific error message to preface the usage message by. 211 */ 212 protected static void usage(String message) 213 { 214 System.err.println(); 215 System.err.println(message); 216 System.err.println(); 217 System.err.println( 218 "Usage: " + version.program_name + " [options]\n" + 219 " and expects a specification file on standard input.\n" + 220 " Legal options include:\n" + 221 " -out path specify the output files path [default current directory]\n" + 222 " -package name specify package generated classes go in [default none]\n" + 223 " -parser name specify parser class name [default \"parser\"]\n" + 224 " -symbols name specify name for symbol constant class [default \"sym\"]\n"+ 225 " -nonterms put non terminals in symbol constant class\n" + 226 " -expect # number of conflicts expected/allowed [default 0]\n" + 227 " -compact_red compact tables by defaulting to most frequent reduce\n" + 228 " -nowarn don't warn about useless productions, etc.\n" + 229 " -nosummary don't print the usual summary of parse states, etc.\n" + 230 " -progress print messages to indicate progress of the system\n" + 231 " -time print time usage summary\n" + 232 " -dump_grammar produce a human readable dump of the symbols and grammar\n"+ 233 " -dump_states produce a dump of parse state machine\n"+ 234 " -dump_tables produce a dump of the parse tables\n"+ 235 " -dump produce a dump of all of the above\n" 236 ); 237 System.exit(1); 238 } 239 240 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 241 242 /** Parse command line options and arguments to set various user-option 243 * flags and variables. 244 * @param argv the command line arguments to be parsed. 245 */ 246 protected static void parse_args(String argv[]) 247 { 248 int len = argv.length; 249 int i; 250 251 /* parse the options */ 252 for (i=0; i<len; i++) 253 { 254 /* try to get the various options */ 255 if (argv[i].equals("-package")) 256 { 257 /* must have an arg */ 258 if (++i >= len || argv[i].startsWith("-") || 259 argv[i].endsWith(".cup")) 260 usage("-package must have a name argument"); 261 262 /* record the name */ 263 emit.package_name = argv[i]; 264 } 265 else if (argv[i].equals("-parser")) 266 { 267 /* must have an arg */ 268 if (++i >= len || argv[i].startsWith("-") || 269 argv[i].endsWith(".cup")) 270 usage("-parser must have a name argument"); 271 272 /* record the name */ 273 emit.parser_class_name = argv[i]; 274 } 275 else if (argv[i].equals("-input")) { 276 /* must have an arg */ 277 if (++i >= len || argv[i].startsWith("-") || 278 argv[i].endsWith(".cup")) 279 usage("-input must have a name argument"); 280 281 /* record the name */ 282 emit.input_file_name = argv[i]; 283 } 284 else if (argv[i].equals("-symbols")) 285 { 286 /* must have an arg */ 287 if (++i >= len || argv[i].startsWith("-") || 288 argv[i].endsWith(".cup")) 289 usage("-symbols must have a name argument"); 290 291 /* record the name */ 292 emit.symbol_const_class_name = argv[i]; 293 } 294 else if (argv[i].equals("-nonterms")) 295 { 296 include_non_terms = true; 297 } 298 else if (argv[i].equals("-expect")) 299 { 300 /* must have an arg */ 301 if (++i >= len || argv[i].startsWith("-") || 302 argv[i].endsWith(".cup")) 303 usage("-expect must have a name argument"); 304 305 /* record the number */ 306 try { 307 expect_conflicts = Integer.parseInt(argv[i]); 308 } catch (NumberFormatException e) { 309 usage("-expect must be followed by a decimal integer"); 310 } 311 } 312 else if (argv[i].equals("-out")) 313 { 314 /* must have an arg */ 315 if (++i >= len || argv[i].startsWith("-")) 316 usage("-out must have a path argument"); 317 318 /* validate path */ 319 if (argv[i].length() != 0) { 320 out_path = argv[i] + File.separator; 321 File f = new File(out_path); 322 if (!f.exists() || !f.isDirectory()) 323 out_path = null; 324 } 325 if (out_path == null) 326 usage("-out argument must be a valid existing path"); 327 } 328 else if (argv[i].equals("-compact_red")) opt_compact_red = true; 329 else if (argv[i].equals("-nosummary")) no_summary = true; 330 else if (argv[i].equals("-nowarn")) emit.nowarn = true; 331 else if (argv[i].equals("-dump_states")) opt_dump_states = true; 332 else if (argv[i].equals("-dump_tables")) opt_dump_tables = true; 333 else if (argv[i].equals("-progress")) print_progress = true; 334 else if (argv[i].equals("-dump_grammar")) opt_dump_grammar = true; 335 else if (argv[i].equals("-dump")) 336 opt_dump_states = opt_dump_tables = opt_dump_grammar = true; 337 else if (argv[i].equals("-time")) opt_show_timing = true; 338 else if (argv[i].equals("-debug")) opt_do_debug = true; 339 else 340 { 341 usage("Unrecognized option \"" + argv[i] + "\""); 342 } 343 } 344 } 345 346 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 347 348 /*-------*/ 349 /* Files */ 350 /*-------*/ 351 352 /** Input file. This is a buffered version of System.in. */ 353 protected static BufferedInputStream input_file; 354 355 /** Output file for the parser class. */ 356 protected static PrintStream parser_class_file; 357 358 /** Output file for the symbol constant class. */ 359 protected static PrintStream symbol_class_file; 360 361 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 362 363 /** Open various files used by the system. */ 364 protected static void open_files() 365 { 366 File fil; 367 String out_name; 368 369 /* use a buffered version of standard input */ 370 if (emit.input_file_name != null) 371 try { 372 input_file = new BufferedInputStream(new FileInputStream(emit.input_file_name)); 373 } catch (Exception ex) { 374 ex.printStackTrace(); 375 System.exit(3); 376 } 377 else 378 input_file = new BufferedInputStream(System.in); 379 380 /* open each of the output files */ 381 if (out_path == null) 382 out_path = ""; 383 384 /* parser class */ 385 out_name = out_path + emit.parser_class_name + ".java"; 386 fil = new File(out_name); 387 try { 388 parser_class_file = new PrintStream( 389 new BufferedOutputStream(new FileOutputStream(fil), 4096)); 390 } catch(Exception e) { 391 System.err.println("Can't open \"" + out_name + "\" for output"); 392 System.exit(3); 393 } 394 395 /* symbol constants class */ 396 out_name = out_path + emit.symbol_const_class_name + ".java"; 397 fil = new File(out_name); 398 try { 399 symbol_class_file = new PrintStream( 400 new BufferedOutputStream(new FileOutputStream(fil), 4096)); 401 } catch(Exception e) { 402 System.err.println("Can't open \"" + out_name + "\" for output"); 403 System.exit(4); 404 } 405 } 406 407 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 408 409 /** Close various files used by the system. */ 410 protected static void close_files() throws java.io.IOException 411 { 412 if (input_file != null) input_file.close(); 413 if (parser_class_file != null) parser_class_file.close(); 414 if (symbol_class_file != null) symbol_class_file.close(); 415 } 416 417 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 418 419 /** Parse the grammar specification from standard input. This produces 420 * sets of terminal, non-terminals, and productions which can be accessed 421 * via static variables of the respective classes, as well as the setting 422 * of various variables (mostly in the emit class) for small user supplied 423 * items such as the code to scan with. 424 */ 425 protected static void parse_grammar_spec() throws java.lang.Exception 426 { 427 parser parser_obj; 428 429 /* create a parser and parse with it */ 430 parser_obj = new parser(); 431 try { 432 if (opt_do_debug) 433 parser_obj.debug_parse(); 434 else 435 parser_obj.parse(); 436 } catch (Exception e) 437 { 438 /* something threw an exception. catch it and emit a message so we 439 have a line number to work with, then re-throw it */ 440 lexer.emit_error("Internal error: Unexpected exception"); 441 throw e; 442 } 443 } 444 445 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 446 447 /** Check for unused symbols. Unreduced productions get checked when 448 * tables are created. 449 */ 450 protected static void check_unused() 451 { 452 terminal term; 453 non_terminal nt; 454 455 /* check for unused terminals */ 456 for (Enumeration t = terminal.all(); t.hasMoreElements(); ) 457 { 458 term = (terminal)t.nextElement(); 459 460 /* don't issue a message for EOF */ 461 if (term == terminal.EOF) continue; 462 463 /* or error */ 464 if (term == terminal.error) continue; 465 466 /* is this one unused */ 467 if (term.use_count() == 0) 468 { 469 /* count it and warn if we are doing warnings */ 470 emit.unused_term++; 471 if (!emit.nowarn) 472 { 473 System.err.println("Warning: Terminal \"" + term.name() + 474 "\" was declared but never used"); 475 lexer.warning_count++; 476 } 477 } 478 } 479 480 /* check for unused non terminals */ 481 for (Enumeration n = non_terminal.all(); n.hasMoreElements(); ) 482 { 483 nt = (non_terminal)n.nextElement(); 484 485 /* is this one unused */ 486 if (nt.use_count() == 0) 487 { 488 /* count and warn if we are doing warnings */ 489 emit.unused_term++; 490 if (!emit.nowarn) 491 { 492 System.err.println("Warning: Non terminal \"" + nt.name() + 493 "\" was declared but never used"); 494 lexer.warning_count++; 495 } 496 } 497 } 498 499 } 500 501 /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ 502 /* . . Internal Results of Generating the Parser . .*/ 503 /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ 504 505 /** Start state in the overall state machine. */ 506 protected static lalr_state start_state; 507 508 /** Resulting parse action table. */ 509 protected static parse_action_table action_table; 510 511 /** Resulting reduce-goto table. */ 512 protected static parse_reduce_table reduce_table; 513 514 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 515 516 /** Build the (internal) parser from the previously parsed specification. 517 * This includes:<ul> 518 * <li> Computing nullability of non-terminals. 519 * <li> Computing first sets of non-terminals and productions. 520 * <li> Building the viable prefix recognizer machine. 521 * <li> Filling in the (internal) parse tables. 522 * <li> Checking for unreduced productions. 523 * </ul> 524 */ 525 protected static void build_parser() throws internal_error 526 { 527 /* compute nullability of all non terminals */ 528 if (opt_do_debug || print_progress) 529 System.err.println(" Computing non-terminal nullability..."); 530 non_terminal.compute_nullability(); 531 532 nullability_end = System.currentTimeMillis(); 533 534 /* compute first sets of all non terminals */ 535 if (opt_do_debug || print_progress) 536 System.err.println(" Computing first sets..."); 537 non_terminal.compute_first_sets(); 538 539 first_end = System.currentTimeMillis(); 540 541 /* build the LR viable prefix recognition machine */ 542 if (opt_do_debug || print_progress) 543 System.err.println(" Building state machine..."); 544 start_state = lalr_state.build_machine(emit.start_production); 545 546 machine_end = System.currentTimeMillis(); 547 548 /* build the LR parser action and reduce-goto tables */ 549 if (opt_do_debug || print_progress) 550 System.err.println(" Filling in tables..."); 551 action_table = new parse_action_table(); 552 reduce_table = new parse_reduce_table(); 553 for (Enumeration st = lalr_state.all(); st.hasMoreElements(); ) 554 { 555 ((lalr_state)st.nextElement()).build_table_entries( 556 action_table, reduce_table); 557 } 558 559 table_end = System.currentTimeMillis(); 560 561 /* check and warn for non-reduced productions */ 562 if (opt_do_debug || print_progress) 563 System.err.println(" Checking for non-reduced productions..."); 564 action_table.check_reductions(); 565 566 reduce_check_end = System.currentTimeMillis(); 567 568 /* if we have more conflicts than we expected issue a message and die */ 569 if (emit.num_conflicts > expect_conflicts) 570 { 571 System.err.println("*** More conflicts encountered than expected " + 572 "-- parser generation aborted"); 573 lexer.error_count++; 574 build_end = System.currentTimeMillis(); 575 576 /* do dumps and summary as needed */ 577 if (opt_dump_grammar) dump_grammar(); 578 if (opt_dump_states) dump_machine(); 579 if (!no_summary) emit_summary(false); 580 581 System.exit(100); 582 } 583 } 584 585 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 586 587 /** Call the emit routines necessary to write out the generated parser. */ 588 protected static void emit_parser() throws internal_error 589 { 590 emit.symbols(symbol_class_file, include_non_terms); 591 emit.parser(parser_class_file, action_table, reduce_table, 592 start_state.index(), emit.start_production, opt_compact_red); 593 } 594 595 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 596 597 /** Helper routine to optionally return a plural or non-plural ending. 598 * @param val the numerical value determining plurality. 599 */ 600 protected static String plural(int val) 601 { 602 if (val == 1) 603 return ""; 604 else 605 return "s"; 606 } 607 608 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 609 610 /** Emit a long summary message to standard error (System.err) which 611 * summarizes what was found in the specification, how many states were 612 * produced, how many conflicts were found, etc. A detailed timing 613 * summary is also produced if it was requested by the user. 614 * @param output_produced did the system get far enough to generate code. 615 */ 616 protected static void emit_summary(boolean output_produced) 617 { 618 final_time = System.currentTimeMillis(); 619 620 if (no_summary) return; 621 622 System.err.println("------- " + version.title_str + 623 " Parser Generation Summary -------"); 624 625 /* error and warning count */ 626 System.err.println(" " + lexer.error_count + " error" + 627 plural(lexer.error_count) + " and " + lexer.warning_count + 628 " warning" + plural(lexer.warning_count)); 629 630 /* basic stats */ 631 System.err.print(" " + terminal.number() + " terminal" + 632 plural(terminal.number()) + ", "); 633 System.err.print(non_terminal.number() + " non terminal" + 634 plural(non_terminal.number()) + ", and "); 635 System.err.println(production.number() + " production" + 636 plural(production.number()) + " declared, "); 637 System.err.println(" producing " + lalr_state.number() + 638 " unique parse states."); 639 640 /* unused symbols */ 641 System.err.println(" " + emit.unused_term + " terminal" + 642 plural(emit.unused_term) + " declared but not used."); 643 System.err.println(" " + emit.unused_non_term + " non terminal" + 644 plural(emit.unused_term) + " declared but not used."); 645 646 /* productions that didn't reduce */ 647 System.err.println(" " + emit.not_reduced + " production" + 648 plural(emit.not_reduced) + " never reduced."); 649 650 /* conflicts */ 651 System.err.println(" " + emit.num_conflicts + " conflict" + 652 plural(emit.num_conflicts) + " detected" + 653 " (" + expect_conflicts + " expected)."); 654 655 /* code location */ 656 if (output_produced) 657 System.err.println(" Code written to \"" + emit.parser_class_name + 658 ".java\", and \"" + emit.symbol_const_class_name + ".java\"."); 659 else 660 System.err.println(" No code produced."); 661 662 if (opt_show_timing) show_times(); 663 664 System.err.println( 665 "---------------------------------------------------- (" + 666 version.version_str + ")"); 667 } 668 669 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 670 671 /** Produce the optional timing summary as part of an overall summary. */ 672 protected static void show_times() 673 { 674 long total_time = final_time - start_time; 675 676 System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . "); 677 System.err.println(" Timing Summary"); 678 System.err.println(" Total time " 679 + timestr(final_time-start_time, total_time)); 680 System.err.println(" Startup " 681 + timestr(prelim_end-start_time, total_time)); 682 System.err.println(" Parse " 683 + timestr(parse_end-prelim_end, total_time) ); 684 if (check_end != 0) 685 System.err.println(" Checking " 686 + timestr(check_end-parse_end, total_time)); 687 if (check_end != 0 && build_end != 0) 688 System.err.println(" Parser Build " 689 + timestr(build_end-check_end, total_time)); 690 if (nullability_end != 0 && check_end != 0) 691 System.err.println(" Nullability " 692 + timestr(nullability_end-check_end, total_time)); 693 if (first_end != 0 && nullability_end != 0) 694 System.err.println(" First sets " 695 + timestr(first_end-nullability_end, total_time)); 696 if (machine_end != 0 && first_end != 0) 697 System.err.println(" State build " 698 + timestr(machine_end-first_end, total_time)); 699 if (table_end != 0 && machine_end != 0) 700 System.err.println(" Table build " 701 + timestr(table_end-machine_end, total_time)); 702 if (reduce_check_end != 0 && table_end != 0) 703 System.err.println(" Checking " 704 + timestr(reduce_check_end-table_end, total_time)); 705 if (emit_end != 0 && build_end != 0) 706 System.err.println(" Code Output " 707 + timestr(emit_end-build_end, total_time)); 708 if (emit.symbols_time != 0) 709 System.err.println(" Symbols " 710 + timestr(emit.symbols_time, total_time)); 711 if (emit.parser_time != 0) 712 System.err.println(" Parser class " 713 + timestr(emit.parser_time, total_time)); 714 if (emit.action_code_time != 0) 715 System.err.println(" Actions " 716 + timestr(emit.action_code_time, total_time)); 717 if (emit.production_table_time != 0) 718 System.err.println(" Prod table " 719 + timestr(emit.production_table_time, total_time)); 720 if (emit.action_table_time != 0) 721 System.err.println(" Action tab " 722 + timestr(emit.action_table_time, total_time)); 723 if (emit.goto_table_time != 0) 724 System.err.println(" Reduce tab " 725 + timestr(emit.goto_table_time, total_time)); 726 727 System.err.println(" Dump Output " 728 + timestr(dump_end-emit_end, total_time)); 729 } 730 731 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 732 733 /** Helper routine to format a decimal based display of seconds and 734 * percentage of total time given counts of milliseconds. Note: this 735 * is broken for use with some instances of negative time (since we don't 736 * use any negative time here, we let if be for now). 737 * @param time_val the value being formatted (in ms). 738 * @param total_time total time percentages are calculated against (in ms). 739 */ 740 protected static String timestr(long time_val, long total_time) 741 { 742 boolean neg; 743 long ms = 0; 744 long sec = 0; 745 long percent10; 746 String pad; 747 748 /* work with positives only */ 749 neg = time_val < 0; 750 if (neg) time_val = -time_val; 751 752 /* pull out seconds and ms */ 753 ms = time_val % 1000; 754 sec = time_val / 1000; 755 756 /* construct a pad to blank fill seconds out to 4 places */ 757 if (sec < 10) 758 pad = " "; 759 else if (sec < 100) 760 pad = " "; 761 else if (sec < 1000) 762 pad = " "; 763 else 764 pad = ""; 765 766 /* calculate 10 times the percentage of total */ 767 percent10 = (time_val*1000)/total_time; 768 769 /* build and return the output string */ 770 return (neg ? "-" : "") + pad + sec + "." + 771 ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" + 772 " (" + percent10/10 + "." + percent10%10 + "%)"; 773 } 774 775 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 776 777 /** Produce a human readable dump of the grammar. */ 778 public static void dump_grammar() throws internal_error 779 { 780 int cnt; 781 Enumeration t, n, p; 782 production prod; 783 784 System.err.println("===== Terminals ====="); 785 for (t = terminal.all(), cnt=0; t.hasMoreElements(); cnt++) 786 { 787 System.err.print(((terminal)t.nextElement()).name() + " "); 788 if ((cnt+1) % 5 == 0) System.err.println(); 789 } 790 System.err.println(); 791 System.err.println(); 792 793 System.err.println("===== Non terminals ====="); 794 for (n=non_terminal.all(), cnt=0; n.hasMoreElements(); cnt++) 795 { 796 System.err.print(((non_terminal)n.nextElement()).name() + " "); 797 if ((cnt+1) % 5 == 0) System.err.println(); 798 } 799 System.err.println(); 800 System.err.println(); 801 802 803 System.err.println("===== Productions ====="); 804 for (p=production.all(); p.hasMoreElements(); ) 805 { 806 prod = (production)p.nextElement(); 807 System.err.print(prod.lhs().the_symbol().name() + " ::= "); 808 for (int i=0; i<prod.rhs_length(); i++) 809 if (prod.rhs(i).is_action()) 810 System.err.print("{action} "); 811 else 812 System.err.print( 813 ((symbol_part)prod.rhs(i)).the_symbol().name() + " "); 814 System.err.println(); 815 } 816 System.err.println(); 817 } 818 819 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 820 821 /** Produce a (semi-) human readable dump of the complete viable prefix 822 * recognition state machine. 823 */ 824 public static void dump_machine() 825 { 826 lalr_state ordered[] = new lalr_state[lalr_state.number()]; 827 828 /* put the states in sorted order for a nicer display */ 829 for (Enumeration s = lalr_state.all(); s.hasMoreElements(); ) 830 { 831 lalr_state st = (lalr_state)s.nextElement(); 832 ordered[st.index()] = st; 833 } 834 835 System.err.println("===== Viable Prefix Recognizer ====="); 836 for (int i = 0; i<lalr_state.number(); i++) 837 { 838 if (ordered[i] == start_state) System.err.print("START "); 839 System.err.println(ordered[i]); 840 System.err.println("-------------------"); 841 } 842 } 843 844 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 845 846 /** Produce a (semi-) human readable dumps of the parse tables */ 847 public static void dump_tables() 848 { 849 System.err.println(action_table); 850 System.err.println(reduce_table); 851 } 852 853 /*-----------------------------------------------------------*/ 854 855 }; 856 857