has a hack on java_cup parser generator: divides a gigantic do_action method into...
[IRC.git] / Robust / cup / java_cup / emit.java
1 package java_cup;
2
3 import java.io.PrintWriter;
4 import java.util.ArrayList;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Set;
9 import java.util.Stack;
10 import java.util.Enumeration;
11 import java.util.Date;
12
13 /** 
14  * This class handles emitting generated code for the resulting parser.
15  * The various parse tables must be constructed, etc. before calling any 
16  * routines in this class.<p>  
17  *
18  * Three classes are produced by this code:
19  *   <dl>
20  *   <dt> symbol constant class
21  *   <dd>   this contains constant declarations for each terminal (and 
22  *          optionally each non-terminal).
23  *   <dt> action class
24  *   <dd>   this non-public class contains code to invoke all the user actions 
25  *          that were embedded in the parser specification.
26  *   <dt> parser class
27  *   <dd>   the specialized parser class consisting primarily of some user 
28  *          supplied general and initialization code, and the parse tables.
29  *   </dl><p>
30  *
31  *  Three parse tables are created as part of the parser class:
32  *    <dl>
33  *    <dt> production table
34  *    <dd>   lists the LHS non terminal number, and the length of the RHS of 
35  *           each production.
36  *    <dt> action table
37  *    <dd>   for each state of the parse machine, gives the action to be taken
38  *           (shift, reduce, or error) under each lookahead symbol.<br>
39  *    <dt> reduce-goto table
40  *    <dd>   when a reduce on a given production is taken, the parse stack is 
41  *           popped back a number of elements corresponding to the RHS of the 
42  *           production.  This reveals a prior state, which we transition out 
43  *           of under the LHS non terminal symbol for the production (as if we
44  *           had seen the LHS symbol rather than all the symbols matching the 
45  *           RHS).  This table is indexed by non terminal numbers and indicates 
46  *           how to make these transitions. 
47  *    </dl><p>
48  * 
49  * In addition to the method interface, this class maintains a series of 
50  * public global variables and flags indicating how misc. parts of the code 
51  * and other output is to be produced, and counting things such as number of 
52  * conflicts detected (see the source code and public variables below for
53  * more details).<p> 
54  *
55  * This class is "static" (contains only static data and methods).<p> 
56  *
57  * @see java_cup.main
58  * @version last update: 11/25/95
59  * @author Scott Hudson
60  */
61
62 /* Major externally callable routines here include:
63      symbols               - emit the symbol constant class 
64      parser                - emit the parser class
65
66    In addition the following major internal routines are provided:
67      emit_package          - emit a package declaration
68      emit_action_code      - emit the class containing the user's actions 
69      emit_production_table - emit declaration and init for the production table
70      do_action_table       - emit declaration and init for the action table
71      do_reduce_table       - emit declaration and init for the reduce-goto table
72
73    Finally, this class uses a number of public instance variables to communicate
74    optional parameters and flags used to control how code is generated,
75    as well as to report counts of various things (such as number of conflicts
76    detected).  These include:
77
78    prefix                  - a prefix string used to prefix names that would 
79                              otherwise "pollute" someone else's name space.
80    package_name            - name of the package emitted code is placed in 
81                              (or null for an unnamed package.
82    symbol_const_class_name - name of the class containing symbol constants.
83    parser_class_name       - name of the class for the resulting parser.
84    action_code             - user supplied declarations and other code to be 
85                              placed in action class.
86    parser_code             - user supplied declarations and other code to be 
87                              placed in parser class.
88    init_code               - user supplied code to be executed as the parser 
89                              is being initialized.
90    scan_code               - user supplied code to get the next Symbol.
91    start_production        - the start production for the grammar.
92    import_list             - list of imports for use with action class.
93    num_conflicts           - number of conflicts detected. 
94    nowarn                  - true if we are not to issue warning messages.
95    not_reduced             - count of number of productions that never reduce.
96    unused_term             - count of unused terminal symbols.
97    unused_non_term         - count of unused non terminal symbols.
98    *_time                  - a series of symbols indicating how long various
99                              sub-parts of code generation took (used to produce
100                              optional time reports in main).
101 */
102
103 public class emit {
104
105   /*-----------------------------------------------------------*/
106   /*--- Constructor(s) ----------------------------------------*/
107   /*-----------------------------------------------------------*/
108
109   /** Only constructor is private so no instances can be created. */
110   private emit() { }
111
112   /*-----------------------------------------------------------*/
113   /*--- Static (Class) Variables ------------------------------*/
114   /*-----------------------------------------------------------*/
115
116   /** The prefix placed on names that pollute someone else's name space. */
117   public static String prefix = "CUP$";
118
119   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
120
121   /** Package that the resulting code goes into (null is used for unnamed). */
122   public static String package_name = null;
123
124   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
125
126   /** Name of the generated class for symbol constants. */
127   public static String symbol_const_class_name = "sym";
128
129   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
130
131   /** Name of the generated parser class. */
132   public static String parser_class_name = "parser";
133
134   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
135
136   /** User declarations for direct inclusion in user action class. */
137   public static String action_code = null;
138
139   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
140
141   /** User declarations for direct inclusion in parser class. */
142   public static String parser_code = null;
143
144   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
145
146   /** User code for user_init() which is called during parser initialization. */
147   public static String init_code = null;
148
149   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
150
151   /** User code for scan() which is called to get the next Symbol. */
152   public static String scan_code = null;
153
154   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
155
156   /** The start production of the grammar. */
157   public static production start_production = null;
158
159   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
160
161   /** List of imports (Strings containing class names) to go with actions. */
162   public static Stack import_list = new Stack();
163
164   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
165
166   /** Number of conflict found while building tables. */
167   public static int num_conflicts = 0;
168
169   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
170
171   /** Do we skip warnings? */
172   public static boolean nowarn = false;
173
174   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
175
176   /** Count of the number on non-reduced productions found. */
177   public static int not_reduced = 0;
178
179   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
180
181   /** Count of unused terminals. */
182   public static int unused_term = 0;
183
184   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
185
186   /** Count of unused non terminals. */
187   public static int unused_non_term = 0;
188
189   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
190
191   /* Timing values used to produce timing report in main.*/
192
193   /** Time to produce symbol constant class. */
194   public static long symbols_time          = 0;
195
196   /** Time to produce parser class. */
197   public static long parser_time           = 0;
198
199   /** Time to produce action code class. */
200   public static long action_code_time      = 0;
201
202   /** Time to produce the production table. */
203   public static long production_table_time = 0;
204
205   /** Time to produce the action table. */
206   public static long action_table_time     = 0;
207
208   /** Time to produce the reduce-goto table. */
209   public static long goto_table_time       = 0;
210
211   /* frankf 6/18/96 */
212   protected static boolean _lr_values;
213
214   /** whether or not to emit code for left and right values */
215   public static boolean lr_values() {return _lr_values;}
216   protected static void set_lr_values(boolean b) { _lr_values = b;}
217
218   /*-----------------------------------------------------------*/
219   /*--- General Methods ---------------------------------------*/
220   /*-----------------------------------------------------------*/
221
222   /** Build a string with the standard prefix. 
223    * @param str string to prefix.
224    */
225   protected static String pre(String str) {
226     return prefix + parser_class_name + "$" + str;
227   }
228
229   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
230
231   /** Emit a package spec if the user wants one. 
232    * @param out stream to produce output on.
233    */
234   protected static void emit_package(PrintWriter out)
235     {
236       /* generate a package spec if we have a name for one */
237       if (package_name != null) {
238         out.println("package " + package_name + ";"); out.println();
239       }
240     }
241
242   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
243
244   /** Emit code for the symbol constant class, optionally including non terms,
245    *  if they have been requested.  
246    * @param out            stream to produce output on.
247    * @param emit_non_terms do we emit constants for non terminals?
248    * @param sym_interface  should we emit an interface, rather than a class?
249    */
250   public static void symbols(PrintWriter out, 
251                              boolean emit_non_terms, boolean sym_interface)
252     {
253       terminal term;
254       non_terminal nt;
255       String class_or_interface = (sym_interface)?"interface":"class";
256
257       long start_time = System.currentTimeMillis();
258
259       /* top of file */
260       out.println();
261       out.println("//----------------------------------------------------"); 
262       out.println("// The following code was generated by " + 
263                                                            version.title_str);
264       out.println("// " + new Date());
265       out.println("//----------------------------------------------------"); 
266       out.println();
267       emit_package(out);
268
269       /* class header */
270       out.println("/** CUP generated " + class_or_interface + 
271                   " containing symbol constants. */");
272       out.println("public " + class_or_interface + " " + 
273                   symbol_const_class_name + " {");
274
275       out.println("  /* terminals */");
276
277       /* walk over the terminals */              /* later might sort these */
278       for (Enumeration e = terminal.all(); e.hasMoreElements(); )
279         {
280           term = (terminal)e.nextElement();
281
282           /* output a constant decl for the terminal */
283           out.println("  public static final int " + term.name() + " = " + 
284                       term.index() + ";");
285         }
286
287       /* do the non terminals if they want them (parser doesn't need them) */
288       if (emit_non_terms)
289         {
290           out.println();
291           out.println("  /* non terminals */");
292
293           /* walk over the non terminals */       /* later might sort these */
294           for (Enumeration e = non_terminal.all(); e.hasMoreElements(); )
295             {
296               nt = (non_terminal)e.nextElement();
297     
298               /* output a constant decl for the terminal */
299               out.println("  static final int " + nt.name() + " = " + 
300                           nt.index() + ";");
301             }
302         }
303
304       /* end of class */
305       out.println("}");
306       out.println();
307
308       symbols_time = System.currentTimeMillis() - start_time;
309     }
310
311   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
312
313   /** Emit code for the non-public class holding the actual action code. 
314    * @param out        stream to produce output on.
315    * @param start_prod the start production of the grammar.
316    */
317   protected static void emit_action_code(PrintWriter out, production start_prod)
318     throws internal_error
319     {
320       long start_time = System.currentTimeMillis();
321
322       /* class header */
323       out.println();
324       out.println(
325        "/** Cup generated class to encapsulate user supplied action code.*/"
326       );  
327       out.println("class " +  pre("actions") + " {");
328
329       /* user supplied code */
330       if (action_code != null)
331         {
332           out.println();
333           out.println(action_code);
334         }
335
336       /* field for parser object */
337       out.println("  private final "+parser_class_name+" parser;");
338
339       /* constructor */
340       out.println();
341       out.println("  /** Constructor */");
342       out.println("  " + pre("actions") + "("+parser_class_name+" parser) {");
343       out.println("    this.parser = parser;");
344       out.println("  }");
345
346       /* action method head */
347       out.println();
348       out.println("  /** Method with the actual generated action code. */");
349       out.println("  public final java_cup.runtime.Symbol " + 
350                      pre("do_action") + "(");
351       out.println("    int                        " + pre("act_num,"));
352       out.println("    java_cup.runtime.lr_parser " + pre("parser,"));
353       out.println("    java.util.Stack            " + pre("stack,"));
354       out.println("    int                        " + pre("top)"));
355       out.println("    throws java.lang.Exception");
356       out.println("    {");
357
358       /* declaration of result symbol */
359       /* New declaration!! now return Symbol
360          6/13/96 frankf */
361       out.println("      /* Symbol object for return from actions */");
362       out.println("      java_cup.runtime.Symbol " + pre("result") + ";");
363       out.println();
364
365       // hack: divide a production table into halves and generates two methods of switch cases
366       // since we have an issue with Java 64K size limitation.      
367       int median=production.number()/2;   
368       // divide production table 
369       List firsthalf=new ArrayList();
370       List secondhalf=new ArrayList();
371       for(int i=0;i<median;i++){
372         firsthalf.add(production.find(i));
373       }      
374       for(int i=median;i<production.number();i++){
375         secondhalf.add(production.find(i));
376       }   
377       
378       // invoke emit_switch_code
379       out.println("    if("+pre("act_num")+" < "+median+" )");
380       out.println("       "+pre("result=")+pre("do_action")+"_1("+ pre("act_num,") +pre("parser,")+ pre("stack,")+ pre("top)")+";");
381       out.println("    else");
382       out.println("       "+pre("result=")+pre("do_action")+"_2("+ pre("act_num,") +pre("parser,") +pre("stack,")+ pre("top)")+";");
383       
384       out.println();
385       out.println("     return "+pre("result")+";");
386       out.println("     }");
387       out.println();
388       
389       emit_switch_code(1,out,start_prod,firsthalf);      
390       emit_switch_code(2,out,start_prod,secondhalf);
391       
392       /* end of class */
393       out.println("}");
394       out.println();
395       
396       action_code_time = System.currentTimeMillis() - start_time;
397     }
398   
399   protected static void emit_switch_code(int funcIdx, PrintWriter out, production start_prod, List prodList)   throws internal_error{
400    
401
402     out.println("  /** Method with the generated switch code. */");
403     out.println("  public final java_cup.runtime.Symbol " + 
404        pre("do_action")+"_"+funcIdx + "(");
405     out.println("    int                        " + pre("act_num,"));
406     out.println("    java_cup.runtime.lr_parser " + pre("parser,"));
407     out.println("    java.util.Stack            " + pre("stack,"));
408     out.println("    int                        " + pre("top)"));
409     out.println("    throws java.lang.Exception");
410     out.println("    {");
411     
412     out.println("      /* Symbol object for return from actions */");
413     out.println("      java_cup.runtime.Symbol " + pre("result") + ";");
414     out.println();
415     
416     production prod;
417
418       /* switch top */
419       out.println("      /* select the action based on the action number */");
420       out.println("      switch (" + pre("act_num") + ")");
421       out.println("        {");
422
423       /* emit action code for each production as a separate case */
424  for (Iterator iterator = prodList.iterator(); iterator.hasNext();) {
425      prod = (production) iterator.next();
426
427           /* case label */
428           out.println("          /*. . . . . . . . . . . . . . . . . . . .*/");
429           out.println("          case " + prod.index() + ": // " + 
430                                           prod.to_simple_string());
431
432           /* give them their own block to work in */
433           out.println("            {");
434
435           /* create the result symbol */
436           /*make the variable RESULT which will point to the new Symbol (see below)
437             and be changed by action code
438             6/13/96 frankf */
439           out.println("              " +  prod.lhs().the_symbol().stack_type() +
440                       " RESULT = null;");
441
442           /* Add code to propagate RESULT assignments that occur in
443            * action code embedded in a production (ie, non-rightmost
444            * action code). 24-Mar-1998 CSA
445            */
446           for (int i=0; i<prod.rhs_length(); i++) {
447             // only interested in non-terminal symbols.
448             if (!(prod.rhs(i) instanceof symbol_part)) continue;
449             symbol s = ((symbol_part)prod.rhs(i)).the_symbol();
450             if (!(s instanceof non_terminal)) continue;
451             // skip this non-terminal unless it corresponds to
452             // an embedded action production.
453             if (((non_terminal)s).is_embedded_action == false) continue;
454             // OK, it fits.  Make a conditional assignment to RESULT.
455             int index = prod.rhs_length() - i - 1; // last rhs is on top.
456             out.println("              " + "// propagate RESULT from " +
457                         s.name());
458             out.println("              " + "if ( " +
459               "((java_cup.runtime.Symbol) " + emit.pre("stack") + ".elementAt("
460               + emit.pre("top") + "-" + index + ")).value != null )");
461             out.println("                " + "RESULT = " +
462               "(" + prod.lhs().the_symbol().stack_type() + ") " +
463               "((java_cup.runtime.Symbol) " + emit.pre("stack") + ".elementAt("
464               + emit.pre("top") + "-" + index + ")).value;");
465           }
466
467         /* if there is an action string, emit it */
468           if (prod.action() != null && prod.action().code_string() != null &&
469               !prod.action().equals(""))
470             out.println(prod.action().code_string());
471
472           /* here we have the left and right values being propagated.  
473                 must make this a command line option.
474              frankf 6/18/96 */
475
476          /* Create the code that assigns the left and right values of
477             the new Symbol that the production is reducing to */
478           if (emit.lr_values()) {           
479             int loffset;
480             String leftstring, rightstring;
481             int roffset = 0;
482             rightstring = "((java_cup.runtime.Symbol)" + emit.pre("stack") + ".elementAt(" + 
483               emit.pre("top") + "-" + roffset + ")).right";       
484             if (prod.rhs_length() == 0) 
485               leftstring = rightstring;
486             else {
487               loffset = prod.rhs_length() - 1;
488               leftstring = "((java_cup.runtime.Symbol)" + emit.pre("stack") + ".elementAt(" + 
489                 emit.pre("top") + "-" + loffset + ")).left";      
490             }
491             out.println("              " + pre("result") + " = new java_cup.runtime.Symbol(" + 
492                         prod.lhs().the_symbol().index() + "/*" +
493                         prod.lhs().the_symbol().name() + "*/" + 
494                         ", " + leftstring + ", " + rightstring + ", RESULT);");
495           } else {
496             out.println("              " + pre("result") + " = new java_cup.runtime.Symbol(" + 
497                         prod.lhs().the_symbol().index() + "/*" +
498                         prod.lhs().the_symbol().name() + "*/" + 
499                         ", RESULT);");
500           }
501           
502           /* end of their block */
503           out.println("            }");
504
505           /* if this was the start production, do action for accept */
506           if (prod == start_prod)
507             {
508               out.println("          /* ACCEPT */");
509               out.println("          " + pre("parser") + ".done_parsing();");
510             }
511
512           /* code to return lhs symbol */
513           out.println("          return " + pre("result") + ";");
514           out.println();
515         }
516
517       /* end of switch */
518       out.println("          /* . . . . . .*/");
519       out.println("          default:");
520       out.println("            throw new Exception(");
521       out.println("               \"Invalid action number found in " +
522                                   "internal parse table\");");
523       out.println();
524       out.println("        }");
525       
526       /* end of method */
527       out.println("    }");
528
529     }
530
531   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
532
533   /** Emit the production table. 
534    * @param out stream to produce output on.
535    */
536   protected static void emit_production_table(PrintWriter out)
537     {
538       production all_prods[];
539       production prod;
540
541       long start_time = System.currentTimeMillis();
542
543       /* collect up the productions in order */
544       all_prods = new production[production.number()];
545       for (Enumeration p = production.all(); p.hasMoreElements(); )
546         {
547           prod = (production)p.nextElement();
548           all_prods[prod.index()] = prod;
549         }
550
551       // make short[][]
552       short[][] prod_table = new short[production.number()][2];
553       for (int i = 0; i<production.number(); i++)
554         {
555           prod = all_prods[i];
556           // { lhs symbol , rhs size }
557           prod_table[i][0] = (short) prod.lhs().the_symbol().index();
558           prod_table[i][1] = (short) prod.rhs_length();
559         }
560       /* do the top of the table */
561       out.println();
562       out.println("  /** Production table. */");
563       out.println("  protected static final short _production_table[][] = ");
564       out.print  ("    unpackFromStrings(");
565       do_table_as_string(out, prod_table);
566       out.println(");");
567
568       /* do the public accessor method */
569       out.println();
570       out.println("  /** Access to production table. */");
571       out.println("  public short[][] production_table() " + 
572                                                  "{return _production_table;}");
573
574       production_table_time = System.currentTimeMillis() - start_time;
575     }
576
577   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
578
579   /** Emit the action table. 
580    * @param out             stream to produce output on.
581    * @param act_tab         the internal representation of the action table.
582    * @param compact_reduces do we use the most frequent reduce as default?
583    */
584   protected static void do_action_table(
585     PrintWriter        out, 
586     parse_action_table act_tab,
587     boolean            compact_reduces)
588     throws internal_error
589     {
590       parse_action_row row;
591       parse_action     act;
592       int              red;
593
594       long start_time = System.currentTimeMillis();
595
596       /* collect values for the action table */
597       short[][] action_table = new short[act_tab.num_states()][];
598       /* do each state (row) of the action table */
599       for (int i = 0; i < act_tab.num_states(); i++)
600         {
601           /* get the row */
602           row = act_tab.under_state[i];
603
604           /* determine the default for the row */
605           if (compact_reduces)
606             row.compute_default();
607           else
608             row.default_reduce = -1;
609
610           /* make temporary table for the row. */
611           short[] temp_table = new short[2*row.size()];
612           int nentries = 0;
613
614           /* do each column */
615           for (int j = 0; j < row.size(); j++)
616             {
617               /* extract the action from the table */
618               act = row.under_term[j];
619
620               /* skip error entries these are all defaulted out */
621               if (act.kind() != parse_action.ERROR)
622                 {
623                   /* first put in the symbol index, then the actual entry */
624
625                   /* shifts get positive entries of state number + 1 */
626                   if (act.kind() == parse_action.SHIFT)
627                     {
628                       /* make entry */
629                       temp_table[nentries++] = (short) j;
630                       temp_table[nentries++] = (short)
631                         (((shift_action)act).shift_to().index() + 1);
632                     }
633
634                   /* reduce actions get negated entries of production# + 1 */
635                   else if (act.kind() == parse_action.REDUCE)
636                     {
637                       /* if its the default entry let it get defaulted out */
638                       red = ((reduce_action)act).reduce_with().index();
639                       if (red != row.default_reduce) {
640                         /* make entry */
641                         temp_table[nentries++] = (short) j;
642                         temp_table[nentries++] = (short) (-(red+1));
643                       }
644                     } else if (act.kind() == parse_action.NONASSOC)
645                       {
646                         /* do nothing, since we just want a syntax error */
647                       }
648                   /* shouldn't be anything else */
649                   else
650                     throw new internal_error("Unrecognized action code " + 
651                                              act.kind() + " found in parse table");
652                 }
653             }
654
655           /* now we know how big to make the row */
656           action_table[i] = new short[nentries + 2];
657           System.arraycopy(temp_table, 0, action_table[i], 0, nentries);
658
659           /* finish off the row with a default entry */
660           action_table[i][nentries++] = -1;
661           if (row.default_reduce != -1)
662             action_table[i][nentries++] = (short) (-(row.default_reduce+1));
663           else
664             action_table[i][nentries++] = 0;
665         }
666
667       /* finish off the init of the table */
668       out.println();
669       out.println("  /** Parse-action table. */");
670       out.println("  protected static final short[][] _action_table = "); 
671       out.print  ("    unpackFromStrings(");
672       do_table_as_string(out, action_table);
673       out.println(");");
674
675       /* do the public accessor method */
676       out.println();
677       out.println("  /** Access to parse-action table. */");
678       out.println("  public short[][] action_table() {return _action_table;}");
679
680       action_table_time = System.currentTimeMillis() - start_time;
681     }
682
683   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
684
685   /** Emit the reduce-goto table. 
686    * @param out     stream to produce output on.
687    * @param red_tab the internal representation of the reduce-goto table.
688    */
689   protected static void do_reduce_table(
690     PrintWriter out, 
691     parse_reduce_table red_tab)
692     {
693       lalr_state       goto_st;
694       parse_action     act;
695
696       long start_time = System.currentTimeMillis();
697
698       /* collect values for reduce-goto table */
699       short[][] reduce_goto_table = new short[red_tab.num_states()][];
700       /* do each row of the reduce-goto table */
701       for (int i=0; i<red_tab.num_states(); i++)
702         {
703           /* make temporary table for the row. */
704           short[] temp_table = new short[2*red_tab.under_state[i].size()];
705           int nentries = 0;
706           /* do each entry in the row */
707           for (int j=0; j<red_tab.under_state[i].size(); j++)
708             {
709               /* get the entry */
710               goto_st = red_tab.under_state[i].under_non_term[j];
711
712               /* if we have none, skip it */
713               if (goto_st != null)
714                 {
715                   /* make entries for the index and the value */
716                   temp_table[nentries++] = (short) j;
717                   temp_table[nentries++] = (short) goto_st.index();
718                 }
719             }
720           /* now we know how big to make the row. */
721           reduce_goto_table[i] = new short[nentries+2];
722           System.arraycopy(temp_table, 0, reduce_goto_table[i], 0, nentries);
723
724           /* end row with default value */
725           reduce_goto_table[i][nentries++] = -1;
726           reduce_goto_table[i][nentries++] = -1;
727         }
728
729       /* emit the table. */
730       out.println();
731       out.println("  /** <code>reduce_goto</code> table. */");
732       out.println("  protected static final short[][] _reduce_table = "); 
733       out.print  ("    unpackFromStrings(");
734       do_table_as_string(out, reduce_goto_table);
735       out.println(");");
736
737       /* do the public accessor method */
738       out.println();
739       out.println("  /** Access to <code>reduce_goto</code> table. */");
740       out.println("  public short[][] reduce_table() {return _reduce_table;}");
741       out.println();
742
743       goto_table_time = System.currentTimeMillis() - start_time;
744     }
745
746   // print a string array encoding the given short[][] array.
747   protected static void do_table_as_string(PrintWriter out, short[][] sa) {
748     out.println("new String[] {");
749     out.print("    \"");
750     int nchar=0, nbytes=0;
751     nbytes+=do_escaped(out, (char)(sa.length>>16));
752     nchar  =do_newline(out, nchar, nbytes);
753     nbytes+=do_escaped(out, (char)(sa.length&0xFFFF));
754     nchar  =do_newline(out, nchar, nbytes);
755     for (int i=0; i<sa.length; i++) {
756         nbytes+=do_escaped(out, (char)(sa[i].length>>16));
757         nchar  =do_newline(out, nchar, nbytes);
758         nbytes+=do_escaped(out, (char)(sa[i].length&0xFFFF));
759         nchar  =do_newline(out, nchar, nbytes);
760         for (int j=0; j<sa[i].length; j++) {
761           // contents of string are (value+2) to allow for common -1, 0 cases
762           // (UTF-8 encoding is most efficient for 0<c<0x80)
763           nbytes+=do_escaped(out, (char)(2+sa[i][j]));
764           nchar  =do_newline(out, nchar, nbytes);
765         }
766     }
767     out.print("\" }");
768   }
769   // split string if it is very long; start new line occasionally for neatness
770   protected static int do_newline(PrintWriter out, int nchar, int nbytes) {
771     if (nbytes > 65500)  { out.println("\", "); out.print("    \""); }
772     else if (nchar > 11) { out.println("\" +"); out.print("    \""); }
773     else return nchar+1;
774     return 0;
775   }
776   // output an escape sequence for the given character code.
777   protected static int do_escaped(PrintWriter out, char c) {
778     StringBuffer escape = new StringBuffer();
779     if (c <= 0xFF) {
780       escape.append(Integer.toOctalString(c));
781       while(escape.length() < 3) escape.insert(0, '0');
782     } else {
783       escape.append(Integer.toHexString(c));
784       while(escape.length() < 4) escape.insert(0, '0');
785       escape.insert(0, 'u');
786     }
787     escape.insert(0, '\\');
788     out.print(escape.toString());
789
790     // return number of bytes this takes up in UTF-8 encoding.
791     if (c == 0) return 2;
792     if (c >= 0x01 && c <= 0x7F) return 1;
793     if (c >= 0x80 && c <= 0x7FF) return 2;
794     return 3;
795   }
796
797   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
798
799   /** Emit the parser subclass with embedded tables. 
800    * @param out             stream to produce output on.
801    * @param action_table    internal representation of the action table.
802    * @param reduce_table    internal representation of the reduce-goto table.
803    * @param start_st        start state of the parse machine.
804    * @param start_prod      start production of the grammar.
805    * @param compact_reduces do we use most frequent reduce as default?
806    * @param suppress_scanner should scanner be suppressed for compatibility?
807    */
808   public static void parser(
809     PrintWriter        out, 
810     parse_action_table action_table,
811     parse_reduce_table reduce_table,
812     int                start_st,
813     production         start_prod,
814     boolean            compact_reduces,
815     boolean            suppress_scanner)
816     throws internal_error
817     {
818       long start_time = System.currentTimeMillis();
819
820       /* top of file */
821       out.println();
822       out.println("//----------------------------------------------------"); 
823       out.println("// The following code was generated by " + 
824                                                         version.title_str);
825       out.println("// " + new Date());
826       out.println("//----------------------------------------------------"); 
827       out.println();
828       emit_package(out);
829
830       /* user supplied imports */
831       for (int i = 0; i < import_list.size(); i++)
832         out.println("import " + import_list.elementAt(i) + ";");
833
834       /* class header */
835       out.println();
836       out.println("/** "+version.title_str+" generated parser.");
837       out.println("  * @version " + new Date());
838       out.println("  */");
839       out.println("public class " + parser_class_name + 
840                   " extends java_cup.runtime.lr_parser {");
841
842       /* constructors [CSA/davidm, 24-jul-99] */
843       out.println();
844       out.println("  /** Default constructor. */");
845       out.println("  public " + parser_class_name + "() {super();}");
846       if (!suppress_scanner) {
847           out.println();
848           out.println("  /** Constructor which sets the default scanner. */");
849           out.println("  public " + parser_class_name + 
850                       "(java_cup.runtime.Scanner s) {super(s);}");
851       }
852
853       /* emit the various tables */
854       emit_production_table(out);
855       do_action_table(out, action_table, compact_reduces);
856       do_reduce_table(out, reduce_table);
857
858       /* instance of the action encapsulation class */
859       out.println("  /** Instance of action encapsulation class. */");
860       out.println("  protected " + pre("actions") + " action_obj;");
861       out.println();
862
863       /* action object initializer */
864       out.println("  /** Action encapsulation object initializer. */");
865       out.println("  protected void init_actions()");
866       out.println("    {");
867       out.println("      action_obj = new " + pre("actions") + "(this);");
868       out.println("    }");
869       out.println();
870
871       /* access to action code */
872       out.println("  /** Invoke a user supplied parse action. */");
873       out.println("  public java_cup.runtime.Symbol do_action(");
874       out.println("    int                        act_num,");
875       out.println("    java_cup.runtime.lr_parser parser,");
876       out.println("    java.util.Stack            stack,");
877       out.println("    int                        top)");
878       out.println("    throws java.lang.Exception");
879       out.println("  {");
880       out.println("    /* call code in generated class */");
881       out.println("    return action_obj." + pre("do_action(") +
882                   "act_num, parser, stack, top);");
883       out.println("  }");
884       out.println("");
885
886
887       /* method to tell the parser about the start state */
888       out.println("  /** Indicates start state. */");
889       out.println("  public int start_state() {return " + start_st + ";}");
890
891       /* method to indicate start production */
892       out.println("  /** Indicates start production. */");
893       out.println("  public int start_production() {return " + 
894                      start_production.index() + ";}");
895       out.println();
896
897       /* methods to indicate EOF and error symbol indexes */
898       out.println("  /** <code>EOF</code> Symbol index. */");
899       out.println("  public int EOF_sym() {return " + terminal.EOF.index() + 
900                                           ";}");
901       out.println();
902       out.println("  /** <code>error</code> Symbol index. */");
903       out.println("  public int error_sym() {return " + terminal.error.index() +
904                                           ";}");
905       out.println();
906
907       /* user supplied code for user_init() */
908       if (init_code != null)
909         {
910           out.println();
911           out.println("  /** User initialization code. */");
912           out.println("  public void user_init() throws java.lang.Exception");
913           out.println("    {");
914           out.println(init_code);
915           out.println("    }");
916         }
917
918       /* user supplied code for scan */
919       if (scan_code != null)
920         {
921           out.println();
922           out.println("  /** Scan to get the next Symbol. */");
923           out.println("  public java_cup.runtime.Symbol scan()");
924           out.println("    throws java.lang.Exception");
925           out.println("    {");
926           out.println(scan_code);
927           out.println("    }");
928         }
929
930       /* user supplied code */
931       if (parser_code != null)
932         {
933           out.println();
934           out.println(parser_code);
935         }
936
937       /* end of class */
938       out.println("}");
939
940       /* put out the action code class */
941       emit_action_code(out, start_prod);
942
943       parser_time = System.currentTimeMillis() - start_time;
944     }
945
946     /*-----------------------------------------------------------*/
947 }