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