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.PrintWriter; import java.util.Enumeration; import java_cup.runtime.ComplexSymbolFactory; /** * 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> -interface * <dd> emit symbol constant <i>interface</i>, rather than class * <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 * <dt> -nopositions * <dd> don't generate the positions code * <dt> -noscanner * <dd> don't refer to java_cup.runtime.Scanner in the parser (for compatibility * with old runtimes) * <dt> -version * <dd> print version information for JavaCUP and halt. * </dl> * * @version last updated: 7/3/96 * @author Frank Flannery */ @SuppressWarnings ( { "all" } ) 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; /* frankf added this 6/18/96 */ /** User option -- should generator generate code for left/right values? */ protected static boolean lr_values = true; /** User option -- should symbols be put in a class or an interface? [CSA] */ protected static boolean sym_interface = false; /** * User option -- should generator suppress references to * java_cup.runtime.Scanner for compatibility with old runtimes? */ protected static boolean suppress_scanner = false; /*----------------------------------------------------------------------*/ /* 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 */ /*-----------------------------------------------------------*/ /*--- 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 (); /** clean all static members, that contain remaining stuff from earlier calls */ terminal.clear (); production.clear (); action_production.clear (); emit.clear (); non_terminal.clear (); parse_reduce_row.clear (); parse_action_row.clear (); lalr_state.clear (); /* process user options and arguments */ parse_args ( argv ); /* * frankf 6/18/96 hackish, yes, but works */ emit.set_lr_values ( lr_values ); /* open output files */ if ( print_progress ) System.err.println ( "Opening files..." ); /* use a buffered version of standard input */ input_file = new BufferedInputStream ( System.in ); 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 ( ErrorManager.getManager ().getErrorCount () == 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 # of conflicts permits */ if ( ErrorManager.getManager ().getErrorCount () != 0 ) { // conflicts! don't emit code, don't dump tables. opt_dump_tables = false; } else { // everything's okay, emit parser. if ( print_progress ) System.err.println ( "Writing parser..." ); open_files (); emit_parser (); did_output = true; } } /* fix up the times to make the summary easier */ emit_end = System.currentTimeMillis (); /* 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 input/output files */ if ( print_progress ) System.err.println ( "Closing files..." ); close_files (); /* produce a summary if desired */ if ( !no_summary ) emit_summary ( did_output ); /* * If there were errors during the run, exit with non-zero status * (makefile-friendliness). --CSA */ if ( ErrorManager.getManager ().getErrorCount () != 0 ) System.exit ( 100 ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * 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] [filename]\n" + " and expects a specification file on standard input if no filename is given.\n" + " Legal options include:\n" + " -package name specify package generated classes go in [default none]\n" + " -destdir name specify the destination directory, to store the generated files in\n" + " -parser name specify parser class name [default \"parser\"]\n" + " -typearg args specify type arguments for parser class\n" + " -symbols name specify name for symbol constant class [default \"sym\"]\n" + " -interface put symbols in an interface, rather than a class\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" + " -nopositions don't propagate the left and right token position values\n" + " -noscanner don't refer to java_cup.runtime.Scanner\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" + " -version print the version information for CUP and exit\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 ( "-destdir" ) ) { /* must have an arg */ if ( ++i >= len || argv [ i ].startsWith ( "-" ) || argv [ i ].endsWith ( ".cup" ) ) usage ( "-destdir must have a name argument" ); /* record the name */ Main.dest_dir = new java.io.File ( 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 ( "-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 ( "-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; /* frankf 6/18/96 */ else if ( argv [ i ].equals ( "-nopositions" ) ) lr_values = false; /* CSA 12/21/97 */ else if ( argv [ i ].equals ( "-interface" ) ) sym_interface = true; /* CSA 23-Jul-1999 */ else if ( argv [ i ].equals ( "-noscanner" ) ) suppress_scanner = true; /* CSA 23-Jul-1999 */ else if ( argv [ i ].equals ( "-version" ) ) { System.out.println ( version.title_str ); System.exit ( 1 ); } /* TUM changes; suggested by Henning Niss 20050628 */ else if ( argv [ i ].equals ( "-typearg" ) ) { if ( ++i >= len || argv [ i ].startsWith ( "-" ) || argv [ i ].endsWith ( ".cup" ) ) usage ( "-symbols must have a name argument" ); /* record the typearg */ emit.class_type_argument = argv [ i ]; } /* CSA 24-Jul-1999; suggestion by Jean Vaucher */ else if ( !argv [ i ].startsWith ( "-" ) && i == len - 1 ) { /* use input from file. */ try { System.setIn ( new FileInputStream ( argv [ i ] ) ); } catch ( java.io.FileNotFoundException e ) { usage ( "Unable to open \"" + argv [ i ] + "\" for input" ); } } 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 PrintWriter parser_class_file; /** Output file for the symbol constant class. */ protected static PrintWriter symbol_class_file; /** Output directory. */ protected static File dest_dir = null; /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Open various files used by the system. */ protected static void open_files () { File fil; String out_name; /* open each of the output files */ /* parser class */ out_name = emit.parser_class_name + ".java"; fil = new File ( dest_dir, out_name ); try { parser_class_file = new PrintWriter ( 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 = emit.symbol_const_class_name + ".java"; fil = new File ( dest_dir, out_name ); try { symbol_class_file = new PrintWriter ( 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 */ ComplexSymbolFactory csf = new ComplexSymbolFactory (); parser_obj = new parser ( new Lexer ( csf ), csf ); 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 */ ErrorManager.getManager ().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 ) { ErrorManager.getManager ().emit_warning ( "Terminal \"" + term.name () + "\" was declared but never used" ); } } } /* 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 ) { ErrorManager.getManager () .emit_warning ( "Non terminal \"" + nt.name () + "\" was declared but never used" ); } } } } /* . . . . . . . . . . . . . . . . . . . . . . . . . */ /* . . 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 lst = ( lalr_state ) st.nextElement (); lst.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 ) { ErrorManager.getManager ().emit_error ( "*** More conflicts encountered than expected " + "-- parser generation aborted" ); // indicate the problem. // we'll die on return, after clean up. } } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** 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, sym_interface ); emit.parser ( parser_class_file, action_table, reduce_table, start_state .index (), emit.start_production, opt_compact_red, suppress_scanner ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * 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 ( " " + ErrorManager.getManager ().getErrorCount () + " error" + plural ( ErrorManager.getManager ().getErrorCount () ) + " and " + ErrorManager.getManager ().getWarningCount () + " warning" + plural ( ErrorManager.getManager ().getWarningCount () ) ); /* 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 { System.err.println ( "===== Terminals =====" ); for ( int tidx = 0, cnt = 0 ; tidx < terminal.number () ; tidx++ , cnt++ ) { System.err.print ( "[" + tidx + "]" + terminal.find ( tidx ).name () + " " ); if ( ( cnt + 1 ) % 5 == 0 ) System.err.println (); } System.err.println (); System.err.println (); System.err.println ( "===== Non terminals =====" ); for ( int nidx = 0, cnt = 0 ; nidx < non_terminal.number () ; nidx++ , cnt++ ) { System.err.print ( "[" + nidx + "]" + non_terminal.find ( nidx ).name () + " " ); if ( ( cnt + 1 ) % 5 == 0 ) System.err.println (); } System.err.println (); System.err.println (); System.err.println ( "===== Productions =====" ); for ( int pidx = 0 ; pidx < production.number () ; pidx++ ) { production prod = production.find ( pidx ); System.err.print ( "[" + pidx + "] " + 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 ); } /*-----------------------------------------------------------*/ }