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