Source code: 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]\n" +
241 " and expects a specification file on standard input.\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 else
351 {
352 usage("Unrecognized option \"" + argv[i] + "\"");
353 }
354 }
355 }
356
357 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
358
359 /*-------*/
360 /* Files */
361 /*-------*/
362
363 /** Input file. This is a buffered version of System.in. */
364 protected static BufferedInputStream input_file;
365
366 /** Output file for the parser class. */
367 protected static PrintWriter parser_class_file;
368
369 /** Output file for the symbol constant class. */
370 protected static PrintWriter symbol_class_file;
371
372 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
373
374 /** Open various files used by the system. */
375 protected static void open_files()
376 {
377 File fil;
378 String out_name;
379
380 /* open each of the output files */
381
382 /* parser class */
383 out_name = emit.parser_class_name + ".java";
384 fil = new File(out_name);
385 try {
386 parser_class_file = new PrintWriter(
387 new BufferedOutputStream(new FileOutputStream(fil), 4096));
388 } catch(Exception e) {
389 System.err.println("Can't open \"" + out_name + "\" for output");
390 System.exit(3);
391 }
392
393 /* symbol constants class */
394 out_name = emit.symbol_const_class_name + ".java";
395 fil = new File(out_name);
396 try {
397 symbol_class_file = new PrintWriter(
398 new BufferedOutputStream(new FileOutputStream(fil), 4096));
399 } catch(Exception e) {
400 System.err.println("Can't open \"" + out_name + "\" for output");
401 System.exit(4);
402 }
403 }
404
405 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
406
407 /** Close various files used by the system. */
408 protected static void close_files() throws java.io.IOException
409 {
410 if (input_file != null) input_file.close();
411 if (parser_class_file != null) parser_class_file.close();
412 if (symbol_class_file != null) symbol_class_file.close();
413 }
414
415 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
416
417 /** Parse the grammar specification from standard input. This produces
418 * sets of terminal, non-terminals, and productions which can be accessed
419 * via static variables of the respective classes, as well as the setting
420 * of various variables (mostly in the emit class) for small user supplied
421 * items such as the code to scan with.
422 */
423 protected static void parse_grammar_spec() throws java.lang.Exception
424 {
425 parser parser_obj;
426
427 /* create a parser and parse with it */
428 parser_obj = new parser();
429 try {
430 if (opt_do_debug)
431 parser_obj.debug_parse();
432 else
433 parser_obj.parse();
434 } catch (Exception e)
435 {
436 /* something threw an exception. catch it and emit a message so we
437 have a line number to work with, then re-throw it */
438 lexer.emit_error("Internal error: Unexpected exception");
439 throw e;
440 }
441 }
442
443 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
444
445 /** Check for unused symbols. Unreduced productions get checked when
446 * tables are created.
447 */
448 protected static void check_unused()
449 {
450 terminal term;
451 non_terminal nt;
452
453 /* check for unused terminals */
454 for (Enumeration t = terminal.all(); t.hasMoreElements(); )
455 {
456 term = (terminal)t.nextElement();
457
458 /* don't issue a message for EOF */
459 if (term == terminal.EOF) continue;
460
461 /* or error */
462 if (term == terminal.error) continue;
463
464 /* is this one unused */
465 if (term.use_count() == 0)
466 {
467 /* count it and warn if we are doing warnings */
468 emit.unused_term++;
469 if (!emit.nowarn)
470 {
471 System.err.println("Warning: Terminal \"" + term.name() +
472 "\" was declared but never used");
473 lexer.warning_count++;
474 }
475 }
476 }
477
478 /* check for unused non terminals */
479 for (Enumeration n = non_terminal.all(); n.hasMoreElements(); )
480 {
481 nt = (non_terminal)n.nextElement();
482
483 /* is this one unused */
484 if (nt.use_count() == 0)
485 {
486 /* count and warn if we are doing warnings */
487 emit.unused_term++;
488 if (!emit.nowarn)
489 {
490 System.err.println("Warning: Non terminal \"" + nt.name() +
491 "\" was declared but never used");
492 lexer.warning_count++;
493 }
494 }
495 }
496
497 }
498
499 /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
500 /* . . Internal Results of Generating the Parser . .*/
501 /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
502
503 /** Start state in the overall state machine. */
504 protected static lalr_state start_state;
505
506 /** Resulting parse action table. */
507 protected static parse_action_table action_table;
508
509 /** Resulting reduce-goto table. */
510 protected static parse_reduce_table reduce_table;
511
512 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
513
514 /** Build the (internal) parser from the previously parsed specification.
515 * This includes:<ul>
516 * <li> Computing nullability of non-terminals.
517 * <li> Computing first sets of non-terminals and productions.
518 * <li> Building the viable prefix recognizer machine.
519 * <li> Filling in the (internal) parse tables.
520 * <li> Checking for unreduced productions.
521 * </ul>
522 */
523 protected static void build_parser() throws internal_error
524 {
525 /* compute nullability of all non terminals */
526 if (opt_do_debug || print_progress)
527 System.err.println(" Computing non-terminal nullability...");
528 non_terminal.compute_nullability();
529
530 nullability_end = System.currentTimeMillis();
531
532 /* compute first sets of all non terminals */
533 if (opt_do_debug || print_progress)
534 System.err.println(" Computing first sets...");
535 non_terminal.compute_first_sets();
536
537 first_end = System.currentTimeMillis();
538
539 /* build the LR viable prefix recognition machine */
540 if (opt_do_debug || print_progress)
541 System.err.println(" Building state machine...");
542 start_state = lalr_state.build_machine(emit.start_production);
543
544 machine_end = System.currentTimeMillis();
545
546 /* build the LR parser action and reduce-goto tables */
547 if (opt_do_debug || print_progress)
548 System.err.println(" Filling in tables...");
549 action_table = new parse_action_table();
550 reduce_table = new parse_reduce_table();
551 for (Enumeration st = lalr_state.all(); st.hasMoreElements(); )
552 {
553 lalr_state lst = (lalr_state)st.nextElement();
554 lst.build_table_entries(
555 action_table, reduce_table);
556 }
557
558 table_end = System.currentTimeMillis();
559
560 /* check and warn for non-reduced productions */
561 if (opt_do_debug || print_progress)
562 System.err.println(" Checking for non-reduced productions...");
563 action_table.check_reductions();
564
565 reduce_check_end = System.currentTimeMillis();
566
567 /* if we have more conflicts than we expected issue a message and die */
568 if (emit.num_conflicts > expect_conflicts)
569 {
570 System.err.println("*** More conflicts encountered than expected " +
571 "-- parser generation aborted");
572 lexer.error_count++; // indicate the problem.
573 // we'll die on return, after clean up.
574 }
575 }
576
577 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
578
579 /** Call the emit routines necessary to write out the generated parser. */
580 protected static void emit_parser() throws internal_error
581 {
582 emit.symbols(symbol_class_file, include_non_terms, sym_interface);
583 emit.parser(parser_class_file, action_table, reduce_table,
584 start_state.index(), emit.start_production, opt_compact_red,
585 suppress_scanner);
586 }
587
588 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
589
590 /** Helper routine to optionally return a plural or non-plural ending.
591 * @param val the numerical value determining plurality.
592 */
593 protected static String plural(int val)
594 {
595 if (val == 1)
596 return "";
597 else
598 return "s";
599 }
600
601 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
602
603 /** Emit a long summary message to standard error (System.err) which
604 * summarizes what was found in the specification, how many states were
605 * produced, how many conflicts were found, etc. A detailed timing
606 * summary is also produced if it was requested by the user.
607 * @param output_produced did the system get far enough to generate code.
608 */
609 protected static void emit_summary(boolean output_produced)
610 {
611 final_time = System.currentTimeMillis();
612
613 if (no_summary) return;
614
615 System.err.println("------- " + version.title_str +
616 " Parser Generation Summary -------");
617
618 /* error and warning count */
619 System.err.println(" " + lexer.error_count + " error" +
620 plural(lexer.error_count) + " and " + lexer.warning_count +
621 " warning" + plural(lexer.warning_count));
622
623 /* basic stats */
624 System.err.print(" " + terminal.number() + " terminal" +
625 plural(terminal.number()) + ", ");
626 System.err.print(non_terminal.number() + " non-terminal" +
627 plural(non_terminal.number()) + ", and ");
628 System.err.println(production.number() + " production" +
629 plural(production.number()) + " declared, ");
630 System.err.println(" producing " + lalr_state.number() +
631 " unique parse states.");
632
633 /* unused symbols */
634 System.err.println(" " + emit.unused_term + " terminal" +
635 plural(emit.unused_term) + " declared but not used.");
636 System.err.println(" " + emit.unused_non_term + " non-terminal" +
637 plural(emit.unused_term) + " declared but not used.");
638
639 /* productions that didn't reduce */
640 System.err.println(" " + emit.not_reduced + " production" +
641 plural(emit.not_reduced) + " never reduced.");
642
643 /* conflicts */
644 System.err.println(" " + emit.num_conflicts + " conflict" +
645 plural(emit.num_conflicts) + " detected" +
646 " (" + expect_conflicts + " expected).");
647
648 /* code location */
649 if (output_produced)
650 System.err.println(" Code written to \"" + emit.parser_class_name +
651 ".java\", and \"" + emit.symbol_const_class_name + ".java\".");
652 else
653 System.err.println(" No code produced.");
654
655 if (opt_show_timing) show_times();
656
657 System.err.println(
658 "---------------------------------------------------- (" +
659 version.version_str + ")");
660 }
661
662 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
663
664 /** Produce the optional timing summary as part of an overall summary. */
665 protected static void show_times()
666 {
667 long total_time = final_time - start_time;
668
669 System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . ");
670 System.err.println(" Timing Summary");
671 System.err.println(" Total time "
672 + timestr(final_time-start_time, total_time));
673 System.err.println(" Startup "
674 + timestr(prelim_end-start_time, total_time));
675 System.err.println(" Parse "
676 + timestr(parse_end-prelim_end, total_time) );
677 if (check_end != 0)
678 System.err.println(" Checking "
679 + timestr(check_end-parse_end, total_time));
680 if (check_end != 0 && build_end != 0)
681 System.err.println(" Parser Build "
682 + timestr(build_end-check_end, total_time));
683 if (nullability_end != 0 && check_end != 0)
684 System.err.println(" Nullability "
685 + timestr(nullability_end-check_end, total_time));
686 if (first_end != 0 && nullability_end != 0)
687 System.err.println(" First sets "
688 + timestr(first_end-nullability_end, total_time));
689 if (machine_end != 0 && first_end != 0)
690 System.err.println(" State build "
691 + timestr(machine_end-first_end, total_time));
692 if (table_end != 0 && machine_end != 0)
693 System.err.println(" Table build "
694 + timestr(table_end-machine_end, total_time));
695 if (reduce_check_end != 0 && table_end != 0)
696 System.err.println(" Checking "
697 + timestr(reduce_check_end-table_end, total_time));
698 if (emit_end != 0 && build_end != 0)
699 System.err.println(" Code Output "
700 + timestr(emit_end-build_end, total_time));
701 if (emit.symbols_time != 0)
702 System.err.println(" Symbols "
703 + timestr(emit.symbols_time, total_time));
704 if (emit.parser_time != 0)
705 System.err.println(" Parser class "
706 + timestr(emit.parser_time, total_time));
707 if (emit.action_code_time != 0)
708 System.err.println(" Actions "
709 + timestr(emit.action_code_time, total_time));
710 if (emit.production_table_time != 0)
711 System.err.println(" Prod table "
712 + timestr(emit.production_table_time, total_time));
713 if (emit.action_table_time != 0)
714 System.err.println(" Action tab "
715 + timestr(emit.action_table_time, total_time));
716 if (emit.goto_table_time != 0)
717 System.err.println(" Reduce tab "
718 + timestr(emit.goto_table_time, total_time));
719
720 System.err.println(" Dump Output "
721 + timestr(dump_end-emit_end, total_time));
722 }
723
724 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
725
726 /** Helper routine to format a decimal based display of seconds and
727 * percentage of total time given counts of milliseconds. Note: this
728 * is broken for use with some instances of negative time (since we don't
729 * use any negative time here, we let if be for now).
730 * @param time_val the value being formatted (in ms).
731 * @param total_time total time percentages are calculated against (in ms).
732 */
733 protected static String timestr(long time_val, long total_time)
734 {
735 boolean neg;
736 long ms = 0;
737 long sec = 0;
738 long percent10;
739 String pad;
740
741 /* work with positives only */
742 neg = time_val < 0;
743 if (neg) time_val = -time_val;
744
745 /* pull out seconds and ms */
746 ms = time_val % 1000;
747 sec = time_val / 1000;
748
749 /* construct a pad to blank fill seconds out to 4 places */
750 if (sec < 10)
751 pad = " ";
752 else if (sec < 100)
753 pad = " ";
754 else if (sec < 1000)
755 pad = " ";
756 else
757 pad = "";
758
759 /* calculate 10 times the percentage of total */
760 percent10 = (time_val*1000)/total_time;
761
762 /* build and return the output string */
763 return (neg ? "-" : "") + pad + sec + "." +
764 ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" +
765 " (" + percent10/10 + "." + percent10%10 + "%)";
766 }
767
768 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
769
770 /** Produce a human readable dump of the grammar. */
771 public static void dump_grammar() throws internal_error
772 {
773 System.err.println("===== Terminals =====");
774 for (int tidx=0, cnt=0; tidx < terminal.number(); tidx++, cnt++)
775 {
776 System.err.print("["+tidx+"]"+terminal.find(tidx).name()+" ");
777 if ((cnt+1) % 5 == 0) System.err.println();
778 }
779 System.err.println();
780 System.err.println();
781
782 System.err.println("===== Non terminals =====");
783 for (int nidx=0, cnt=0; nidx < non_terminal.number(); nidx++, cnt++)
784 {
785 System.err.print("["+nidx+"]"+non_terminal.find(nidx).name()+" ");
786 if ((cnt+1) % 5 == 0) System.err.println();
787 }
788 System.err.println();
789 System.err.println();
790
791
792 System.err.println("===== Productions =====");
793 for (int pidx=0; pidx < production.number(); pidx++)
794 {
795 production prod = production.find(pidx);
796 System.err.print("["+pidx+"] "+prod.lhs().the_symbol().name() + " ::= ");
797 for (int i=0; i<prod.rhs_length(); i++)
798 if (prod.rhs(i).is_action())
799 System.err.print("{action} ");
800 else
801 System.err.print(
802 ((symbol_part)prod.rhs(i)).the_symbol().name() + " ");
803 System.err.println();
804 }
805 System.err.println();
806 }
807
808 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
809
810 /** Produce a (semi-) human readable dump of the complete viable prefix
811 * recognition state machine.
812 */
813 public static void dump_machine()
814 {
815 lalr_state ordered[] = new lalr_state[lalr_state.number()];
816
817 /* put the states in sorted order for a nicer display */
818 for (Enumeration s = lalr_state.all(); s.hasMoreElements(); )
819 {
820 lalr_state st = (lalr_state)s.nextElement();
821 ordered[st.index()] = st;
822 }
823
824 System.err.println("===== Viable Prefix Recognizer =====");
825 for (int i = 0; i<lalr_state.number(); i++)
826 {
827 if (ordered[i] == start_state) System.err.print("START ");
828 System.err.println(ordered[i]);
829 System.err.println("-------------------");
830 }
831 }
832
833 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
834
835 /** Produce a (semi-) human readable dumps of the parse tables */
836 public static void dump_tables()
837 {
838 System.err.println(action_table);
839 System.err.println(reduce_table);
840 }
841
842 /*-----------------------------------------------------------*/
843
844 }
845