| |
| package java_cup; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.PrintStream; |
| import java.util.Enumeration; |
| |
| /** This class serves as the main driver for the JavaCup system. |
| * It accepts user options and coordinates overall control flow. |
| * The main flow of control includes the following activities: |
| * <ul> |
| * <li> Parse user supplied arguments and options. |
| * <li> Open output files. |
| * <li> Parse the specification from standard input. |
| * <li> Check for unused terminals, non-terminals, and productions. |
| * <li> Build the state machine, tables, etc. |
| * <li> Output the generated code. |
| * <li> Close output files. |
| * <li> Print a summary if requested. |
| * </ul> |
| * |
| * Options to the main program include: <dl> |
| * <dt> -package name |
| * <dd> specify package generated classes go in [default none] |
| * <dt> -parser name |
| * <dd> specify parser class name [default "parser"] |
| * <dt> -symbols name |
| * <dd> specify name for symbol constant class [default "sym"] |
| * <dt> -nonterms |
| * <dd> put non terminals in symbol constant class |
| * <dt> -expect # |
| * <dd> number of conflicts expected/allowed [default 0] |
| * <dt> -compact_red |
| * <dd> compact tables by defaulting to most frequent reduce |
| * <dt> -nowarn |
| * <dd> don't warn about useless productions, etc. |
| * <dt> -nosummary |
| * <dd> don't print the usual summary of parse states, etc. |
| * <dt> -progress |
| * <dd> print messages to indicate progress of the system |
| * <dt> -time |
| * <dd> print time usage summary |
| * <dt> -dump_grammar |
| * <dd> produce a dump of the symbols and grammar |
| * <dt> -dump_states |
| * <dd> produce a dump of parse state machine |
| * <dt> -dump_tables |
| * <dd> produce a dump of the parse tables |
| * <dt> -dump |
| * <dd> produce a dump of all of the above |
| * <dt> -debug |
| * <dd> turn on debugging messages within JavaCup |
| * </dl> |
| * |
| * @version last updated: 11/25/95 |
| * @author Scott Hudson |
| */ |
| |
| public class Main { |
| |
| /*-----------------------------------------------------------*/ |
| /*--- Constructor(s) ----------------------------------------*/ |
| /*-----------------------------------------------------------*/ |
| /** Only constructor is private, so we do not allocate any instances of this |
| class. */ |
| private Main() { } |
| |
| /*-------------------------*/ |
| /* Options set by the user */ |
| /*-------------------------*/ |
| /** User option -- do we print progress messages. */ |
| protected static boolean print_progress = false; |
| /** User option -- do we produce a dump of the state machine */ |
| protected static boolean opt_dump_states = false; |
| /** User option -- do we produce a dump of the parse tables */ |
| protected static boolean opt_dump_tables = false; |
| /** User option -- do we produce a dump of the grammar */ |
| protected static boolean opt_dump_grammar = false; |
| /** User option -- do we show timing information as a part of the summary */ |
| protected static boolean opt_show_timing = false; |
| /** User option -- do we run produce extra debugging messages */ |
| protected static boolean opt_do_debug = false; |
| /** User option -- do we compact tables by making most common reduce the |
| default action */ |
| protected static boolean opt_compact_red = false; |
| /** User option -- should we include non terminal symbol numbers in the |
| symbol constant class. */ |
| protected static boolean include_non_terms = false; |
| /** User option -- do not print a summary. */ |
| protected static boolean no_summary = false; |
| /** User option -- number of conflicts to expect */ |
| protected static int expect_conflicts = 0; |
| |
| /*----------------------------------------------------------------------*/ |
| /* Timing data (not all of these time intervals are mutually exclusive) */ |
| /*----------------------------------------------------------------------*/ |
| /** Timing data -- when did we start */ |
| protected static long start_time = 0; |
| /** Timing data -- when did we end preliminaries */ |
| protected static long prelim_end = 0; |
| /** Timing data -- when did we end parsing */ |
| protected static long parse_end = 0; |
| /** Timing data -- when did we end checking */ |
| protected static long check_end = 0; |
| /** Timing data -- when did we end dumping */ |
| protected static long dump_end = 0; |
| /** Timing data -- when did we end state and table building */ |
| protected static long build_end = 0; |
| /** Timing data -- when did we end nullability calculation */ |
| protected static long nullability_end = 0; |
| /** Timing data -- when did we end first set calculation */ |
| protected static long first_end = 0; |
| /** Timing data -- when did we end state machine construction */ |
| protected static long machine_end = 0; |
| /** Timing data -- when did we end table construction */ |
| protected static long table_end = 0; |
| /** Timing data -- when did we end checking for non-reduced productions */ |
| protected static long reduce_check_end = 0; |
| /** Timing data -- when did we finish emitting code */ |
| protected static long emit_end = 0; |
| /** Timing data -- when were we completely done */ |
| protected static long final_time = 0; |
| |
| /* Additional timing information is also collected in emit */ |
| |
| /** Path to create output files */ |
| private static String out_path = null; |
| |
| /*-----------------------------------------------------------*/ |
| /*--- Main Program ------------------------------------------*/ |
| /*-----------------------------------------------------------*/ |
| |
| /** The main driver for the system. |
| * @param argv an array of strings containing command line arguments. |
| */ |
| public static void main(String argv[]) |
| throws internal_error, java.io.IOException, java.lang.Exception |
| { |
| boolean did_output = false; |
| |
| start_time = System.currentTimeMillis(); |
| |
| /* process user options and arguments */ |
| parse_args(argv); |
| |
| /* open output files */ |
| if (print_progress) System.err.println("Opening files..."); |
| open_files(); |
| |
| prelim_end = System.currentTimeMillis(); |
| |
| /* parse spec into internal data structures */ |
| if (print_progress) |
| System.err.println("Parsing specification from standard input..."); |
| parse_grammar_spec(); |
| |
| parse_end = System.currentTimeMillis(); |
| |
| /* don't proceed unless we are error free */ |
| if (lexer.error_count == 0) |
| { |
| /* check for unused bits */ |
| if (print_progress) System.err.println("Checking specification..."); |
| check_unused(); |
| |
| check_end = System.currentTimeMillis(); |
| |
| /* build the state machine and parse tables */ |
| if (print_progress) System.err.println("Building parse tables..."); |
| build_parser(); |
| |
| build_end = System.currentTimeMillis(); |
| |
| /* output the generated code */ |
| if (print_progress) System.err.println("Writing parser..."); |
| emit_parser(); |
| did_output = true; |
| |
| emit_end = System.currentTimeMillis(); |
| } |
| else |
| { |
| /* fix up the times to make the summary easier */ |
| emit_end = parse_end; |
| } |
| |
| /* do requested dumps */ |
| if (opt_dump_grammar) dump_grammar(); |
| if (opt_dump_states) dump_machine(); |
| if (opt_dump_tables) dump_tables(); |
| |
| dump_end = System.currentTimeMillis(); |
| |
| /* close output files */ |
| if (print_progress) System.err.println("Closing files..."); |
| close_files(); |
| |
| /* produce a summary if desired */ |
| if (!no_summary) emit_summary(did_output); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Print a "usage message" that described possible command line options, |
| * then exit. |
| * @param message a specific error message to preface the usage message by. |
| */ |
| protected static void usage(String message) |
| { |
| System.err.println(); |
| System.err.println(message); |
| System.err.println(); |
| System.err.println( |
| "Usage: " + version.program_name + " [options]\n" + |
| " and expects a specification file on standard input.\n" + |
| " Legal options include:\n" + |
| " -out path specify the output files path [default current directory]\n" + |
| " -package name specify package generated classes go in [default none]\n" + |
| " -parser name specify parser class name [default \"parser\"]\n" + |
| " -symbols name specify name for symbol constant class [default \"sym\"]\n"+ |
| " -nonterms put non terminals in symbol constant class\n" + |
| " -expect # number of conflicts expected/allowed [default 0]\n" + |
| " -compact_red compact tables by defaulting to most frequent reduce\n" + |
| " -nowarn don't warn about useless productions, etc.\n" + |
| " -nosummary don't print the usual summary of parse states, etc.\n" + |
| " -progress print messages to indicate progress of the system\n" + |
| " -time print time usage summary\n" + |
| " -dump_grammar produce a human readable dump of the symbols and grammar\n"+ |
| " -dump_states produce a dump of parse state machine\n"+ |
| " -dump_tables produce a dump of the parse tables\n"+ |
| " -dump produce a dump of all of the above\n" |
| ); |
| System.exit(1); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Parse command line options and arguments to set various user-option |
| * flags and variables. |
| * @param argv the command line arguments to be parsed. |
| */ |
| protected static void parse_args(String argv[]) |
| { |
| int len = argv.length; |
| int i; |
| |
| /* parse the options */ |
| for (i=0; i<len; i++) |
| { |
| /* try to get the various options */ |
| if (argv[i].equals("-package")) |
| { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-") || |
| argv[i].endsWith(".cup")) |
| usage("-package must have a name argument"); |
| |
| /* record the name */ |
| emit.package_name = argv[i]; |
| } |
| else if (argv[i].equals("-parser")) |
| { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-") || |
| argv[i].endsWith(".cup")) |
| usage("-parser must have a name argument"); |
| |
| /* record the name */ |
| emit.parser_class_name = argv[i]; |
| } |
| else if (argv[i].equals("-input")) { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-") || |
| argv[i].endsWith(".cup")) |
| usage("-input must have a name argument"); |
| |
| /* record the name */ |
| emit.input_file_name = argv[i]; |
| } |
| else if (argv[i].equals("-symbols")) |
| { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-") || |
| argv[i].endsWith(".cup")) |
| usage("-symbols must have a name argument"); |
| |
| /* record the name */ |
| emit.symbol_const_class_name = argv[i]; |
| } |
| else if (argv[i].equals("-nonterms")) |
| { |
| include_non_terms = true; |
| } |
| else if (argv[i].equals("-expect")) |
| { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-") || |
| argv[i].endsWith(".cup")) |
| usage("-expect must have a name argument"); |
| |
| /* record the number */ |
| try { |
| expect_conflicts = Integer.parseInt(argv[i]); |
| } catch (NumberFormatException e) { |
| usage("-expect must be followed by a decimal integer"); |
| } |
| } |
| else if (argv[i].equals("-out")) |
| { |
| /* must have an arg */ |
| if (++i >= len || argv[i].startsWith("-")) |
| usage("-out must have a path argument"); |
| |
| /* validate path */ |
| if (argv[i].length() != 0) { |
| out_path = argv[i] + File.separator; |
| File f = new File(out_path); |
| if (!f.exists() || !f.isDirectory()) |
| out_path = null; |
| } |
| if (out_path == null) |
| usage("-out argument must be a valid existing path"); |
| } |
| else if (argv[i].equals("-compact_red")) opt_compact_red = true; |
| else if (argv[i].equals("-nosummary")) no_summary = true; |
| else if (argv[i].equals("-nowarn")) emit.nowarn = true; |
| else if (argv[i].equals("-dump_states")) opt_dump_states = true; |
| else if (argv[i].equals("-dump_tables")) opt_dump_tables = true; |
| else if (argv[i].equals("-progress")) print_progress = true; |
| else if (argv[i].equals("-dump_grammar")) opt_dump_grammar = true; |
| else if (argv[i].equals("-dump")) |
| opt_dump_states = opt_dump_tables = opt_dump_grammar = true; |
| else if (argv[i].equals("-time")) opt_show_timing = true; |
| else if (argv[i].equals("-debug")) opt_do_debug = true; |
| else |
| { |
| usage("Unrecognized option \"" + argv[i] + "\""); |
| } |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /*-------*/ |
| /* Files */ |
| /*-------*/ |
| |
| /** Input file. This is a buffered version of System.in. */ |
| protected static BufferedInputStream input_file; |
| |
| /** Output file for the parser class. */ |
| protected static PrintStream parser_class_file; |
| |
| /** Output file for the symbol constant class. */ |
| protected static PrintStream symbol_class_file; |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Open various files used by the system. */ |
| protected static void open_files() |
| { |
| File fil; |
| String out_name; |
| |
| /* use a buffered version of standard input */ |
| if (emit.input_file_name != null) |
| try { |
| input_file = new BufferedInputStream(new FileInputStream(emit.input_file_name)); |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| System.exit(3); |
| } |
| else |
| input_file = new BufferedInputStream(System.in); |
| |
| /* open each of the output files */ |
| if (out_path == null) |
| out_path = ""; |
| |
| /* parser class */ |
| out_name = out_path + emit.parser_class_name + ".java"; |
| fil = new File(out_name); |
| try { |
| parser_class_file = new PrintStream( |
| new BufferedOutputStream(new FileOutputStream(fil), 4096)); |
| } catch(Exception e) { |
| System.err.println("Can't open \"" + out_name + "\" for output"); |
| System.exit(3); |
| } |
| |
| /* symbol constants class */ |
| out_name = out_path + emit.symbol_const_class_name + ".java"; |
| fil = new File(out_name); |
| try { |
| symbol_class_file = new PrintStream( |
| new BufferedOutputStream(new FileOutputStream(fil), 4096)); |
| } catch(Exception e) { |
| System.err.println("Can't open \"" + out_name + "\" for output"); |
| System.exit(4); |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Close various files used by the system. */ |
| protected static void close_files() throws java.io.IOException |
| { |
| if (input_file != null) input_file.close(); |
| if (parser_class_file != null) parser_class_file.close(); |
| if (symbol_class_file != null) symbol_class_file.close(); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Parse the grammar specification from standard input. This produces |
| * sets of terminal, non-terminals, and productions which can be accessed |
| * via static variables of the respective classes, as well as the setting |
| * of various variables (mostly in the emit class) for small user supplied |
| * items such as the code to scan with. |
| */ |
| protected static void parse_grammar_spec() throws java.lang.Exception |
| { |
| parser parser_obj; |
| |
| /* create a parser and parse with it */ |
| parser_obj = new parser(); |
| try { |
| if (opt_do_debug) |
| parser_obj.debug_parse(); |
| else |
| parser_obj.parse(); |
| } catch (Exception e) |
| { |
| /* something threw an exception. catch it and emit a message so we |
| have a line number to work with, then re-throw it */ |
| lexer.emit_error("Internal error: Unexpected exception"); |
| throw e; |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Check for unused symbols. Unreduced productions get checked when |
| * tables are created. |
| */ |
| protected static void check_unused() |
| { |
| terminal term; |
| non_terminal nt; |
| |
| /* check for unused terminals */ |
| for (Enumeration t = terminal.all(); t.hasMoreElements(); ) |
| { |
| term = (terminal)t.nextElement(); |
| |
| /* don't issue a message for EOF */ |
| if (term == terminal.EOF) continue; |
| |
| /* or error */ |
| if (term == terminal.error) continue; |
| |
| /* is this one unused */ |
| if (term.use_count() == 0) |
| { |
| /* count it and warn if we are doing warnings */ |
| emit.unused_term++; |
| if (!emit.nowarn) |
| { |
| System.err.println("Warning: Terminal \"" + term.name() + |
| "\" was declared but never used"); |
| lexer.warning_count++; |
| } |
| } |
| } |
| |
| /* check for unused non terminals */ |
| for (Enumeration n = non_terminal.all(); n.hasMoreElements(); ) |
| { |
| nt = (non_terminal)n.nextElement(); |
| |
| /* is this one unused */ |
| if (nt.use_count() == 0) |
| { |
| /* count and warn if we are doing warnings */ |
| emit.unused_term++; |
| if (!emit.nowarn) |
| { |
| System.err.println("Warning: Non terminal \"" + nt.name() + |
| "\" was declared but never used"); |
| lexer.warning_count++; |
| } |
| } |
| } |
| |
| } |
| |
| /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| /* . . Internal Results of Generating the Parser . .*/ |
| /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Start state in the overall state machine. */ |
| protected static lalr_state start_state; |
| |
| /** Resulting parse action table. */ |
| protected static parse_action_table action_table; |
| |
| /** Resulting reduce-goto table. */ |
| protected static parse_reduce_table reduce_table; |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Build the (internal) parser from the previously parsed specification. |
| * This includes:<ul> |
| * <li> Computing nullability of non-terminals. |
| * <li> Computing first sets of non-terminals and productions. |
| * <li> Building the viable prefix recognizer machine. |
| * <li> Filling in the (internal) parse tables. |
| * <li> Checking for unreduced productions. |
| * </ul> |
| */ |
| protected static void build_parser() throws internal_error |
| { |
| /* compute nullability of all non terminals */ |
| if (opt_do_debug || print_progress) |
| System.err.println(" Computing non-terminal nullability..."); |
| non_terminal.compute_nullability(); |
| |
| nullability_end = System.currentTimeMillis(); |
| |
| /* compute first sets of all non terminals */ |
| if (opt_do_debug || print_progress) |
| System.err.println(" Computing first sets..."); |
| non_terminal.compute_first_sets(); |
| |
| first_end = System.currentTimeMillis(); |
| |
| /* build the LR viable prefix recognition machine */ |
| if (opt_do_debug || print_progress) |
| System.err.println(" Building state machine..."); |
| start_state = lalr_state.build_machine(emit.start_production); |
| |
| machine_end = System.currentTimeMillis(); |
| |
| /* build the LR parser action and reduce-goto tables */ |
| if (opt_do_debug || print_progress) |
| System.err.println(" Filling in tables..."); |
| action_table = new parse_action_table(); |
| reduce_table = new parse_reduce_table(); |
| for (Enumeration st = lalr_state.all(); st.hasMoreElements(); ) |
| { |
| ((lalr_state)st.nextElement()).build_table_entries( |
| action_table, reduce_table); |
| } |
| |
| table_end = System.currentTimeMillis(); |
| |
| /* check and warn for non-reduced productions */ |
| if (opt_do_debug || print_progress) |
| System.err.println(" Checking for non-reduced productions..."); |
| action_table.check_reductions(); |
| |
| reduce_check_end = System.currentTimeMillis(); |
| |
| /* if we have more conflicts than we expected issue a message and die */ |
| if (emit.num_conflicts > expect_conflicts) |
| { |
| System.err.println("*** More conflicts encountered than expected " + |
| "-- parser generation aborted"); |
| lexer.error_count++; |
| build_end = System.currentTimeMillis(); |
| |
| /* do dumps and summary as needed */ |
| if (opt_dump_grammar) dump_grammar(); |
| if (opt_dump_states) dump_machine(); |
| if (!no_summary) emit_summary(false); |
| |
| System.exit(100); |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Call the emit routines necessary to write out the generated parser. */ |
| protected static void emit_parser() throws internal_error |
| { |
| emit.symbols(symbol_class_file, include_non_terms); |
| emit.parser(parser_class_file, action_table, reduce_table, |
| start_state.index(), emit.start_production, opt_compact_red); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Helper routine to optionally return a plural or non-plural ending. |
| * @param val the numerical value determining plurality. |
| */ |
| protected static String plural(int val) |
| { |
| if (val == 1) |
| return ""; |
| else |
| return "s"; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Emit a long summary message to standard error (System.err) which |
| * summarizes what was found in the specification, how many states were |
| * produced, how many conflicts were found, etc. A detailed timing |
| * summary is also produced if it was requested by the user. |
| * @param output_produced did the system get far enough to generate code. |
| */ |
| protected static void emit_summary(boolean output_produced) |
| { |
| final_time = System.currentTimeMillis(); |
| |
| if (no_summary) return; |
| |
| System.err.println("------- " + version.title_str + |
| " Parser Generation Summary -------"); |
| |
| /* error and warning count */ |
| System.err.println(" " + lexer.error_count + " error" + |
| plural(lexer.error_count) + " and " + lexer.warning_count + |
| " warning" + plural(lexer.warning_count)); |
| |
| /* basic stats */ |
| System.err.print(" " + terminal.number() + " terminal" + |
| plural(terminal.number()) + ", "); |
| System.err.print(non_terminal.number() + " non terminal" + |
| plural(non_terminal.number()) + ", and "); |
| System.err.println(production.number() + " production" + |
| plural(production.number()) + " declared, "); |
| System.err.println(" producing " + lalr_state.number() + |
| " unique parse states."); |
| |
| /* unused symbols */ |
| System.err.println(" " + emit.unused_term + " terminal" + |
| plural(emit.unused_term) + " declared but not used."); |
| System.err.println(" " + emit.unused_non_term + " non terminal" + |
| plural(emit.unused_term) + " declared but not used."); |
| |
| /* productions that didn't reduce */ |
| System.err.println(" " + emit.not_reduced + " production" + |
| plural(emit.not_reduced) + " never reduced."); |
| |
| /* conflicts */ |
| System.err.println(" " + emit.num_conflicts + " conflict" + |
| plural(emit.num_conflicts) + " detected" + |
| " (" + expect_conflicts + " expected)."); |
| |
| /* code location */ |
| if (output_produced) |
| System.err.println(" Code written to \"" + emit.parser_class_name + |
| ".java\", and \"" + emit.symbol_const_class_name + ".java\"."); |
| else |
| System.err.println(" No code produced."); |
| |
| if (opt_show_timing) show_times(); |
| |
| System.err.println( |
| "---------------------------------------------------- (" + |
| version.version_str + ")"); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Produce the optional timing summary as part of an overall summary. */ |
| protected static void show_times() |
| { |
| long total_time = final_time - start_time; |
| |
| System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . "); |
| System.err.println(" Timing Summary"); |
| System.err.println(" Total time " |
| + timestr(final_time-start_time, total_time)); |
| System.err.println(" Startup " |
| + timestr(prelim_end-start_time, total_time)); |
| System.err.println(" Parse " |
| + timestr(parse_end-prelim_end, total_time) ); |
| if (check_end != 0) |
| System.err.println(" Checking " |
| + timestr(check_end-parse_end, total_time)); |
| if (check_end != 0 && build_end != 0) |
| System.err.println(" Parser Build " |
| + timestr(build_end-check_end, total_time)); |
| if (nullability_end != 0 && check_end != 0) |
| System.err.println(" Nullability " |
| + timestr(nullability_end-check_end, total_time)); |
| if (first_end != 0 && nullability_end != 0) |
| System.err.println(" First sets " |
| + timestr(first_end-nullability_end, total_time)); |
| if (machine_end != 0 && first_end != 0) |
| System.err.println(" State build " |
| + timestr(machine_end-first_end, total_time)); |
| if (table_end != 0 && machine_end != 0) |
| System.err.println(" Table build " |
| + timestr(table_end-machine_end, total_time)); |
| if (reduce_check_end != 0 && table_end != 0) |
| System.err.println(" Checking " |
| + timestr(reduce_check_end-table_end, total_time)); |
| if (emit_end != 0 && build_end != 0) |
| System.err.println(" Code Output " |
| + timestr(emit_end-build_end, total_time)); |
| if (emit.symbols_time != 0) |
| System.err.println(" Symbols " |
| + timestr(emit.symbols_time, total_time)); |
| if (emit.parser_time != 0) |
| System.err.println(" Parser class " |
| + timestr(emit.parser_time, total_time)); |
| if (emit.action_code_time != 0) |
| System.err.println(" Actions " |
| + timestr(emit.action_code_time, total_time)); |
| if (emit.production_table_time != 0) |
| System.err.println(" Prod table " |
| + timestr(emit.production_table_time, total_time)); |
| if (emit.action_table_time != 0) |
| System.err.println(" Action tab " |
| + timestr(emit.action_table_time, total_time)); |
| if (emit.goto_table_time != 0) |
| System.err.println(" Reduce tab " |
| + timestr(emit.goto_table_time, total_time)); |
| |
| System.err.println(" Dump Output " |
| + timestr(dump_end-emit_end, total_time)); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Helper routine to format a decimal based display of seconds and |
| * percentage of total time given counts of milliseconds. Note: this |
| * is broken for use with some instances of negative time (since we don't |
| * use any negative time here, we let if be for now). |
| * @param time_val the value being formatted (in ms). |
| * @param total_time total time percentages are calculated against (in ms). |
| */ |
| protected static String timestr(long time_val, long total_time) |
| { |
| boolean neg; |
| long ms = 0; |
| long sec = 0; |
| long percent10; |
| String pad; |
| |
| /* work with positives only */ |
| neg = time_val < 0; |
| if (neg) time_val = -time_val; |
| |
| /* pull out seconds and ms */ |
| ms = time_val % 1000; |
| sec = time_val / 1000; |
| |
| /* construct a pad to blank fill seconds out to 4 places */ |
| if (sec < 10) |
| pad = " "; |
| else if (sec < 100) |
| pad = " "; |
| else if (sec < 1000) |
| pad = " "; |
| else |
| pad = ""; |
| |
| /* calculate 10 times the percentage of total */ |
| percent10 = (time_val*1000)/total_time; |
| |
| /* build and return the output string */ |
| return (neg ? "-" : "") + pad + sec + "." + |
| ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" + |
| " (" + percent10/10 + "." + percent10%10 + "%)"; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Produce a human readable dump of the grammar. */ |
| public static void dump_grammar() throws internal_error |
| { |
| int cnt; |
| Enumeration t, n, p; |
| production prod; |
| |
| System.err.println("===== Terminals ====="); |
| for (t = terminal.all(), cnt=0; t.hasMoreElements(); cnt++) |
| { |
| System.err.print(((terminal)t.nextElement()).name() + " "); |
| if ((cnt+1) % 5 == 0) System.err.println(); |
| } |
| System.err.println(); |
| System.err.println(); |
| |
| System.err.println("===== Non terminals ====="); |
| for (n=non_terminal.all(), cnt=0; n.hasMoreElements(); cnt++) |
| { |
| System.err.print(((non_terminal)n.nextElement()).name() + " "); |
| if ((cnt+1) % 5 == 0) System.err.println(); |
| } |
| System.err.println(); |
| System.err.println(); |
| |
| |
| System.err.println("===== Productions ====="); |
| for (p=production.all(); p.hasMoreElements(); ) |
| { |
| prod = (production)p.nextElement(); |
| System.err.print(prod.lhs().the_symbol().name() + " ::= "); |
| for (int i=0; i<prod.rhs_length(); i++) |
| if (prod.rhs(i).is_action()) |
| System.err.print("{action} "); |
| else |
| System.err.print( |
| ((symbol_part)prod.rhs(i)).the_symbol().name() + " "); |
| System.err.println(); |
| } |
| System.err.println(); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Produce a (semi-) human readable dump of the complete viable prefix |
| * recognition state machine. |
| */ |
| public static void dump_machine() |
| { |
| lalr_state ordered[] = new lalr_state[lalr_state.number()]; |
| |
| /* put the states in sorted order for a nicer display */ |
| for (Enumeration s = lalr_state.all(); s.hasMoreElements(); ) |
| { |
| lalr_state st = (lalr_state)s.nextElement(); |
| ordered[st.index()] = st; |
| } |
| |
| System.err.println("===== Viable Prefix Recognizer ====="); |
| for (int i = 0; i<lalr_state.number(); i++) |
| { |
| if (ordered[i] == start_state) System.err.print("START "); |
| System.err.println(ordered[i]); |
| System.err.println("-------------------"); |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Produce a (semi-) human readable dumps of the parse tables */ |
| public static void dump_tables() |
| { |
| System.err.println(action_table); |
| System.err.println(reduce_table); |
| } |
| |
| /*-----------------------------------------------------------*/ |
| |
| }; |
| |