Home | History | Annotate | Download | only in java_cup
      1 
      2 package java_cup;
      3 
      4 import java.io.BufferedInputStream;
      5 import java.io.BufferedOutputStream;
      6 import java.io.File;
      7 import java.io.FileInputStream;
      8 import java.io.FileOutputStream;
      9 import java.io.PrintStream;
     10 import java.util.Enumeration;
     11 
     12 /** This class serves as the main driver for the JavaCup system.
     13  *  It accepts user options and coordinates overall control flow.
     14  *  The main flow of control includes the following activities:
     15  *  <ul>
     16  *    <li> Parse user supplied arguments and options.
     17  *    <li> Open output files.
     18  *    <li> Parse the specification from standard input.
     19  *    <li> Check for unused terminals, non-terminals, and productions.
     20  *    <li> Build the state machine, tables, etc.
     21  *    <li> Output the generated code.
     22  *    <li> Close output files.
     23  *    <li> Print a summary if requested.
     24  *  </ul>
     25  *
     26  *  Options to the main program include: <dl>
     27  *   <dt> -package name
     28  *   <dd> specify package generated classes go in [default none]
     29  *   <dt> -parser name
     30  *   <dd> specify parser class name [default "parser"]
     31  *   <dt> -symbols name
     32  *   <dd> specify name for symbol constant class [default "sym"]
     33  *   <dt> -nonterms
     34  *   <dd> put non terminals in symbol constant class
     35  *   <dt> -expect #
     36  *   <dd> number of conflicts expected/allowed [default 0]
     37  *   <dt> -compact_red
     38  *   <dd> compact tables by defaulting to most frequent reduce
     39  *   <dt> -nowarn
     40  *   <dd> don't warn about useless productions, etc.
     41  *   <dt> -nosummary
     42  *   <dd> don't print the usual summary of parse states, etc.
     43  *   <dt> -progress
     44  *   <dd> print messages to indicate progress of the system
     45  *   <dt> -time
     46  *   <dd> print time usage summary
     47  *   <dt> -dump_grammar
     48  *   <dd> produce a dump of the symbols and grammar
     49  *   <dt> -dump_states
     50  *   <dd> produce a dump of parse state machine
     51  *   <dt> -dump_tables
     52  *   <dd> produce a dump of the parse tables
     53  *   <dt> -dump
     54  *   <dd> produce a dump of all of the above
     55  *   <dt> -debug
     56  *   <dd> turn on debugging messages within JavaCup
     57  *   </dl>
     58  *
     59  * @version last updated: 11/25/95
     60  * @author  Scott Hudson
     61  */
     62 
     63 public class Main {
     64 
     65   /*-----------------------------------------------------------*/
     66   /*--- Constructor(s) ----------------------------------------*/
     67   /*-----------------------------------------------------------*/
     68   /** Only constructor is private, so we do not allocate any instances of this
     69       class. */
     70   private Main() { }
     71 
     72   /*-------------------------*/
     73   /* Options set by the user */
     74   /*-------------------------*/
     75   /** User option -- do we print progress messages. */
     76   protected static boolean print_progress   = false;
     77   /** User option -- do we produce a dump of the state machine */
     78   protected static boolean opt_dump_states  = false;
     79   /** User option -- do we produce a dump of the parse tables */
     80   protected static boolean opt_dump_tables  = false;
     81   /** User option -- do we produce a dump of the grammar */
     82   protected static boolean opt_dump_grammar = false;
     83   /** User option -- do we show timing information as a part of the summary */
     84   protected static boolean opt_show_timing  = false;
     85   /** User option -- do we run produce extra debugging messages */
     86   protected static boolean opt_do_debug     = false;
     87   /** User option -- do we compact tables by making most common reduce the
     88       default action */
     89   protected static boolean opt_compact_red  = false;
     90   /** User option -- should we include non terminal symbol numbers in the
     91       symbol constant class. */
     92   protected static boolean include_non_terms = false;
     93   /** User option -- do not print a summary. */
     94   protected static boolean no_summary = false;
     95   /** User option -- number of conflicts to expect */
     96   protected static int expect_conflicts = 0;
     97 
     98   /*----------------------------------------------------------------------*/
     99   /* Timing data (not all of these time intervals are mutually exclusive) */
    100   /*----------------------------------------------------------------------*/
    101   /** Timing data -- when did we start */
    102   protected static long start_time       = 0;
    103   /** Timing data -- when did we end preliminaries */
    104   protected static long prelim_end       = 0;
    105   /** Timing data -- when did we end parsing */
    106   protected static long parse_end        = 0;
    107   /** Timing data -- when did we end checking */
    108   protected static long check_end        = 0;
    109   /** Timing data -- when did we end dumping */
    110   protected static long dump_end         = 0;
    111   /** Timing data -- when did we end state and table building */
    112   protected static long build_end        = 0;
    113   /** Timing data -- when did we end nullability calculation */
    114   protected static long nullability_end  = 0;
    115   /** Timing data -- when did we end first set calculation */
    116   protected static long first_end        = 0;
    117   /** Timing data -- when did we end state machine construction */
    118   protected static long machine_end      = 0;
    119   /** Timing data -- when did we end table construction */
    120   protected static long table_end        = 0;
    121   /** Timing data -- when did we end checking for non-reduced productions */
    122   protected static long reduce_check_end = 0;
    123   /** Timing data -- when did we finish emitting code */
    124   protected static long emit_end         = 0;
    125   /** Timing data -- when were we completely done */
    126   protected static long final_time       = 0;
    127 
    128   /* Additional timing information is also collected in emit */
    129 
    130   /** Path to create output files */
    131   private static String out_path = null;
    132 
    133   /*-----------------------------------------------------------*/
    134   /*--- Main Program ------------------------------------------*/
    135   /*-----------------------------------------------------------*/
    136 
    137   /** The main driver for the system.
    138    * @param argv an array of strings containing command line arguments.
    139    */
    140   public static void main(String argv[])
    141     throws internal_error, java.io.IOException, java.lang.Exception
    142     {
    143       boolean did_output = false;
    144 
    145       start_time = System.currentTimeMillis();
    146 
    147       /* process user options and arguments */
    148       parse_args(argv);
    149 
    150       /* open output files */
    151       if (print_progress) System.err.println("Opening files...");
    152       open_files();
    153 
    154       prelim_end = System.currentTimeMillis();
    155 
    156       /* parse spec into internal data structures */
    157       if (print_progress)
    158     System.err.println("Parsing specification from standard input...");
    159       parse_grammar_spec();
    160 
    161       parse_end = System.currentTimeMillis();
    162 
    163       /* don't proceed unless we are error free */
    164       if (lexer.error_count == 0)
    165     {
    166       /* check for unused bits */
    167           if (print_progress) System.err.println("Checking specification...");
    168           check_unused();
    169 
    170           check_end = System.currentTimeMillis();
    171 
    172       /* build the state machine and parse tables */
    173           if (print_progress) System.err.println("Building parse tables...");
    174           build_parser();
    175 
    176           build_end = System.currentTimeMillis();
    177 
    178       /* output the generated code */
    179           if (print_progress) System.err.println("Writing parser...");
    180           emit_parser();
    181       did_output = true;
    182 
    183           emit_end = System.currentTimeMillis();
    184     }
    185       else
    186     {
    187       /* fix up the times to make the summary easier */
    188       emit_end = parse_end;
    189     }
    190 
    191       /* do requested dumps */
    192       if (opt_dump_grammar) dump_grammar();
    193       if (opt_dump_states)  dump_machine();
    194       if (opt_dump_tables)  dump_tables();
    195 
    196       dump_end = System.currentTimeMillis();
    197 
    198       /* close output files */
    199       if (print_progress) System.err.println("Closing files...");
    200       close_files();
    201 
    202       /* produce a summary if desired */
    203       if (!no_summary) emit_summary(did_output);
    204     }
    205 
    206   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    207 
    208   /** Print a "usage message" that described possible command line options,
    209    *  then exit.
    210    * @param message a specific error message to preface the usage message by.
    211    */
    212   protected static void usage(String message)
    213     {
    214       System.err.println();
    215       System.err.println(message);
    216       System.err.println();
    217       System.err.println(
    218 "Usage: " + version.program_name + " [options]\n" +
    219 "  and expects a specification file on standard input.\n" +
    220 "  Legal options include:\n" +
    221 "    -out path      specify the output files path [default current directory]\n" +
    222 "    -package name  specify package generated classes go in [default none]\n" +
    223 "    -parser name   specify parser class name [default \"parser\"]\n" +
    224 "    -symbols name  specify name for symbol constant class [default \"sym\"]\n"+
    225 "    -nonterms      put non terminals in symbol constant class\n" +
    226 "    -expect #      number of conflicts expected/allowed [default 0]\n" +
    227 "    -compact_red   compact tables by defaulting to most frequent reduce\n" +
    228 "    -nowarn        don't warn about useless productions, etc.\n" +
    229 "    -nosummary     don't print the usual summary of parse states, etc.\n" +
    230 "    -progress      print messages to indicate progress of the system\n" +
    231 "    -time          print time usage summary\n" +
    232 "    -dump_grammar  produce a human readable dump of the symbols and grammar\n"+
    233 "    -dump_states   produce a dump of parse state machine\n"+
    234 "    -dump_tables   produce a dump of the parse tables\n"+
    235 "    -dump          produce a dump of all of the above\n"
    236       );
    237       System.exit(1);
    238     }
    239 
    240   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    241 
    242   /** Parse command line options and arguments to set various user-option
    243    *  flags and variables.
    244    * @param argv the command line arguments to be parsed.
    245    */
    246   protected static void parse_args(String argv[])
    247     {
    248       int len = argv.length;
    249       int i;
    250 
    251       /* parse the options */
    252       for (i=0; i<len; i++)
    253     {
    254       /* try to get the various options */
    255       if (argv[i].equals("-package"))
    256         {
    257           /* must have an arg */
    258           if (++i >= len || argv[i].startsWith("-") ||
    259                 argv[i].endsWith(".cup"))
    260         usage("-package must have a name argument");
    261 
    262           /* record the name */
    263           emit.package_name = argv[i];
    264         }
    265       else if (argv[i].equals("-parser"))
    266         {
    267           /* must have an arg */
    268           if (++i >= len || argv[i].startsWith("-") ||
    269                 argv[i].endsWith(".cup"))
    270         usage("-parser must have a name argument");
    271 
    272           /* record the name */
    273           emit.parser_class_name = argv[i];
    274         }
    275       else if (argv[i].equals("-input")) {
    276           /* must have an arg */
    277           if (++i >= len || argv[i].startsWith("-") ||
    278               argv[i].endsWith(".cup"))
    279               usage("-input must have a name argument");
    280 
    281           /* record the name */
    282           emit.input_file_name = argv[i];
    283       }
    284       else if (argv[i].equals("-symbols"))
    285         {
    286           /* must have an arg */
    287           if (++i >= len || argv[i].startsWith("-") ||
    288                 argv[i].endsWith(".cup"))
    289         usage("-symbols must have a name argument");
    290 
    291           /* record the name */
    292           emit.symbol_const_class_name = argv[i];
    293         }
    294       else if (argv[i].equals("-nonterms"))
    295         {
    296           include_non_terms = true;
    297         }
    298       else if (argv[i].equals("-expect"))
    299         {
    300           /* must have an arg */
    301           if (++i >= len || argv[i].startsWith("-") ||
    302                 argv[i].endsWith(".cup"))
    303         usage("-expect must have a name argument");
    304 
    305           /* record the number */
    306           try {
    307             expect_conflicts = Integer.parseInt(argv[i]);
    308           } catch (NumberFormatException e) {
    309         usage("-expect must be followed by a decimal integer");
    310           }
    311         }
    312           else if (argv[i].equals("-out"))
    313         {
    314           /* must have an arg */
    315               if (++i >= len || argv[i].startsWith("-"))
    316                 usage("-out must have a path argument");
    317 
    318               /* validate path */
    319               if (argv[i].length() != 0) {
    320                 out_path = argv[i] + File.separator;
    321                 File f = new File(out_path);
    322                 if (!f.exists() || !f.isDirectory())
    323                   out_path = null;
    324           }
    325               if (out_path == null)
    326                 usage("-out argument must be a valid existing path");
    327         }
    328       else if (argv[i].equals("-compact_red"))  opt_compact_red = true;
    329       else if (argv[i].equals("-nosummary"))    no_summary = true;
    330       else if (argv[i].equals("-nowarn"))       emit.nowarn = true;
    331       else if (argv[i].equals("-dump_states"))  opt_dump_states = true;
    332       else if (argv[i].equals("-dump_tables"))  opt_dump_tables = true;
    333       else if (argv[i].equals("-progress"))     print_progress = true;
    334       else if (argv[i].equals("-dump_grammar")) opt_dump_grammar = true;
    335       else if (argv[i].equals("-dump"))
    336             opt_dump_states = opt_dump_tables = opt_dump_grammar = true;
    337       else if (argv[i].equals("-time"))         opt_show_timing = true;
    338       else if (argv[i].equals("-debug"))        opt_do_debug = true;
    339       else
    340         {
    341           usage("Unrecognized option \"" + argv[i] + "\"");
    342         }
    343     }
    344     }
    345 
    346   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    347 
    348   /*-------*/
    349   /* Files */
    350   /*-------*/
    351 
    352   /** Input file.  This is a buffered version of System.in. */
    353   protected static BufferedInputStream input_file;
    354 
    355   /** Output file for the parser class. */
    356   protected static PrintStream parser_class_file;
    357 
    358   /** Output file for the symbol constant class. */
    359   protected static PrintStream symbol_class_file;
    360 
    361   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    362 
    363   /** Open various files used by the system. */
    364   protected static void open_files()
    365     {
    366       File fil;
    367       String out_name;
    368 
    369       /* use a buffered version of standard input */
    370         if (emit.input_file_name != null)
    371             try {
    372                 input_file = new BufferedInputStream(new FileInputStream(emit.input_file_name));
    373             } catch (Exception ex) {
    374                 ex.printStackTrace();
    375                 System.exit(3);
    376             }
    377         else
    378             input_file = new BufferedInputStream(System.in);
    379 
    380       /* open each of the output files */
    381       if (out_path == null)
    382         out_path = "";
    383 
    384       /* parser class */
    385       out_name = out_path + emit.parser_class_name + ".java";
    386       fil = new File(out_name);
    387       try {
    388         parser_class_file = new PrintStream(
    389          new BufferedOutputStream(new FileOutputStream(fil), 4096));
    390       } catch(Exception e) {
    391     System.err.println("Can't open \"" + out_name + "\" for output");
    392     System.exit(3);
    393       }
    394 
    395       /* symbol constants class */
    396       out_name = out_path + emit.symbol_const_class_name + ".java";
    397       fil = new File(out_name);
    398       try {
    399         symbol_class_file = new PrintStream(
    400          new BufferedOutputStream(new FileOutputStream(fil), 4096));
    401       } catch(Exception e) {
    402     System.err.println("Can't open \"" + out_name + "\" for output");
    403     System.exit(4);
    404       }
    405     }
    406 
    407   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    408 
    409   /** Close various files used by the system. */
    410   protected static void close_files() throws java.io.IOException
    411     {
    412       if (input_file != null) input_file.close();
    413       if (parser_class_file != null) parser_class_file.close();
    414       if (symbol_class_file != null) symbol_class_file.close();
    415     }
    416 
    417   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    418 
    419   /** Parse the grammar specification from standard input.  This produces
    420    *  sets of terminal, non-terminals, and productions which can be accessed
    421    *  via static variables of the respective classes, as well as the setting
    422    *  of various variables (mostly in the emit class) for small user supplied
    423    *  items such as the code to scan with.
    424    */
    425   protected static void parse_grammar_spec() throws java.lang.Exception
    426     {
    427       parser parser_obj;
    428 
    429       /* create a parser and parse with it */
    430       parser_obj = new parser();
    431       try {
    432     if (opt_do_debug)
    433           parser_obj.debug_parse();
    434     else
    435           parser_obj.parse();
    436       } catch (Exception e)
    437       {
    438     /* something threw an exception.  catch it and emit a message so we
    439        have a line number to work with, then re-throw it */
    440     lexer.emit_error("Internal error: Unexpected exception");
    441     throw e;
    442       }
    443     }
    444 
    445   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    446 
    447   /** Check for unused symbols.  Unreduced productions get checked when
    448    *  tables are created.
    449    */
    450   protected static void check_unused()
    451     {
    452       terminal term;
    453       non_terminal nt;
    454 
    455       /* check for unused terminals */
    456       for (Enumeration t = terminal.all(); t.hasMoreElements(); )
    457     {
    458       term = (terminal)t.nextElement();
    459 
    460       /* don't issue a message for EOF */
    461       if (term == terminal.EOF) continue;
    462 
    463       /* or error */
    464       if (term == terminal.error) continue;
    465 
    466       /* is this one unused */
    467       if (term.use_count() == 0)
    468         {
    469           /* count it and warn if we are doing warnings */
    470           emit.unused_term++;
    471           if (!emit.nowarn)
    472         {
    473           System.err.println("Warning: Terminal \"" + term.name() +
    474                      "\" was declared but never used");
    475           lexer.warning_count++;
    476         }
    477         }
    478     }
    479 
    480       /* check for unused non terminals */
    481       for (Enumeration n = non_terminal.all(); n.hasMoreElements(); )
    482     {
    483       nt = (non_terminal)n.nextElement();
    484 
    485       /* is this one unused */
    486       if (nt.use_count() == 0)
    487         {
    488           /* count and warn if we are doing warnings */
    489           emit.unused_term++;
    490           if (!emit.nowarn)
    491         {
    492           System.err.println("Warning: Non terminal \"" + nt.name() +
    493                      "\" was declared but never used");
    494           lexer.warning_count++;
    495         }
    496         }
    497     }
    498 
    499     }
    500 
    501   /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
    502   /* . . Internal Results of Generating the Parser . .*/
    503   /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
    504 
    505   /** Start state in the overall state machine. */
    506   protected static lalr_state start_state;
    507 
    508   /** Resulting parse action table. */
    509   protected static parse_action_table action_table;
    510 
    511   /** Resulting reduce-goto table. */
    512   protected static parse_reduce_table reduce_table;
    513 
    514   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    515 
    516   /** Build the (internal) parser from the previously parsed specification.
    517    *  This includes:<ul>
    518    *    <li> Computing nullability of non-terminals.
    519    *    <li> Computing first sets of non-terminals and productions.
    520    *    <li> Building the viable prefix recognizer machine.
    521    *    <li> Filling in the (internal) parse tables.
    522    *    <li> Checking for unreduced productions.
    523    *  </ul>
    524    */
    525   protected static void build_parser() throws internal_error
    526     {
    527       /* compute nullability of all non terminals */
    528       if (opt_do_debug || print_progress)
    529     System.err.println("  Computing non-terminal nullability...");
    530       non_terminal.compute_nullability();
    531 
    532       nullability_end = System.currentTimeMillis();
    533 
    534       /* compute first sets of all non terminals */
    535       if (opt_do_debug || print_progress)
    536     System.err.println("  Computing first sets...");
    537       non_terminal.compute_first_sets();
    538 
    539       first_end = System.currentTimeMillis();
    540 
    541       /* build the LR viable prefix recognition machine */
    542       if (opt_do_debug || print_progress)
    543     System.err.println("  Building state machine...");
    544       start_state = lalr_state.build_machine(emit.start_production);
    545 
    546       machine_end = System.currentTimeMillis();
    547 
    548       /* build the LR parser action and reduce-goto tables */
    549       if (opt_do_debug || print_progress)
    550     System.err.println("  Filling in tables...");
    551       action_table = new parse_action_table();
    552       reduce_table = new parse_reduce_table();
    553       for (Enumeration st = lalr_state.all(); st.hasMoreElements(); )
    554     {
    555       ((lalr_state)st.nextElement()).build_table_entries(
    556                                   action_table, reduce_table);
    557     }
    558 
    559       table_end = System.currentTimeMillis();
    560 
    561       /* check and warn for non-reduced productions */
    562       if (opt_do_debug || print_progress)
    563     System.err.println("  Checking for non-reduced productions...");
    564       action_table.check_reductions();
    565 
    566       reduce_check_end = System.currentTimeMillis();
    567 
    568       /* if we have more conflicts than we expected issue a message and die */
    569       if (emit.num_conflicts > expect_conflicts)
    570     {
    571       System.err.println("*** More conflicts encountered than expected " +
    572                  "-- parser generation aborted");
    573       lexer.error_count++;
    574       build_end = System.currentTimeMillis();
    575 
    576       /* do dumps and summary as needed */
    577           if (opt_dump_grammar) dump_grammar();
    578           if (opt_dump_states)  dump_machine();
    579       if (!no_summary) emit_summary(false);
    580 
    581       System.exit(100);
    582     }
    583     }
    584 
    585   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    586 
    587   /** Call the emit routines necessary to write out the generated parser. */
    588   protected static void emit_parser() throws internal_error
    589     {
    590       emit.symbols(symbol_class_file, include_non_terms);
    591       emit.parser(parser_class_file, action_table, reduce_table,
    592           start_state.index(), emit.start_production, opt_compact_red);
    593     }
    594 
    595   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    596 
    597   /** Helper routine to optionally return a plural or non-plural ending.
    598    * @param val the numerical value determining plurality.
    599    */
    600   protected static String plural(int val)
    601     {
    602       if (val == 1)
    603     return "";
    604       else
    605     return "s";
    606     }
    607 
    608   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    609 
    610   /** Emit a long summary message to standard error (System.err) which
    611    *  summarizes what was found in the specification, how many states were
    612    *  produced, how many conflicts were found, etc.  A detailed timing
    613    *  summary is also produced if it was requested by the user.
    614    * @param output_produced did the system get far enough to generate code.
    615    */
    616   protected static void emit_summary(boolean output_produced)
    617     {
    618       final_time = System.currentTimeMillis();
    619 
    620       if (no_summary) return;
    621 
    622       System.err.println("------- " + version.title_str +
    623              " Parser Generation Summary -------");
    624 
    625       /* error and warning count */
    626       System.err.println("  " + lexer.error_count + " error" +
    627      plural(lexer.error_count) + " and " + lexer.warning_count +
    628      " warning" + plural(lexer.warning_count));
    629 
    630       /* basic stats */
    631       System.err.print("  " + terminal.number() + " terminal" +
    632              plural(terminal.number()) + ", ");
    633       System.err.print(non_terminal.number() + " non terminal" +
    634              plural(non_terminal.number()) + ", and ");
    635       System.err.println(production.number() + " production" +
    636              plural(production.number()) + " declared, ");
    637       System.err.println("  producing " + lalr_state.number() +
    638              " unique parse states.");
    639 
    640       /* unused symbols */
    641       System.err.println("  " + emit.unused_term + " terminal" +
    642              plural(emit.unused_term) + " declared but not used.");
    643       System.err.println("  " + emit.unused_non_term + " non terminal" +
    644              plural(emit.unused_term) + " declared but not used.");
    645 
    646       /* productions that didn't reduce */
    647       System.err.println("  " + emit.not_reduced + " production" +
    648              plural(emit.not_reduced) + " never reduced.");
    649 
    650       /* conflicts */
    651       System.err.println("  " + emit.num_conflicts + " conflict" +
    652              plural(emit.num_conflicts) + " detected" +
    653                      " (" + expect_conflicts + " expected).");
    654 
    655       /* code location */
    656       if (output_produced)
    657     System.err.println("  Code written to \"" + emit.parser_class_name +
    658             ".java\", and \"" + emit.symbol_const_class_name + ".java\".");
    659       else
    660     System.err.println("  No code produced.");
    661 
    662       if (opt_show_timing) show_times();
    663 
    664       System.err.println(
    665     "---------------------------------------------------- (" +
    666      version.version_str + ")");
    667     }
    668 
    669   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    670 
    671   /** Produce the optional timing summary as part of an overall summary. */
    672   protected static void show_times()
    673     {
    674       long total_time = final_time - start_time;
    675 
    676       System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . ");
    677       System.err.println("  Timing Summary");
    678       System.err.println("    Total time       "
    679         + timestr(final_time-start_time, total_time));
    680       System.err.println("      Startup        "
    681     + timestr(prelim_end-start_time, total_time));
    682       System.err.println("      Parse          "
    683     + timestr(parse_end-prelim_end, total_time) );
    684       if (check_end != 0)
    685         System.err.println("      Checking       "
    686         + timestr(check_end-parse_end, total_time));
    687       if (check_end != 0 && build_end != 0)
    688         System.err.println("      Parser Build   "
    689         + timestr(build_end-check_end, total_time));
    690       if (nullability_end != 0 && check_end != 0)
    691         System.err.println("        Nullability  "
    692         + timestr(nullability_end-check_end, total_time));
    693       if (first_end != 0 && nullability_end != 0)
    694         System.err.println("        First sets   "
    695             + timestr(first_end-nullability_end, total_time));
    696       if (machine_end != 0 && first_end != 0)
    697         System.err.println("        State build  "
    698         + timestr(machine_end-first_end, total_time));
    699       if (table_end != 0 && machine_end != 0)
    700         System.err.println("        Table build  "
    701         + timestr(table_end-machine_end, total_time));
    702       if (reduce_check_end != 0 && table_end != 0)
    703         System.err.println("        Checking     "
    704         + timestr(reduce_check_end-table_end, total_time));
    705       if (emit_end != 0 && build_end != 0)
    706         System.err.println("      Code Output    "
    707         + timestr(emit_end-build_end, total_time));
    708       if (emit.symbols_time != 0)
    709     System.err.println("        Symbols      "
    710         + timestr(emit.symbols_time, total_time));
    711       if (emit.parser_time != 0)
    712     System.err.println("        Parser class "
    713         + timestr(emit.parser_time, total_time));
    714       if (emit.action_code_time != 0)
    715     System.err.println("          Actions    "
    716         + timestr(emit.action_code_time, total_time));
    717       if (emit.production_table_time != 0)
    718     System.err.println("          Prod table "
    719         + timestr(emit.production_table_time, total_time));
    720       if (emit.action_table_time != 0)
    721     System.err.println("          Action tab "
    722         + timestr(emit.action_table_time, total_time));
    723       if (emit.goto_table_time != 0)
    724     System.err.println("          Reduce tab "
    725         + timestr(emit.goto_table_time, total_time));
    726 
    727       System.err.println("      Dump Output    "
    728     + timestr(dump_end-emit_end, total_time));
    729     }
    730 
    731   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    732 
    733   /** Helper routine to format a decimal based display of seconds and
    734    *  percentage of total time given counts of milliseconds.   Note: this
    735    *  is broken for use with some instances of negative time (since we don't
    736    *  use any negative time here, we let if be for now).
    737    * @param time_val   the value being formatted (in ms).
    738    * @param total_time total time percentages are calculated against (in ms).
    739    */
    740   protected static String timestr(long time_val, long total_time)
    741     {
    742       boolean neg;
    743       long    ms = 0;
    744       long    sec = 0;
    745       long    percent10;
    746       String  pad;
    747 
    748       /* work with positives only */
    749       neg = time_val < 0;
    750       if (neg) time_val = -time_val;
    751 
    752       /* pull out seconds and ms */
    753       ms = time_val % 1000;
    754       sec = time_val / 1000;
    755 
    756       /* construct a pad to blank fill seconds out to 4 places */
    757       if (sec < 10)
    758     pad = "   ";
    759       else if (sec < 100)
    760     pad = "  ";
    761       else if (sec < 1000)
    762     pad = " ";
    763       else
    764     pad = "";
    765 
    766       /* calculate 10 times the percentage of total */
    767       percent10 = (time_val*1000)/total_time;
    768 
    769       /* build and return the output string */
    770       return (neg ? "-" : "") + pad + sec + "." +
    771          ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" +
    772          " (" + percent10/10 + "." + percent10%10 + "%)";
    773     }
    774 
    775   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    776 
    777   /** Produce a human readable dump of the grammar. */
    778   public static void dump_grammar() throws internal_error
    779     {
    780       int cnt;
    781       Enumeration t, n, p;
    782       production prod;
    783 
    784       System.err.println("===== Terminals =====");
    785       for (t = terminal.all(), cnt=0; t.hasMoreElements(); cnt++)
    786     {
    787       System.err.print(((terminal)t.nextElement()).name() + " ");
    788       if ((cnt+1) % 5 == 0) System.err.println();
    789     }
    790       System.err.println();
    791       System.err.println();
    792 
    793       System.err.println("===== Non terminals =====");
    794       for (n=non_terminal.all(), cnt=0; n.hasMoreElements(); cnt++)
    795     {
    796       System.err.print(((non_terminal)n.nextElement()).name() + " ");
    797       if ((cnt+1) % 5 == 0) System.err.println();
    798     }
    799       System.err.println();
    800       System.err.println();
    801 
    802 
    803       System.err.println("===== Productions =====");
    804       for (p=production.all(); p.hasMoreElements(); )
    805     {
    806       prod = (production)p.nextElement();
    807       System.err.print(prod.lhs().the_symbol().name() + " ::= ");
    808       for (int i=0; i<prod.rhs_length(); i++)
    809         if (prod.rhs(i).is_action())
    810           System.err.print("{action} ");
    811         else
    812           System.err.print(
    813              ((symbol_part)prod.rhs(i)).the_symbol().name() + " ");
    814       System.err.println();
    815     }
    816       System.err.println();
    817     }
    818 
    819   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    820 
    821   /** Produce a (semi-) human readable dump of the complete viable prefix
    822    *  recognition state machine.
    823    */
    824   public static void dump_machine()
    825     {
    826       lalr_state ordered[] = new lalr_state[lalr_state.number()];
    827 
    828       /* put the states in sorted order for a nicer display */
    829       for (Enumeration s = lalr_state.all(); s.hasMoreElements(); )
    830     {
    831       lalr_state st = (lalr_state)s.nextElement();
    832       ordered[st.index()] = st;
    833     }
    834 
    835       System.err.println("===== Viable Prefix Recognizer =====");
    836       for (int i = 0; i<lalr_state.number(); i++)
    837     {
    838       if (ordered[i] == start_state) System.err.print("START ");
    839           System.err.println(ordered[i]);
    840       System.err.println("-------------------");
    841     }
    842     }
    843 
    844   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    845 
    846   /** Produce a (semi-) human readable dumps of the parse tables */
    847   public static void dump_tables()
    848     {
    849       System.err.println(action_table);
    850       System.err.println(reduce_table);
    851     }
    852 
    853   /*-----------------------------------------------------------*/
    854 
    855 };
    856 
    857