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. */
Main()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    */
main(String argv[])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    */
usage(String message)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    */
parse_args(String argv[])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. */
open_files()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. */
close_files()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    */
parse_grammar_spec()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    */
check_unused()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    */
build_parser()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. */
emit_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    */
plural(int val)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    */
emit_summary(boolean output_produced)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. */
show_times()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    */
timestr(long time_val, long total_time)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