FileDocCategorySizeDatePackage
Main.javaAPI DocJava SE 5 API30454Fri Aug 26 14:54:54 BST 2005com.sun.java_cup.internal

Main

public class Main extends Object
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:
  • Parse user supplied arguments and options.
  • Open output files.
  • Parse the specification from standard input.
  • Check for unused terminals, non-terminals, and productions.
  • Build the state machine, tables, etc.
  • Output the generated code.
  • Close output files.
  • Print a summary if requested.
Options to the main program include:
-package name
specify package generated classes go in [default none]
-parser name
specify parser class name [default "parser"]
-symbols name
specify name for symbol constant class [default "sym"]
-interface
emit symbol constant interface, rather than class
-nonterms
put non terminals in symbol constant class
-expect #
number of conflicts expected/allowed [default 0]
-compact_red
compact tables by defaulting to most frequent reduce
-nowarn
don't warn about useless productions, etc.
-nosummary
don't print the usual summary of parse states, etc.
-progress
print messages to indicate progress of the system
-time
print time usage summary
-dump_grammar
produce a dump of the symbols and grammar
-dump_states
produce a dump of parse state machine
-dump_tables
produce a dump of the parse tables
-dump
produce a dump of all of the above
-debug
turn on debugging messages within JavaCup
-nopositions
don't generate the positions code
-noscanner
don't refer to com.sun.java_cup.internal.runtime.Scanner in the parser (for compatibility with old runtimes)
-version
print version information for JavaCUP and halt.
version
last updated: 7/3/96
author
Frank Flannery

Fields Summary
protected static boolean
print_progress
User option -- do we print progress messages.
protected static boolean
opt_dump_states
User option -- do we produce a dump of the state machine
protected static boolean
opt_dump_tables
User option -- do we produce a dump of the parse tables
protected static boolean
opt_dump_grammar
User option -- do we produce a dump of the grammar
protected static boolean
opt_show_timing
User option -- do we show timing information as a part of the summary
protected static boolean
opt_do_debug
User option -- do we run produce extra debugging messages
protected static boolean
opt_compact_red
User option -- do we compact tables by making most common reduce the default action
protected static boolean
include_non_terms
User option -- should we include non terminal symbol numbers in the symbol constant class.
protected static boolean
no_summary
User option -- do not print a summary.
protected static int
expect_conflicts
User option -- number of conflicts to expect
protected static boolean
lr_values
User option -- should generator generate code for left/right values?
protected static boolean
sym_interface
User option -- should symbols be put in a class or an interface? [CSA]
protected static boolean
suppress_scanner
User option -- should generator suppress references to com.sun.java_cup.internal.runtime.Scanner for compatibility with old runtimes?
protected static long
start_time
Timing data -- when did we start
protected static long
prelim_end
Timing data -- when did we end preliminaries
protected static long
parse_end
Timing data -- when did we end parsing
protected static long
check_end
Timing data -- when did we end checking
protected static long
dump_end
Timing data -- when did we end dumping
protected static long
build_end
Timing data -- when did we end state and table building
protected static long
nullability_end
Timing data -- when did we end nullability calculation
protected static long
first_end
Timing data -- when did we end first set calculation
protected static long
machine_end
Timing data -- when did we end state machine construction
protected static long
table_end
Timing data -- when did we end table construction
protected static long
reduce_check_end
Timing data -- when did we end checking for non-reduced productions
protected static long
emit_end
Timing data -- when did we finish emitting code
protected static long
final_time
Timing data -- when were we completely done
protected static BufferedInputStream
input_file
Input file. This is a buffered version of System.in.
protected static PrintWriter
parser_class_file
Output file for the parser class.
protected static PrintWriter
symbol_class_file
Output file for the symbol constant class.
protected static lalr_state
start_state
Start state in the overall state machine.
protected static parse_action_table
action_table
Resulting parse action table.
protected static parse_reduce_table
reduce_table
Resulting reduce-goto table.
Constructors Summary
private Main()
Only constructor is private, so we do not allocate any instances of this class.

 
Methods Summary
protected static voidbuild_parser()
Build the (internal) parser from the previously parsed specification. This includes:
  • Computing nullability of non-terminals.
  • Computing first sets of non-terminals and productions.
  • Building the viable prefix recognizer machine.
  • Filling in the (internal) parse tables.
  • Checking for unreduced productions.

      /* 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)
	{
	  System.err.println("*** More conflicts encountered than expected " +
			     "-- parser generation aborted");
	  lexer.error_count++; // indicate the problem.
	  // we'll die on return, after clean up.
	}
    
protected static voidcheck_unused()
Check for unused symbols. Unreduced productions get checked when tables are created.

      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++;
		}
	    }
	}

    
protected static voidclose_files()
Close various files used by the system.

      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();
    
public static voiddump_grammar()
Produce a human readable dump of the grammar.

      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();
    
public static voiddump_machine()
Produce a (semi-) human readable dump of the complete viable prefix recognition state 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("-------------------");
	}
    
public static voiddump_tables()
Produce a (semi-) human readable dumps of the parse tables

      System.err.println(action_table);
      System.err.println(reduce_table);
    
protected static voidemit_parser()
Call the emit routines necessary to write out the generated parser.

      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);
    
protected static voidemit_summary(boolean output_produced)
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.

      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 + ")");
    
public static voidmain(java.lang.String[] argv)
The main driver for the system.

param
argv an array of strings containing command line arguments.


  /* Additional timing information is also collected in emit */

  /*-----------------------------------------------------------*/
  /*--- Main Program ------------------------------------------*/
  /*-----------------------------------------------------------*/

                      
       
       
    
      boolean did_output = false;

      start_time = System.currentTimeMillis();

      /* 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 (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 # of conflicts permits */
	  if (lexer.error_count != 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 (lexer.error_count != 0)
	  System.exit(100);
    
protected static voidopen_files()
Open various files used by the system.

      File fil;
      String out_name;

      /* open each of the output files */

      /* parser class */
      out_name = emit.parser_class_name + ".java";
      fil = new File(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(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);
      }
    
protected static voidparse_args(java.lang.String[] argv)
Parse command line options and arguments to set various user-option flags and variables.

param
argv the command line arguments to be parsed.

      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("-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);
	  }
	  else
	    {
	      usage("Unrecognized option \"" + argv[i] + "\"");
	    }
	}
    
protected static voidparse_grammar_spec()
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.

      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;
      }
    
protected static java.lang.Stringplural(int val)
Helper routine to optionally return a plural or non-plural ending.

param
val the numerical value determining plurality.

      if (val == 1)
	return "";
      else
	return "s";
    
protected static voidshow_times()
Produce the optional timing summary as part of an overall summary.

      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));
    
protected static java.lang.Stringtimestr(long time_val, long 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).

      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 + "%)";
    
protected static voidusage(java.lang.String message)
Print a "usage message" that described possible command line options, then exit.

param
message a specific error message to preface the usage message by.

      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" +
"    -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"+
"    -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 com.sun.java_cup.internal.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);