KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java_cup > emit


1 package java_cup;
2
3 import java.io.PrintWriter JavaDoc;
4 import java.util.Stack JavaDoc;
5 import java.util.Enumeration JavaDoc;
6 import java.util.Date JavaDoc;
7
8 /**
9  * This class handles emitting generated code for the resulting parser.
10  * The various parse tables must be constructed, etc. before calling any
11  * routines in this class.<p>
12  *
13  * Three classes are produced by this code:
14  * <dl>
15  * <dt> symbol constant class
16  * <dd> this contains constant declarations for each terminal (and
17  * optionally each non-terminal).
18  * <dt> action class
19  * <dd> this non-public class contains code to invoke all the user actions
20  * that were embedded in the parser specification.
21  * <dt> parser class
22  * <dd> the specialized parser class consisting primarily of some user
23  * supplied general and initialization code, and the parse tables.
24  * </dl><p>
25  *
26  * Three parse tables are created as part of the parser class:
27  * <dl>
28  * <dt> production table
29  * <dd> lists the LHS non terminal number, and the length of the RHS of
30  * each production.
31  * <dt> action table
32  * <dd> for each state of the parse machine, gives the action to be taken
33  * (shift, reduce, or error) under each lookahead symbol.<br>
34  * <dt> reduce-goto table
35  * <dd> when a reduce on a given production is taken, the parse stack is
36  * popped back a number of elements corresponding to the RHS of the
37  * production. This reveals a prior state, which we transition out
38  * of under the LHS non terminal symbol for the production (as if we
39  * had seen the LHS symbol rather than all the symbols matching the
40  * RHS). This table is indexed by non terminal numbers and indicates
41  * how to make these transitions.
42  * </dl><p>
43  *
44  * In addition to the method interface, this class maintains a series of
45  * public global variables and flags indicating how misc. parts of the code
46  * and other output is to be produced, and counting things such as number of
47  * conflicts detected (see the source code and public variables below for
48  * more details).<p>
49  *
50  * This class is "static" (contains only static data and methods).<p>
51  *
52  * @see java_cup.main
53  * @version last update: 11/25/95
54  * @author Scott Hudson
55  */

56
57 /* Major externally callable routines here include:
58      symbols - emit the symbol constant class
59      parser - emit the parser class
60
61    In addition the following major internal routines are provided:
62      emit_package - emit a package declaration
63      emit_action_code - emit the class containing the user's actions
64      emit_production_table - emit declaration and init for the production table
65      do_action_table - emit declaration and init for the action table
66      do_reduce_table - emit declaration and init for the reduce-goto table
67
68    Finally, this class uses a number of public instance variables to communicate
69    optional parameters and flags used to control how code is generated,
70    as well as to report counts of various things (such as number of conflicts
71    detected). These include:
72
73    prefix - a prefix string used to prefix names that would
74                  otherwise "pollute" someone else's name space.
75    package_name - name of the package emitted code is placed in
76                  (or null for an unnamed package.
77    symbol_const_class_name - name of the class containing symbol constants.
78    parser_class_name - name of the class for the resulting parser.
79    action_code - user supplied declarations and other code to be
80                  placed in action class.
81    parser_code - user supplied declarations and other code to be
82                  placed in parser class.
83    init_code - user supplied code to be executed as the parser
84                  is being initialized.
85    scan_code - user supplied code to get the next Symbol.
86    start_production - the start production for the grammar.
87    import_list - list of imports for use with action class.
88    num_conflicts - number of conflicts detected.
89    nowarn - true if we are not to issue warning messages.
90    not_reduced - count of number of productions that never reduce.
91    unused_term - count of unused terminal symbols.
92    unused_non_term - count of unused non terminal symbols.
93    *_time - a series of symbols indicating how long various
94                  sub-parts of code generation took (used to produce
95                  optional time reports in main).
96 */

97
98 public class emit {
99
100   /*-----------------------------------------------------------*/
101   /*--- Constructor(s) ----------------------------------------*/
102   /*-----------------------------------------------------------*/
103
104   /** Only constructor is private so no instances can be created. */
105   private emit() { }
106
107   /*-----------------------------------------------------------*/
108   /*--- Static (Class) Variables ------------------------------*/
109   /*-----------------------------------------------------------*/
110
111   /** Max constant pool string size (65536), minus a bit for padding. */
112   public static final int max_string_size = 65500;
113
114   /** The prefix placed on names that pollute someone else's name space. */
115   public static String JavaDoc prefix = "CUP$";
116
117   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
118
119   /** Package that the resulting code goes into (null is used for unnamed). */
120   public static String JavaDoc package_name = null;
121
122   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
123
124   /** Name of the generated class for symbol constants. */
125   public static String JavaDoc symbol_const_class_name = "sym";
126
127   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
128
129   /** Name of the generated parser class. */
130   public static String JavaDoc parser_class_name = "parser";
131
132   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
133
134   /** Extends and implements declarations for the parser class
135     * (ACM extension) */

136   public static String JavaDoc extendsimpls = "";
137
138   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
139
140   /** User declarations for direct inclusion in user action class. */
141   public static String JavaDoc action_code = null;
142
143   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
144
145   /** User declarations for direct inclusion in parser class. */
146   public static String JavaDoc parser_code = null;
147
148   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
149
150   /** User code for user_init() which is called during parser initialization. */
151   public static String JavaDoc init_code = null;
152
153   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
154
155   /** User code for scan() which is called to get the next Symbol. */
156   public static String JavaDoc scan_code = null;
157
158   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
159
160   /** The start production of the grammar. */
161   public static production start_production = null;
162
163   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
164
165   /** List of imports (Strings containing class names) to go with actions. */
166   public static Stack JavaDoc import_list = new Stack JavaDoc();
167
168   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
169
170   /** Number of conflict found while building tables. */
171   public static int num_conflicts = 0;
172
173   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
174
175   /** Do we skip warnings? */
176   public static boolean nowarn = false;
177
178   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
179
180   /** Count of the number on non-reduced productions found. */
181   public static int not_reduced = 0;
182
183   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
184
185   /** Count of unused terminals. */
186   public static int unused_term = 0;
187
188   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
189
190   /** Count of unused non terminals. */
191   public static int unused_non_term = 0;
192
193   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
194
195   /* Timing values used to produce timing report in main.*/
196
197   /** Time to produce symbol constant class. */
198   public static long symbols_time = 0;
199
200   /** Time to produce parser class. */
201   public static long parser_time = 0;
202
203   /** Time to produce action code class. */
204   public static long action_code_time = 0;
205
206   /** Time to produce the production table. */
207   public static long production_table_time = 0;
208
209   /** Time to produce the action table. */
210   public static long action_table_time = 0;
211
212   /** Time to produce the reduce-goto table. */
213   public static long goto_table_time = 0;
214
215   /* frankf 6/18/96 */
216   protected static boolean _lr_values;
217
218   /** whether or not to emit code for left and right values */
219   public static boolean lr_values() {return _lr_values;}
220   protected static void set_lr_values(boolean b) { _lr_values = b;}
221
222   /*-----------------------------------------------------------*/
223   /*--- General Methods ---------------------------------------*/
224   /*-----------------------------------------------------------*/
225
226   /** Build a string with the standard prefix.
227    * @param str string to prefix.
228    */

229   protected static String JavaDoc pre(String JavaDoc str) {
230     return prefix + parser_class_name + "$" + str;
231   }
232
233   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
234
235   /** Emit a package spec if the user wants one.
236    * @param out stream to produce output on.
237    */

238   protected static void emit_package(PrintWriter JavaDoc out)
239     {
240       /* generate a package spec if we have a name for one */
241       if (package_name != null) {
242     out.println("package " + package_name + ";"); out.println();
243       }
244     }
245
246   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
247
248   /** Emit code for the symbol constant class, optionally including non terms,
249    * if they have been requested.
250    * @param out stream to produce output on.
251    * @param emit_non_terms do we emit constants for non terminals?
252    * @param sym_interface should we emit an interface, rather than a class?
253    */

254   public static void symbols(PrintWriter JavaDoc out,
255                  boolean emit_non_terms, boolean sym_interface)
256     {
257       terminal term;
258       non_terminal nt;
259       String JavaDoc class_or_interface = (sym_interface)?"interface":"class";
260
261       long start_time = System.currentTimeMillis();
262
263       /* top of file */
264       out.println();
265       out.println("//----------------------------------------------------");
266       out.println("// The following code was generated by " +
267                                version.title_str);
268       out.println("// " + new Date JavaDoc());
269       out.println("//----------------------------------------------------");
270       out.println();
271       emit_package(out);
272
273       /* class header */
274       out.println("/** CUP generated " + class_or_interface +
275           " containing symbol constants. */");
276       out.println("public " + class_or_interface + " " +
277           symbol_const_class_name + " {");
278
279       out.println(" /* terminals */");
280
281       /* walk over the terminals */ /* later might sort these */
282       for (Enumeration JavaDoc e = terminal.all(); e.hasMoreElements(); )
283     {
284       term = (terminal)e.nextElement();
285
286       /* output a constant decl for the terminal */
287       out.println(" public static final int " + term.name() + " = " +
288               term.index() + ";");
289     }
290
291       /* do the non terminals if they want them (parser doesn't need them) */
292       if (emit_non_terms)
293     {
294           out.println();
295           out.println(" /* non terminals */");
296
297           /* walk over the non terminals */ /* later might sort these */
298           for (Enumeration JavaDoc e = non_terminal.all(); e.hasMoreElements(); )
299         {
300           nt = (non_terminal)e.nextElement();
301     
302           /* output a constant decl for the terminal */
303           out.println(" static final int " + nt.name() + " = " +
304                   nt.index() + ";");
305         }
306     }
307
308       /* end of class */
309       out.println("}");
310       out.println();
311
312       symbols_time = System.currentTimeMillis() - start_time;
313     }
314
315   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
316
317   /** Emit code for the non-public class holding the actual action code.
318    * @param out stream to produce output on.
319    * @param start_prod the start production of the grammar.
320    * @param max_actions max number of actions per method in generated code
321    */

322   protected static void emit_action_code(PrintWriter JavaDoc out, production start_prod,
323                                          int max_actions)
324     throws internal_error
325     {
326       production prod;
327
328       long start_time = System.currentTimeMillis();
329
330       /* class header */
331       out.println();
332       out.println(
333        "/** Cup generated class to encapsulate user supplied action code.*/"
334       );
335       out.println("class " + pre("actions") + " {");
336
337       /* user supplied code */
338       if (action_code != null)
339     {
340       out.println();
341           out.println(action_code);
342     }
343
344       /* field for parser object */
345       out.println(" private final "+parser_class_name+" parser;");
346
347       /* constructor */
348       out.println();
349       out.println(" /** Constructor */");
350       out.println(" " + pre("actions") + "("+parser_class_name+" parser) {");
351       out.println(" this.parser = parser;");
352       out.println(" }");
353
354       /* action method head */
355       emit_do_action_header(out, "");
356
357       int num_prods = production.number();
358
359       if (num_prods > max_actions) {
360         emit_dispatch_search(out, 0, num_prods-1, max_actions, " ");
361       } else {
362         emit_dispatch_switch(out, 0, num_prods-1, start_prod);
363       }
364
365       /* end of method */
366       out.println(" }");
367
368       if (num_prods > max_actions) {
369         emit_dispatch_methods(out, 0, num_prods-1, max_actions, start_prod);
370       }
371
372       /* end of class */
373       out.println("}");
374       out.println();
375
376       action_code_time = System.currentTimeMillis() - start_time;
377     }
378
379   protected static void emit_do_action_call(PrintWriter JavaDoc out, String JavaDoc suffix)
380     throws internal_error
381     {
382       /* action method head */
383       out.print(pre("do_action" + suffix) + "(");
384       out.print(pre("act_num,"));
385       out.print(pre("parser,"));
386       out.print(pre("stack,"));
387       out.print(pre("top)"));
388     }
389
390   protected static void emit_do_action_header(PrintWriter JavaDoc out, String JavaDoc suffix)
391     throws internal_error
392     {
393       /* action method head */
394       out.println();
395       out.println(" /** Method with the actual generated action code. */");
396       out.println(" public final java_cup.runtime.Symbol " +
397              pre("do_action" + suffix) + "(");
398       out.println(" int " + pre("act_num,"));
399       out.println(" java_cup.runtime.lr_parser " + pre("parser,"));
400       out.println(" java.util.Stack " + pre("stack,"));
401       out.println(" int " + pre("top)"));
402       out.println(" throws java.lang.Exception");
403       out.println(" {");
404
405       /* declaration of result symbol */
406       /* New declaration!! now return Symbol
407         6/13/96 frankf */

408       out.println(" /* Symbol object for return from actions */");
409       out.println(" java_cup.runtime.Symbol " + pre("result") + ";");
410       out.println();
411     }
412
413   protected static void emit_dispatch_search(PrintWriter JavaDoc out, int lo, int hi,
414                                              int max_actions,
415                                              String JavaDoc in)
416     throws internal_error
417     {
418       if (hi - lo + 1 <= max_actions) {
419         out.print(in + "return ");
420         emit_do_action_call(out, "_" + lo);
421         out.println(";");
422       }
423       else {
424         int mid = (lo + hi) / 2;
425         out.println(in + "if (" + pre("act_num") + " <= " + mid + ") {");
426         emit_dispatch_search(out, lo, mid, max_actions, in + " ");
427         out.println(in + "} else {");
428         emit_dispatch_search(out, mid+1, hi, max_actions, in + " ");
429         out.println(in + "}");
430       }
431     }
432
433   protected static void emit_dispatch_methods(PrintWriter JavaDoc out, int lo, int hi,
434                                               int max_actions,
435                                               production start_prod)
436     throws internal_error
437     {
438       if (hi - lo + 1 <= max_actions) {
439         emit_do_action_header(out, "_" + lo);
440         emit_dispatch_switch(out, lo, hi, start_prod);
441         /* end of method */
442         out.println(" }");
443       } else {
444         int mid = (lo + hi) / 2;
445         emit_dispatch_methods(out, lo, mid, max_actions, start_prod);
446         emit_dispatch_methods(out, mid+1, hi, max_actions, start_prod);
447       }
448     }
449
450   protected static void emit_dispatch_switch(PrintWriter JavaDoc out, int lo, int hi,
451                                              production start_prod)
452     throws internal_error
453     {
454       production prod;
455
456       /* switch top */
457       out.println(" /* select the action based on the action number */");
458       out.println(" switch (" + pre("act_num") + ")");
459       out.println(" {");
460
461       /* emit action code for each production as a separate case */
462       for (Enumeration JavaDoc p = production.all(); p.hasMoreElements(); )
463         {
464           prod = (production)p.nextElement();
465
466           if (prod.index() < lo || prod.index() > hi)
467             continue;
468
469           /* case label */
470           out.println(" /*. . . . . . . . . . . . . . . . . . . .*/");
471           out.println(" case " + prod.index() + ": // " +
472                                           prod.to_simple_string());
473
474           emit_production_block(out, prod, start_prod);
475         }
476
477       out.println(" default:");
478       out.println(" {");
479       out.println(" throw new Exception(");
480       out.println(" \"Invalid action number found in " +
481                                     "internal parse table\");");
482       out.println(" }");
483       out.println();
484
485       /* end of switch */
486       out.println(" }");
487     }
488
489   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
490
491   /** Emit code for a single production.
492    * @param out stream to produce output on.
493    * @param prod the production to emit.
494    * @param start_prod the start production of the grammar.
495    */

496   protected static void emit_production_block(PrintWriter JavaDoc out, production prod,
497                                               production start_prod)
498     throws internal_error
499     {
500       /* give them their own block to work in */
501       out.println(" {");
502
503       /* create the result symbol */
504       /*make the variable RESULT which will point to the new Symbol (see below)
505         and be changed by action code
506         6/13/96 frankf */

507       out.println(" " + prod.lhs().the_symbol().stack_type() +
508                   " RESULT = null;");
509
510       /* Add code to propagate RESULT assignments that occur in
511         * action code embedded in a production (ie, non-rightmost
512         * action code). 24-Mar-1998 CSA
513         */

514       for (int i=0; i<prod.rhs_length(); i++) {
515         // only interested in non-terminal symbols.
516
if (!(prod.rhs(i) instanceof symbol_part)) continue;
517         symbol s = ((symbol_part)prod.rhs(i)).the_symbol();
518         if (!(s instanceof non_terminal)) continue;
519         // skip this non-terminal unless it corresponds to
520
// an embedded action production.
521
if (((non_terminal)s).is_embedded_action == false) continue;
522         // OK, it fits. Make a conditional assignment to RESULT.
523
int index = prod.rhs_length() - i - 1; // last rhs is on top.
524
out.println(" " + "// propagate RESULT from " +
525                     s.name());
526         out.println(" " + "if ( " +
527           "((java_cup.runtime.Symbol) " + emit.pre("stack") + ".elementAt("
528           + emit.pre("top") + "-" + index + ")).value != null )");
529         out.println(" " + "RESULT = " +
530           "(" + prod.lhs().the_symbol().stack_type() + ") " +
531           "((java_cup.runtime.Symbol) " + emit.pre("stack") + ".elementAt("
532           + emit.pre("top") + "-" + index + ")).value;");
533       }
534
535     /* if there is an action string, emit it */
536       if (prod.action() != null && prod.action().code_string() != null &&
537           !prod.action().equals(""))
538         out.println(prod.action().code_string());
539
540       /* here we have the left and right values being propagated.
541             must make this a command line option.
542           frankf 6/18/96 */

543
544       /* Create the code that assigns the left and right values of
545         the new Symbol that the production is reducing to */

546       if (emit.lr_values()) {
547         int loffset;
548         String JavaDoc leftstring, rightstring;
549         int roffset = 0;
550         rightstring = "((java_cup.runtime.Symbol)" + emit.pre("stack") + ".elementAt(" +
551           emit.pre("top") + "-" + roffset + ")).right";
552         if (prod.rhs_length() == 0)
553           leftstring = rightstring;
554         else {
555           loffset = prod.rhs_length() - 1;
556           leftstring = "((java_cup.runtime.Symbol)" + emit.pre("stack") + ".elementAt(" +
557             emit.pre("top") + "-" + loffset + ")).left";
558         }
559         out.println(" " + pre("result") + " = new java_cup.runtime.Symbol(" +
560                     prod.lhs().the_symbol().index() + "/*" +
561                     prod.lhs().the_symbol().name() + "*/" +
562                     ", " + leftstring + ", " + rightstring + ", RESULT);");
563       } else {
564         out.println(" " + pre("result") + " = new java_cup.runtime.Symbol(" +
565                     prod.lhs().the_symbol().index() + "/*" +
566                     prod.lhs().the_symbol().name() + "*/" +
567                     ", RESULT);");
568       }
569       
570       /* end of their block */
571       out.println(" }");
572
573       /* if this was the start production, do action for accept */
574       if (prod == start_prod)
575         {
576           out.println(" /* ACCEPT */");
577           out.println(" " + pre("parser") + ".done_parsing();");
578         }
579
580       /* code to return lhs symbol */
581       out.println(" return " + pre("result") + ";");
582       out.println();
583     }
584
585   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
586
587   /** Emit the production table.
588    * @param out stream to produce output on.
589    */

590   protected static void emit_production_table(PrintWriter JavaDoc out)
591     {
592       production all_prods[];
593       production prod;
594
595       long start_time = System.currentTimeMillis();
596
597       /* collect up the productions in order */
598       all_prods = new production[production.number()];
599       for (Enumeration JavaDoc p = production.all(); p.hasMoreElements(); )
600     {
601       prod = (production)p.nextElement();
602       all_prods[prod.index()] = prod;
603     }
604
605       // make short[][]
606
short[][] prod_table = new short[production.number()][2];
607       for (int i = 0; i<production.number(); i++)
608     {
609       prod = all_prods[i];
610       // { lhs symbol , rhs size }
611
prod_table[i][0] = (short) prod.lhs().the_symbol().index();
612       prod_table[i][1] = (short) prod.rhs_length();
613     }
614       /* do the top of the table */
615       out.println();
616       out.println(" /** Production table. */");
617       out.println(" protected static final short _production_table[][] = ");
618       out.print (" unpackFromStrings(");
619       do_table_as_string(out, prod_table);
620       out.println(");");
621
622       /* do the public accessor method */
623       out.println();
624       out.println(" /** Access to production table. */");
625       out.println(" public short[][] production_table() " +
626                          "{return _production_table;}");
627
628       production_table_time = System.currentTimeMillis() - start_time;
629     }
630
631   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
632
633   /** Emit the action table.
634    * @param out stream to produce output on.
635    * @param act_tab the internal representation of the action table.
636    * @param compact_reduces do we use the most frequent reduce as default?
637    * @param max_actions max number of actions per method in generated code
638    */

639   protected static void do_action_table(
640     PrintWriter JavaDoc out,
641     parse_action_table act_tab,
642     boolean compact_reduces,
643     int max_actions)
644     throws internal_error
645     {
646       parse_action_row row;
647       parse_action act;
648       int red;
649
650       long start_time = System.currentTimeMillis();
651
652       /* collect values for the action table */
653       short[][] action_table = new short[act_tab.num_states()][];
654       /* do each state (row) of the action table */
655       for (int i = 0; i < act_tab.num_states(); i++)
656     {
657       /* get the row */
658       row = act_tab.under_state[i];
659
660       /* determine the default for the row */
661       if (compact_reduces)
662         row.compute_default();
663       else
664         row.default_reduce = -1;
665
666       /* make temporary table for the row. */
667       short[] temp_table = new short[2*row.size()];
668       int nentries = 0;
669
670       /* do each column */
671       for (int j = 0; j < row.size(); j++)
672         {
673           /* extract the action from the table */
674           act = row.under_term[j];
675
676           /* skip error entries these are all defaulted out */
677           if (act.kind() != parse_action.ERROR)
678         {
679           /* first put in the symbol index, then the actual entry */
680
681           /* shifts get positive entries of state number + 1 */
682           if (act.kind() == parse_action.SHIFT)
683             {
684               /* make entry */
685               temp_table[nentries++] = (short) j;
686               temp_table[nentries++] = (short)
687             (((shift_action)act).shift_to().index() + 1);
688             }
689
690           /* reduce actions get negated entries of production# + 1 */
691           else if (act.kind() == parse_action.REDUCE)
692             {
693               /* if its the default entry let it get defaulted out */
694               red = ((reduce_action)act).reduce_with().index();
695               if (red != row.default_reduce) {
696             /* make entry */
697             temp_table[nentries++] = (short) j;
698             temp_table[nentries++] = (short) (-(red+1));
699               }
700             } else if (act.kind() == parse_action.NONASSOC)
701               {
702             /* do nothing, since we just want a syntax error */
703               }
704           /* shouldn't be anything else */
705           else
706             throw new internal_error("Unrecognized action code " +
707                          act.kind() + " found in parse table");
708         }
709         }
710
711       /* now we know how big to make the row */
712       action_table[i] = new short[nentries + 2];
713       System.arraycopy(temp_table, 0, action_table[i], 0, nentries);
714
715       /* finish off the row with a default entry */
716       action_table[i][nentries++] = -1;
717       if (row.default_reduce != -1)
718         action_table[i][nentries++] = (short) (-(row.default_reduce+1));
719       else
720         action_table[i][nentries++] = 0;
721     }
722
723       /* finish off the init of the table */
724       out.println();
725       out.println(" /** Parse-action table. */");
726       out.println(" protected static final short[][] _action_table = ");
727       out.print (" unpackFromStrings(");
728       do_table_as_string(out, action_table);
729       out.println(");");
730
731       /* do the public accessor method */
732       out.println();
733       out.println(" /** Access to parse-action table. */");
734       out.println(" public short[][] action_table() {return _action_table;}");
735
736       action_table_time = System.currentTimeMillis() - start_time;
737     }
738
739   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
740
741   /** Emit the reduce-goto table.
742    * @param out stream to produce output on.
743    * @param red_tab the internal representation of the reduce-goto table.
744    */

745   protected static void do_reduce_table(
746     PrintWriter JavaDoc out,
747     parse_reduce_table red_tab)
748     {
749       lalr_state goto_st;
750       parse_action act;
751
752       long start_time = System.currentTimeMillis();
753
754       /* collect values for reduce-goto table */
755       short[][] reduce_goto_table = new short[red_tab.num_states()][];
756       /* do each row of the reduce-goto table */
757       for (int i=0; i<red_tab.num_states(); i++)
758     {
759       /* make temporary table for the row. */
760       short[] temp_table = new short[2*red_tab.under_state[i].size()];
761       int nentries = 0;
762       /* do each entry in the row */
763       for (int j=0; j<red_tab.under_state[i].size(); j++)
764         {
765           /* get the entry */
766           goto_st = red_tab.under_state[i].under_non_term[j];
767
768           /* if we have none, skip it */
769           if (goto_st != null)
770         {
771           /* make entries for the index and the value */
772           temp_table[nentries++] = (short) j;
773           temp_table[nentries++] = (short) goto_st.index();
774         }
775         }
776       /* now we know how big to make the row. */
777       reduce_goto_table[i] = new short[nentries+2];
778       System.arraycopy(temp_table, 0, reduce_goto_table[i], 0, nentries);
779
780       /* end row with default value */
781       reduce_goto_table[i][nentries++] = -1;
782       reduce_goto_table[i][nentries++] = -1;
783     }
784
785       /* emit the table. */
786       out.println();
787       out.println(" /** <code>reduce_goto</code> table. */");
788       out.println(" protected static final short[][] _reduce_table = ");
789       out.print (" unpackFromStrings(");
790       do_table_as_string(out, reduce_goto_table);
791       out.println(");");
792
793       /* do the public accessor method */
794       out.println();
795       out.println(" /** Access to <code>reduce_goto</code> table. */");
796       out.println(" public short[][] reduce_table() {return _reduce_table;}");
797       out.println();
798
799       goto_table_time = System.currentTimeMillis() - start_time;
800     }
801
802   // print a string array encoding the given short[][] array.
803
protected static void do_table_as_string(PrintWriter JavaDoc out, short[][] sa) {
804     out.println("new String[] {");
805     out.print(" \"");
806     int nchar=0, nbytes=0;
807     nbytes+=do_escaped(out, (char)(sa.length>>16));
808     nchar =do_newline(out, nchar, nbytes);
809     if (nbytes > max_string_size) nbytes = 0;
810     nbytes+=do_escaped(out, (char)(sa.length&0xFFFF));
811     nchar =do_newline(out, nchar, nbytes);
812     if (nbytes > max_string_size) nbytes = 0;
813     for (int i=0; i<sa.length; i++) {
814     nbytes+=do_escaped(out, (char)(sa[i].length>>16));
815     nchar =do_newline(out, nchar, nbytes);
816         if (nbytes > max_string_size) nbytes = 0;
817     nbytes+=do_escaped(out, (char)(sa[i].length&0xFFFF));
818     nchar =do_newline(out, nchar, nbytes);
819         if (nbytes > max_string_size) nbytes = 0;
820     for (int j=0; j<sa[i].length; j++) {
821       // contents of string are (value+2) to allow for common -1, 0 cases
822
// (UTF-8 encoding is most efficient for 0<c<0x80)
823
nbytes+=do_escaped(out, (char)(2+sa[i][j]));
824       nchar =do_newline(out, nchar, nbytes);
825           if (nbytes > max_string_size) nbytes = 0;
826     }
827     }
828     out.print("\" }");
829   }
830   // split string if it is very long; start new line occasionally for neatness
831
protected static int do_newline(PrintWriter JavaDoc out, int nchar, int nbytes) {
832     if (nbytes > max_string_size) {
833         out.println("\", "); out.print(" \""); }
834     else if (nchar > 11) { out.println("\" +"); out.print(" \""); }
835     else return nchar+1;
836     return 0;
837   }
838   // output an escape sequence for the given character code.
839
protected static int do_escaped(PrintWriter JavaDoc out, char c) {
840     StringBuffer JavaDoc escape = new StringBuffer JavaDoc();
841     if (c <= 0xFF) {
842       escape.append(Integer.toOctalString(c));
843       while(escape.length() < 3) escape.insert(0, '0');
844     } else {
845       escape.append(Integer.toHexString(c));
846       while(escape.length() < 4) escape.insert(0, '0');
847       escape.insert(0, 'u');
848     }
849     escape.insert(0, '\\');
850     out.print(escape.toString());
851
852     // return number of bytes this takes up in UTF-8 encoding.
853
if (c == 0) return 2;
854     if (c >= 0x01 && c <= 0x7F) return 1;
855     if (c >= 0x80 && c <= 0x7FF) return 2;
856     return 3;
857   }
858
859   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
860
861   /** Emit the parser subclass with embedded tables.
862    * @param out stream to produce output on.
863    * @param action_table internal representation of the action table.
864    * @param reduce_table internal representation of the reduce-goto table.
865    * @param start_st start state of the parse machine.
866    * @param start_prod start production of the grammar.
867    * @param compact_reduces do we use most frequent reduce as default?
868    * @param max_actions max number of actions per method in generated code
869    * @param suppress_scanner should scanner be suppressed for compatibility?
870    */

871   public static void parser(
872     PrintWriter JavaDoc out,
873     parse_action_table action_table,
874     parse_reduce_table reduce_table,
875     int start_st,
876     production start_prod,
877     boolean compact_reduces,
878     int max_actions,
879     boolean suppress_scanner)
880     throws internal_error
881     {
882       long start_time = System.currentTimeMillis();
883
884       /* top of file */
885       out.println();
886       out.println("//----------------------------------------------------");
887       out.println("// The following code was generated by " +
888                             version.title_str);
889       out.println("// " + new Date JavaDoc());
890       out.println("//----------------------------------------------------");
891       out.println();
892       emit_package(out);
893
894       /* user supplied imports */
895       for (int i = 0; i < import_list.size(); i++)
896     out.println("import " + import_list.elementAt(i) + ";");
897
898       /* class header */
899       out.println();
900       out.println("/** "+version.title_str+" generated parser.");
901       out.println(" * @version " + new Date JavaDoc());
902       out.println(" */");
903       out.println("public class " + parser_class_name);
904       if (extendsimpls.equals(""))
905     out.println(" extends java_cup.runtime.lr_parser");
906       else out.println(extendsimpls);
907
908       /* constructors [CSA/davidm, 24-jul-99] */
909     
910       out.println("{");
911       if (extendsimpls.equals("")) {
912         out.println(" /** Default constructor. */");
913     out.println(" public " + parser_class_name + "() {super();}");
914     if (!suppress_scanner) {
915         out.println();
916         out.println(" /** Constructor which sets the default scanner. */");
917         out.println(" public " + parser_class_name +
918             "(java_cup.runtime.Scanner s) {super(s);}");
919     }
920       }
921
922       /* emit the various tables */
923       emit_production_table(out);
924       do_action_table(out, action_table, compact_reduces, max_actions);
925       do_reduce_table(out, reduce_table);
926
927       /* instance of the action encapsulation class */
928       out.println(" /** Instance of action encapsulation class. */");
929       out.println(" protected " + pre("actions") + " action_obj;");
930       out.println();
931
932       /* action object initializer */
933       out.println(" /** Action encapsulation object initializer. */");
934       out.println(" protected void init_actions()");
935       out.println(" {");
936       out.println(" action_obj = new " + pre("actions") + "(this);");
937       out.println(" }");
938       out.println();
939
940       /* access to action code */
941       out.println(" /** Invoke a user supplied parse action. */");
942       out.println(" public java_cup.runtime.Symbol do_action(");
943       out.println(" int act_num,");
944       out.println(" java_cup.runtime.lr_parser parser,");
945       out.println(" java.util.Stack stack,");
946       out.println(" int top)");
947       out.println(" throws java.lang.Exception");
948       out.println(" {");
949       out.println(" /* call code in generated class */");
950       out.println(" return action_obj." + pre("do_action(") +
951                   "act_num, parser, stack, top);");
952       out.println(" }");
953       out.println("");
954
955
956       /* method to tell the parser about the start state */
957       out.println(" /** Indicates start state. */");
958       out.println(" public int start_state() {return " + start_st + ";}");
959
960       /* method to indicate start production */
961       out.println(" /** Indicates start production. */");
962       out.println(" public int start_production() {return " +
963              start_production.index() + ";}");
964       out.println();
965
966       /* methods to indicate EOF and error symbol indexes */
967       out.println(" /** <code>EOF</code> Symbol index. */");
968       out.println(" public int EOF_sym() {return " + terminal.EOF.index() +
969                       ";}");
970       out.println();
971       out.println(" /** <code>error</code> Symbol index. */");
972       out.println(" public int error_sym() {return " + terminal.error.index() +
973                       ";}");
974       out.println();
975
976       /* user supplied code for user_init() */
977       if (init_code != null)
978     {
979           out.println();
980       out.println(" /** User initialization code. */");
981       out.println(" public void user_init() throws java.lang.Exception");
982       out.println(" {");
983       out.println(init_code);
984       out.println(" }");
985     }
986
987       /* user supplied code for scan */
988       if (scan_code != null)
989     {
990           out.println();
991       out.println(" /** Scan to get the next Symbol. */");
992       out.println(" public java_cup.runtime.Symbol scan()");
993       out.println(" throws java.lang.Exception");
994       out.println(" {");
995       out.println(scan_code);
996       out.println(" }");
997     }
998
999       /* user supplied code */
1000      if (parser_code != null)
1001    {
1002      out.println();
1003          out.println(parser_code);
1004    }
1005
1006      /* end of class */
1007      out.println("}");
1008
1009      /* put out the action code class */
1010      emit_action_code(out, start_prod, max_actions);
1011
1012      parser_time = System.currentTimeMillis() - start_time;
1013    }
1014
1015    /*-----------------------------------------------------------*/
1016}
1017
Popular Tags