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