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