KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java_cup > Main


1
2 package java_cup;
3
4 import java.util.Enumeration JavaDoc;
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> -srcdir dir
29  * <dd> specify the root directory of the java tyee [default the current directory]
30  * <dt> -interface
31  * <dd> emit symbol constant <i>interface</i>, rather than class
32  * <dt> -nonterms
33  * <dd> put non terminals in symbol constant class
34  * <dt> -expect #
35  * <dd> number of conflicts expected/allowed [default 0]
36  * <dt> -compact_red
37  * <dd> compact tables by defaulting to most frequent reduce
38  * <dt> -nowarn
39  * <dd> don't warn about useless productions, etc.
40  * <dt> -nosummary
41  * <dd> don't print the usual summary of parse states, etc.
42  * <dt> -progress
43  * <dd> print messages to indicate progress of the system
44  * <dt> -time
45  * <dd> print time usage summary
46  * <dt> -dump_grammar
47  * <dd> produce a dump of the symbols and grammar
48  * <dt> -dump_states
49  * <dd> produce a dump of parse state machine
50  * <dt> -dump_tables
51  * <dd> produce a dump of the parse tables
52  * <dt> -dump
53  * <dd> produce a dump of all of the above
54  * <dt> -debug
55  * <dd> turn on debugging messages within JavaCup
56  * <dt> -nopositions
57  * <dd> don't generate the positions code
58  * <dt> -noscanner
59  * <dd> don't refer to java_cup.runtime.Scanner in the parser
60  * (for compatibility with old runtimes)
61  * <dt> -version
62  * <dd> print version information for JavaCUP and halt.
63  * </dl>
64  *
65  * @version last updated: 7/3/96
66  * @author Frank Flannery
67  */

68
69 public class Main {
70
71   /*-----------------------------------------------------------*/
72   /*--- Constructor(s) ----------------------------------------*/
73   /*-----------------------------------------------------------*/
74   /** Only constructor is private, so we do not allocate any instances of this
75       class. */

76   private Main() { }
77
78   /*-------------------------*/
79   /* Options set by the user */
80   /*-------------------------*/
81   /** User option -- do we print progress messages. */
82   protected static boolean print_progress = true;
83   /** User option -- do we produce a dump of the state machine */
84   protected static boolean opt_dump_states = false;
85   /** User option -- do we produce a dump of the parse tables */
86   protected static boolean opt_dump_tables = false;
87   /** User option -- do we produce a dump of the grammar */
88   protected static boolean opt_dump_grammar = false;
89   /** User option -- do we show timing information as a part of the summary */
90   protected static boolean opt_show_timing = false;
91   /** User option -- do we run produce extra debugging messages */
92   protected static boolean opt_do_debug = false;
93   /** User option -- do we compact tables by making most common reduce the
94       default action */

95   protected static boolean opt_compact_red = false;
96   /** User option -- should we include non terminal symbol numbers in the
97       symbol constant class. */

98   protected static boolean include_non_terms = false;
99   /** User option -- do not print a summary. */
100   protected static boolean no_summary = false;
101   /** User option -- number of conflicts to expect */
102   protected static int expect_conflicts = 0;
103
104   /* frankf added this 6/18/96 */
105   /** User option -- should generator generate code for left/right values? */
106   protected static boolean lr_values = true;
107
108   /** User option -- should symbols be put in a class or an interface? [CSA]*/
109   protected static boolean sym_interface = false;
110
111   /** Input stream. */
112   protected static InputStream in;
113
114   /** Name of input file (or "Standard input"). */
115   protected static String JavaDoc inFileName;
116
117   /** Name of output file which holds parser class. */
118   protected static String JavaDoc classFileName;
119
120   /** Name of output file which holds symbols class. */
121   protected static String JavaDoc symbolsFileName;
122
123   /** User option -- should generator suppress references to
124    * java_cup.runtime.Scanner for compatibility with old runtimes? */

125   protected static boolean suppress_scanner = false;
126
127   /** Only generate output files if the specification is newer. **/
128   protected static boolean newer = false;
129
130   /*----------------------------------------------------------------------*/
131   /* Timing data (not all of these time intervals are mutually exclusive) */
132   /*----------------------------------------------------------------------*/
133   /** Timing data -- when did we start */
134   protected static long start_time = 0;
135   /** Timing data -- when did we end preliminaries */
136   protected static long prelim_end = 0;
137   /** Timing data -- when did we end parsing */
138   protected static long parse_end = 0;
139   /** Timing data -- when did we end checking */
140   protected static long check_end = 0;
141   /** Timing data -- when did we end dumping */
142   protected static long dump_end = 0;
143   /** Timing data -- when did we end state and table building */
144   protected static long build_end = 0;
145   /** Timing data -- when did we end nullability calculation */
146   protected static long nullability_end = 0;
147   /** Timing data -- when did we end first set calculation */
148   protected static long first_end = 0;
149   /** Timing data -- when did we end state machine construction */
150   protected static long machine_end = 0;
151   /** Timing data -- when did we end table construction */
152   protected static long table_end = 0;
153   /** Timing data -- when did we end checking for non-reduced productions */
154   protected static long reduce_check_end = 0;
155   /** Timing data -- when did we finish emitting code */
156   protected static long emit_end = 0;
157   /** Timing data -- when were we completely done */
158   protected static long final_time = 0;
159
160   /* Additional timing information is also collected in emit */
161
162   /*-----------------------------------------------------------*/
163   /*--- Main Program ------------------------------------------*/
164   /*-----------------------------------------------------------*/
165
166   /** The main driver for the system.
167    * @param argv an array of strings containing command line arguments.
168    */

169   public static void main(String JavaDoc argv[])
170     throws internal_error, java.io.IOException JavaDoc, java.lang.Exception JavaDoc
171     {
172     main(argv, null);
173     }
174
175   static void main(String JavaDoc argv[], String JavaDoc _inFileName)
176     throws internal_error, java.io.IOException JavaDoc, java.lang.Exception JavaDoc
177     {
178       boolean did_output = false;
179
180       start_time = System.currentTimeMillis();
181
182       /* process user options and arguments */
183       parse_args(argv);
184
185       if (!compute_file_names(_inFileName)) {
186           if (print_progress) {
187               System.err.println("Files are up to date.");
188           }
189           return;
190       }
191
192       /* frankf 6/18/96
193      hackish, yes, but works */

194       emit.set_lr_values(lr_values);
195       /* open input file (or stdin) */
196       open_input_file();
197
198       prelim_end = System.currentTimeMillis();
199
200       /* parse spec into internal data structures */
201       parse_grammar_spec();
202
203       parse_end = System.currentTimeMillis();
204
205       /* don't proceed unless we are error free */
206       if (lexer.error_count == 0)
207     {
208       /* check for unused bits */
209           if (print_progress) System.err.println("Checking specification...");
210           check_unused();
211
212           check_end = System.currentTimeMillis();
213
214       /* build the state machine and parse tables */
215           if (print_progress) System.err.println("Building parse tables...");
216           build_parser();
217
218           build_end = System.currentTimeMillis();
219
220       /* output the generated code, if # of conflicts permits */
221       if (lexer.error_count != 0) {
222           // conflicts! don't emit code, don't dump tables.
223
opt_dump_tables = false;
224       } else { // everything's okay, emit parser.
225
if (print_progress) System.err.println("Writing parser...");
226           open_files();
227           emit_parser();
228           did_output = true;
229       }
230     }
231       /* fix up the times to make the summary easier */
232       emit_end = System.currentTimeMillis();
233
234       /* do requested dumps */
235       if (opt_dump_grammar) dump_grammar();
236       if (opt_dump_states) dump_machine();
237       if (opt_dump_tables) dump_tables();
238
239       dump_end = System.currentTimeMillis();
240
241       /* close input/output files */
242       if (print_progress) System.err.println("Closing files...");
243       close_files();
244
245       /* produce a summary if desired */
246       if (!no_summary) emit_summary(did_output);
247
248       /* If there were errors during the run,
249        * exit with non-zero status (makefile-friendliness). --CSA */

250       if (lexer.error_count != 0)
251       System.exit(100);
252     }
253
254   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
255
256   /** Print a "usage message" that described possible command line options,
257    * then exit.
258    * @param message a specific error message to preface the usage message by.
259    */

260   protected static void usage(String JavaDoc message)
261     {
262       System.err.println();
263       System.err.println(message);
264       System.err.println();
265       System.err.println(
266 "Usage: " + version.program_name + " [options] [filename]\n" +
267 " and expects a specification file on standard input if no filename is given.\n" +
268 " Legal options include:\n" +
269 " -package name specify package generated classes go in [default none]\n" +
270 " -parser name specify parser class name [default \"parser\"]\n" +
271 " -symbols name specify name for symbol constant class [default \"sym\"]\n"+
272 " -interface put symbols in an interface, rather than a class\n" +
273 " -nonterms put non terminals in symbol constant class\n" +
274 " -expect # number of conflicts expected/allowed [default 0]\n" +
275 " -compact_red compact tables by defaulting to most frequent reduce\n" +
276 " -nowarn don't warn about useless productions, etc.\n" +
277 " -nosummary don't print the usual summary of parse states, etc.\n" +
278 " -nopositions don't propagate the left and right token position values\n" +
279 " -noscanner don't refer to java_cup.runtime.Scanner\n" +
280 " -progress print messages to indicate progress of the system\n" +
281 " -time print time usage summary\n" +
282 " -dump_grammar produce a human readable dump of the symbols and grammar\n"+
283 " -dump_states produce a dump of parse state machine\n"+
284 " -dump_tables produce a dump of the parse tables\n"+
285 " -dump produce a dump of all of the above\n"+
286 " -version print the version information for CUP and exit\n"+
287 " -newer generate only if the specification is newer\n"
288       );
289       System.exit(1);
290     }
291
292   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
293
294   /** Parse command line options and arguments to set various user-option
295    * flags and variables.
296    * @param argv the command line arguments to be parsed.
297    */

298   protected static void parse_args(String JavaDoc argv[])
299     {
300       int len = argv.length;
301       int i;
302
303       /* parse the options */
304       for (i=0; i<len; i++)
305     {
306       /* try to get the various options */
307       if (argv[i].equals("-package"))
308         {
309           /* must have an arg */
310           if (++i >= len || argv[i].startsWith("-") ||
311                 argv[i].endsWith(".cup"))
312         usage("-package must have a name argument");
313
314           /* record the name */
315           emit.package_name = argv[i];
316         }
317       else if (argv[i].equals("-parser"))
318         {
319           /* must have an arg */
320           if (++i >= len || argv[i].startsWith("-") ||
321                 argv[i].endsWith(".cup"))
322         usage("-parser must have a name argument");
323
324           /* record the name */
325           emit.parser_class_name = argv[i];
326         }
327       else if (argv[i].equals("-symbols"))
328         {
329           /* must have an arg */
330           if (++i >= len || argv[i].startsWith("-") ||
331                 argv[i].endsWith(".cup"))
332         usage("-symbols must have a name argument");
333
334           /* record the name */
335           emit.symbol_const_class_name = argv[i];
336         }
337       else if (argv[i].equals("-nonterms"))
338         {
339           include_non_terms = true;
340         }
341       else if (argv[i].equals("-expect"))
342         {
343           /* must have an arg */
344           if (++i >= len || argv[i].startsWith("-") ||
345                 argv[i].endsWith(".cup"))
346         usage("-expect must have a name argument");
347
348           /* record the number */
349           try {
350             expect_conflicts = Integer.parseInt(argv[i]);
351           } catch (NumberFormatException JavaDoc e) {
352         usage("-expect must be followed by a decimal integer");
353           }
354         }
355       else if (argv[i].equals("-srcdir"))
356         {
357           /* must have an arg */
358           if (++i >= len || argv[i].startsWith("-") ||
359                 argv[i].endsWith(".cup"))
360         usage("-srcdir must have a name argument");
361
362           /* record the name */
363           emit.src_dir_name = argv[i];
364         }
365       else if (argv[i].equals("-compact_red")) opt_compact_red = true;
366       else if (argv[i].equals("-nosummary")) no_summary = true;
367       else if (argv[i].equals("-nowarn")) emit.nowarn = true;
368       else if (argv[i].equals("-dump_states")) opt_dump_states = true;
369       else if (argv[i].equals("-dump_tables")) opt_dump_tables = true;
370       else if (argv[i].equals("-progress")) print_progress = true;
371       else if (argv[i].equals("-dump_grammar")) opt_dump_grammar = true;
372       else if (argv[i].equals("-dump"))
373             opt_dump_states = opt_dump_tables = opt_dump_grammar = true;
374       else if (argv[i].equals("-time")) opt_show_timing = true;
375       else if (argv[i].equals("-debug")) opt_do_debug = true;
376       /* frankf 6/18/96 */
377       else if (argv[i].equals("-nopositions")) lr_values = false;
378       /* CSA 12/21/97 */
379       else if (argv[i].equals("-interface")) sym_interface = true;
380       /* CSA 23-Jul-1999 */
381       else if (argv[i].equals("-noscanner")) suppress_scanner = true;
382       /* CSA 23-Jul-1999 */
383       else if (argv[i].equals("-version")) {
384           System.out.println(version.title_str);
385           System.exit(1);
386       }
387       /* jhyde 02-Apr-2002 */
388       else if (argv[i].equals("-newer")) newer = true;
389       /* CSA 24-Jul-1999; suggestion by Jean Vaucher */
390       else if (!argv[i].startsWith("-") && i==len-1) {
391           /* use input from file. */
392           try {
393           System.setIn(new FileInputStream(argv[i]));
394           } catch (java.io.FileNotFoundException JavaDoc e) {
395           usage("Unable to open \"" + argv[i] +"\" for input");
396           }
397       }
398       else
399         {
400           usage("Unrecognized option \"" + argv[i] + "\"");
401         }
402     }
403     }
404
405   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
406
407   /*-------*/
408   /* Files */
409   /*-------*/
410
411   /** Input file. This is a buffered version of System.in. */
412   protected static BufferedInputStream input_file;
413
414   /** Output file for the parser class. */
415   protected static PrintWriter parser_class_file;
416
417   /** Output file for the symbol constant class. */
418   protected static PrintWriter symbol_class_file;
419
420   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
421
422   /**
423    * Figures out the names of the input and output files, checks their time-
424    * stamps, and returns whether to go ahead.
425    */

426   protected static boolean compute_file_names(String JavaDoc _inFileName)
427     {
428       inFileName = _inFileName; // may be null
429
classFileName = classToFileName(emit.package_name, emit.parser_class_name);
430       symbolsFileName = classToFileName(emit.package_name, emit.symbol_const_class_name);
431       if (newer && inFileName != null) {
432     File inFile = new File(inFileName),
433         classFile = new File(classFileName),
434         symbolsFile = new File(symbolsFileName);
435     if (!classFile.exists() ||
436         !symbolsFile.exists()) {
437       return true;
438     }
439     long inStamp = inFile.lastModified(),
440         classStamp = classFile.lastModified(),
441         symbolsStamp = symbolsFile.lastModified();
442     if (inStamp > classStamp ||
443         inStamp > symbolsStamp) {
444       return true;
445     }
446     return false;
447       } else {
448     return false;
449       }
450     }
451
452   /** Open various files used by the system. */
453   protected static void open_input_file()
454     {
455       if (print_progress) {
456         System.err.println("Opening files...");
457       }
458       if (inFileName == null) {
459     inFileName = "standard input";
460     in = new BufferedInputStream(System.in);
461       } else {
462     try {
463       in = new FileInputStream(inFileName);
464     } catch (IOException e) {
465       System.err.println("Can't open \"" + inFileName + "\" for input");
466       System.exit(4);
467     }
468       }
469
470       if (print_progress) {
471     System.err.println("Parsing specification from " + inFileName + "...");
472       }
473       /* use a buffered version of standard input */
474       input_file = new BufferedInputStream(in);
475     }
476
477   /** Open each of the output files. */
478   protected static void open_files()
479     {
480       /* parser class */
481       File fil = new File(classFileName);
482       try {
483         parser_class_file = new PrintWriter(
484          new BufferedOutputStream(new FileOutputStream(fil), 4096));
485       } catch(Exception JavaDoc e) {
486     System.err.println("Can't open \"" + classFileName + "\" for output");
487     System.exit(3);
488       }
489
490       /* symbol constants class */
491       fil = new File(symbolsFileName);
492       try {
493         symbol_class_file = new PrintWriter(
494          new BufferedOutputStream(new FileOutputStream(fil), 4096));
495       } catch(Exception JavaDoc e) {
496     System.err.println("Can't open \"" + symbolsFileName + "\" for output");
497     System.exit(4);
498       }
499     }
500
501   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
502
503   /** Close various files used by the system. */
504   protected static void close_files() throws java.io.IOException JavaDoc
505     {
506       if (input_file != null) input_file.close();
507       if (parser_class_file != null) parser_class_file.close();
508       if (symbol_class_file != null) symbol_class_file.close();
509     }
510
511   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
512
513   /** Parse the grammar specification from standard input. This produces
514    * sets of terminal, non-terminals, and productions which can be accessed
515    * via static variables of the respective classes, as well as the setting
516    * of various variables (mostly in the emit class) for small user supplied
517    * items such as the code to scan with.
518    */

519   protected static void parse_grammar_spec() throws java.lang.Exception JavaDoc
520     {
521       parser parser_obj;
522
523       /* create a parser and parse with it */
524       parser_obj = new parser();
525       try {
526     if (opt_do_debug)
527           parser_obj.debug_parse();
528     else
529           parser_obj.parse();
530       } catch (Exception JavaDoc e)
531       {
532     /* something threw an exception. catch it and emit a message so we
533        have a line number to work with, then re-throw it */

534     lexer.emit_error("Internal error: Unexpected exception");
535     throw (Exception JavaDoc) e.fillInStackTrace();
536       }
537     }
538
539   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
540
541   /** Check for unused symbols. Unreduced productions get checked when
542    * tables are created.
543    */

544   protected static void check_unused()
545     {
546       terminal term;
547       non_terminal nt;
548
549       /* check for unused terminals */
550       for (Enumeration JavaDoc t = terminal.all(); t.hasMoreElements(); )
551     {
552       term = (terminal)t.nextElement();
553
554       /* don't issue a message for EOF */
555       if (term == terminal.EOF) continue;
556
557       /* or error */
558       if (term == terminal.error) continue;
559
560       /* is this one unused */
561       if (term.use_count() == 0)
562         {
563           /* count it and warn if we are doing warnings */
564           emit.unused_term++;
565           if (!emit.nowarn)
566         {
567           System.err.println("Warning: Terminal \"" + term.name() +
568                      "\" was declared but never used");
569           lexer.warning_count++;
570         }
571         }
572     }
573
574       /* check for unused non terminals */
575       for (Enumeration JavaDoc n = non_terminal.all(); n.hasMoreElements(); )
576     {
577       nt = (non_terminal)n.nextElement();
578
579       /* is this one unused */
580       if (nt.use_count() == 0)
581         {
582           /* count and warn if we are doing warnings */
583           emit.unused_term++;
584           if (!emit.nowarn)
585         {
586           System.err.println("Warning: Non terminal \"" + nt.name() +
587                      "\" was declared but never used");
588           lexer.warning_count++;
589         }
590         }
591     }
592
593     }
594
595   /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
596   /* . . Internal Results of Generating the Parser . .*/
597   /* . . . . . . . . . . . . . . . . . . . . . . . . .*/
598
599   /** Start state in the overall state machine. */
600   protected static lalr_state start_state;
601
602   /** Resulting parse action table. */
603   protected static parse_action_table action_table;
604
605   /** Resulting reduce-goto table. */
606   protected static parse_reduce_table reduce_table;
607
608   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
609
610   /** Build the (internal) parser from the previously parsed specification.
611    * This includes:<ul>
612    * <li> Computing nullability of non-terminals.
613    * <li> Computing first sets of non-terminals and productions.
614    * <li> Building the viable prefix recognizer machine.
615    * <li> Filling in the (internal) parse tables.
616    * <li> Checking for unreduced productions.
617    * </ul>
618    */

619   protected static void build_parser() throws internal_error
620     {
621       /* compute nullability of all non terminals */
622       if (opt_do_debug || print_progress)
623     System.err.println(" Computing non-terminal nullability...");
624       non_terminal.compute_nullability();
625
626       nullability_end = System.currentTimeMillis();
627
628       /* compute first sets of all non terminals */
629       if (opt_do_debug || print_progress)
630     System.err.println(" Computing first sets...");
631       non_terminal.compute_first_sets();
632
633       first_end = System.currentTimeMillis();
634
635       /* build the LR viable prefix recognition machine */
636       if (opt_do_debug || print_progress)
637     System.err.println(" Building state machine...");
638       start_state = lalr_state.build_machine(emit.start_production);
639
640       machine_end = System.currentTimeMillis();
641
642       /* build the LR parser action and reduce-goto tables */
643       if (opt_do_debug || print_progress)
644     System.err.println(" Filling in tables...");
645       action_table = new parse_action_table();
646       reduce_table = new parse_reduce_table();
647       for (Enumeration JavaDoc st = lalr_state.all(); st.hasMoreElements(); )
648     {
649       lalr_state lst = (lalr_state)st.nextElement();
650       lst.build_table_entries(
651                                   action_table, reduce_table);
652     }
653
654       table_end = System.currentTimeMillis();
655
656       /* check and warn for non-reduced productions */
657       if (opt_do_debug || print_progress)
658     System.err.println(" Checking for non-reduced productions...");
659       action_table.check_reductions();
660
661       reduce_check_end = System.currentTimeMillis();
662
663       /* if we have more conflicts than we expected issue a message and die */
664       if (emit.num_conflicts > expect_conflicts)
665     {
666       System.err.println("*** More conflicts encountered than expected " +
667                  "-- parser generation aborted");
668       lexer.error_count++; // indicate the problem.
669
// we'll die on return, after clean up.
670
}
671     }
672
673   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
674
675   /** Call the emit routines necessary to write out the generated parser. */
676   protected static void emit_parser() throws internal_error
677     {
678       emit.symbols(symbol_class_file, include_non_terms, sym_interface);
679       emit.parser(parser_class_file, action_table, reduce_table,
680           start_state.index(), emit.start_production, opt_compact_red,
681           suppress_scanner);
682     }
683
684   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
685
686   /** Helper routine to optionally return a plural or non-plural ending.
687    * @param val the numerical value determining plurality.
688    */

689   protected static String JavaDoc plural(int val)
690     {
691       if (val == 1)
692     return "";
693       else
694     return "s";
695     }
696
697   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
698
699   /** Emit a long summary message to standard error (System.err) which
700    * summarizes what was found in the specification, how many states were
701    * produced, how many conflicts were found, etc. A detailed timing
702    * summary is also produced if it was requested by the user.
703    * @param output_produced did the system get far enough to generate code.
704    */

705   protected static void emit_summary(boolean output_produced)
706     {
707       final_time = System.currentTimeMillis();
708
709       if (no_summary) return;
710
711       System.err.println("------- " + version.title_str +
712              " Parser Generation Summary -------");
713
714       /* error and warning count */
715       System.err.println(" " + lexer.error_count + " error" +
716      plural(lexer.error_count) + " and " + lexer.warning_count +
717      " warning" + plural(lexer.warning_count));
718
719       /* basic stats */
720       System.err.print(" " + terminal.number() + " terminal" +
721              plural(terminal.number()) + ", ");
722       System.err.print(non_terminal.number() + " non-terminal" +
723              plural(non_terminal.number()) + ", and ");
724       System.err.println(production.number() + " production" +
725              plural(production.number()) + " declared, ");
726       System.err.println(" producing " + lalr_state.number() +
727              " unique parse states.");
728
729       /* unused symbols */
730       System.err.println(" " + emit.unused_term + " terminal" +
731              plural(emit.unused_term) + " declared but not used.");
732       System.err.println(" " + emit.unused_non_term + " non-terminal" +
733              plural(emit.unused_term) + " declared but not used.");
734
735       /* productions that didn't reduce */
736       System.err.println(" " + emit.not_reduced + " production" +
737              plural(emit.not_reduced) + " never reduced.");
738
739       /* conflicts */
740       System.err.println(" " + emit.num_conflicts + " conflict" +
741              plural(emit.num_conflicts) + " detected" +
742                      " (" + expect_conflicts + " expected).");
743
744       /* code location */
745       if (output_produced)
746     System.err.println(" Code written to \"" + emit.parser_class_name +
747             ".java\", and \"" + emit.symbol_const_class_name + ".java\".");
748       else
749     System.err.println(" No code produced.");
750
751       if (opt_show_timing) show_times();
752
753       System.err.println(
754     "---------------------------------------------------- (" +
755      version.version_str + ")");
756     }
757
758   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
759
760   /** Produce the optional timing summary as part of an overall summary. */
761   protected static void show_times()
762     {
763       long total_time = final_time - start_time;
764
765       System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . ");
766       System.err.println(" Timing Summary");
767       System.err.println(" Total time "
768         + timestr(final_time-start_time, total_time));
769       System.err.println(" Startup "
770     + timestr(prelim_end-start_time, total_time));
771       System.err.println(" Parse "
772     + timestr(parse_end-prelim_end, total_time) );
773       if (check_end != 0)
774         System.err.println(" Checking "
775         + timestr(check_end-parse_end, total_time));
776       if (check_end != 0 && build_end != 0)
777         System.err.println(" Parser Build "
778         + timestr(build_end-check_end, total_time));
779       if (nullability_end != 0 && check_end != 0)
780         System.err.println(" Nullability "
781         + timestr(nullability_end-check_end, total_time));
782       if (first_end != 0 && nullability_end != 0)
783         System.err.println(" First sets "
784             + timestr(first_end-nullability_end, total_time));
785       if (machine_end != 0 && first_end != 0)
786         System.err.println(" State build "
787         + timestr(machine_end-first_end, total_time));
788       if (table_end != 0 && machine_end != 0)
789         System.err.println(" Table build "
790         + timestr(table_end-machine_end, total_time));
791       if (reduce_check_end != 0 && table_end != 0)
792         System.err.println(" Checking "
793         + timestr(reduce_check_end-table_end, total_time));
794       if (emit_end != 0 && build_end != 0)
795         System.err.println(" Code Output "
796         + timestr(emit_end-build_end, total_time));
797       if (emit.symbols_time != 0)
798     System.err.println(" Symbols "
799         + timestr(emit.symbols_time, total_time));
800       if (emit.parser_time != 0)
801     System.err.println(" Parser class "
802         + timestr(emit.parser_time, total_time));
803       if (emit.action_code_time != 0)
804     System.err.println(" Actions "
805         + timestr(emit.action_code_time, total_time));
806       if (emit.production_table_time != 0)
807     System.err.println(" Prod table "
808         + timestr(emit.production_table_time, total_time));
809       if (emit.action_table_time != 0)
810     System.err.println(" Action tab "
811         + timestr(emit.action_table_time, total_time));
812       if (emit.goto_table_time != 0)
813     System.err.println(" Reduce tab "
814         + timestr(emit.goto_table_time, total_time));
815
816       System.err.println(" Dump Output "
817     + timestr(dump_end-emit_end, total_time));
818     }
819
820   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
821
822   /** Helper routine to format a decimal based display of seconds and
823    * percentage of total time given counts of milliseconds. Note: this
824    * is broken for use with some instances of negative time (since we don't
825    * use any negative time here, we let if be for now).
826    * @param time_val the value being formatted (in ms).
827    * @param total_time total time percentages are calculated against (in ms).
828    */

829   protected static String JavaDoc timestr(long time_val, long total_time)
830     {
831       boolean neg;
832       long ms = 0;
833       long sec = 0;
834       long percent10;
835       String JavaDoc pad;
836
837       /* work with positives only */
838       neg = time_val < 0;
839       if (neg) time_val = -time_val;
840
841       /* pull out seconds and ms */
842       ms = time_val % 1000;
843       sec = time_val / 1000;
844
845       /* construct a pad to blank fill seconds out to 4 places */
846       if (sec < 10)
847     pad = " ";
848       else if (sec < 100)
849     pad = " ";
850       else if (sec < 1000)
851     pad = " ";
852       else
853     pad = "";
854
855       /* calculate 10 times the percentage of total */
856       percent10 = (time_val*1000)/total_time;
857
858       /* build and return the output string */
859       return (neg ? "-" : "") + pad + sec + "." +
860          ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" +
861          " (" + percent10/10 + "." + percent10%10 + "%)";
862     }
863
864   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
865
866   /** Produce a human readable dump of the grammar. */
867   public static void dump_grammar() throws internal_error
868     {
869       System.err.println("===== Terminals =====");
870       for (int tidx=0, cnt=0; tidx < terminal.number(); tidx++, cnt++)
871     {
872       System.err.print("["+tidx+"]"+terminal.find(tidx).name()+" ");
873       if ((cnt+1) % 5 == 0) System.err.println();
874     }
875       System.err.println();
876       System.err.println();
877
878       System.err.println("===== Non terminals =====");
879       for (int nidx=0, cnt=0; nidx < non_terminal.number(); nidx++, cnt++)
880     {
881       System.err.print("["+nidx+"]"+non_terminal.find(nidx).name()+" ");
882       if ((cnt+1) % 5 == 0) System.err.println();
883     }
884       System.err.println();
885       System.err.println();
886
887
888       System.err.println("===== Productions =====");
889       for (int pidx=0; pidx < production.number(); pidx++)
890     {
891       production prod = production.find(pidx);
892       System.err.print("["+pidx+"] "+prod.lhs().the_symbol().name() + " ::= ");
893       for (int i=0; i<prod.rhs_length(); i++)
894         if (prod.rhs(i).is_action())
895           System.err.print("{action} ");
896         else
897           System.err.print(
898              ((symbol_part)prod.rhs(i)).the_symbol().name() + " ");
899       System.err.println();
900     }
901       System.err.println();
902     }
903
904   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
905
906   /** Produce a (semi-) human readable dump of the complete viable prefix
907    * recognition state machine.
908    */

909   public static void dump_machine()
910     {
911       lalr_state ordered[] = new lalr_state[lalr_state.number()];
912
913       /* put the states in sorted order for a nicer display */
914       for (Enumeration JavaDoc s = lalr_state.all(); s.hasMoreElements(); )
915     {
916       lalr_state st = (lalr_state)s.nextElement();
917       ordered[st.index()] = st;
918     }
919
920       System.err.println("===== Viable Prefix Recognizer =====");
921       for (int i = 0; i<lalr_state.number(); i++)
922     {
923       if (ordered[i] == start_state) System.err.print("START ");
924           System.err.println(ordered[i]);
925       System.err.println("-------------------");
926     }
927     }
928
929   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
930
931   /** Produce a (semi-) human readable dumps of the parse tables */
932   public static void dump_tables()
933     {
934       System.err.println(action_table);
935       System.err.println(reduce_table);
936     }
937
938   /*-----------------------------------------------------------*/
939
940     /**
941      * Creates the name a java class will live in. For example,
942      * <code>makeJavaFileName("com.myproj", "MyClass")</code> returns
943      * "com/myproj/MyClass.java".
944      **/

945     static String JavaDoc classToFileName(String JavaDoc packageName, String JavaDoc className)
946     {
947     char fileSep = System.getProperty("file.separator").charAt(0); // e.g. '/'
948
String JavaDoc s = emit.src_dir_name;
949     if (s == null) {
950         s = "";
951     } else if (s.equals("")) {
952     } else {
953         s += fileSep;
954     }
955     if (packageName != null && !packageName.equals("")) {
956         className = packageName + "." + className;
957     }
958     return s + className.replace('.', fileSep) + ".java";
959     }
960
961     /**
962      * Returns the full class name which lives in a java file.
963      **/

964     static String JavaDoc fileNameToClass(String JavaDoc fileName)
965     {
966     if (fileName.endsWith(".cup")) {
967         fileName = fileName.substring(
968         0, fileName.length() - ".cup".length());
969     }
970     if (fileName.endsWith(".java")) {
971         fileName = fileName.substring(
972         0, fileName.length() - ".java".length());
973     }
974     char fileSep = System.getProperty("file.separator").charAt(0); // e.g. '/'
975
return fileName.replace(fileSep, '.');
976     }
977 }
978
979
Popular Tags