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 */ 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 ) ; } /*-----------------------------------------------------------*/ }