/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Emit the reduce-goto table. * @param out stream to produce output on. * @param red_tab the internal representation of the reduce-goto table. */ protected static void do_reduce_table( TextWriter cout, parse_reduce_table red_tab) { lalr_state goto_st; long start_time = DateTime.Now.Ticks; /* collect values for reduce-goto table */ short[][] reduce_goto_table = new short[red_tab.num_states()][]; /* do each row of the reduce-goto table */ for (int i = 0; i < red_tab.num_states(); i++) { /* make temporary table for the row. */ short[] temp_table = new short[2 * parse_reduce_row.size()]; int nentries = 0; /* do each entry in the row */ for (int j = 0; j < parse_reduce_row.size(); j++) { /* get the entry */ goto_st = red_tab.under_state[i].under_non_term[j]; /* if we have none, skip it */ if (goto_st != null) { /* make entries for the index and the value */ temp_table[nentries++] = (short)j; temp_table[nentries++] = (short)goto_st.index(); } } /* now we know how big to make the row. */ reduce_goto_table[i] = new short[nentries + 2]; Array.Copy(temp_table, reduce_goto_table[i], nentries); /* end row with default value */ reduce_goto_table[i][nentries++] = -1; reduce_goto_table[i][nentries++] = -1; } /* emit the table. */ cout.WriteLine(); cout.WriteLine(" /** <code>reduce_goto</code> table. */"); cout.WriteLine(" protected static readonly short[][] _reduce_table = "); cout.Write(" unpackFromStrings("); do_table_as_string(cout, reduce_goto_table); cout.WriteLine(");"); /* do the public accessor method */ cout.WriteLine(); cout.WriteLine(" /** Access to <code>reduce_goto</code> table. */"); cout.WriteLine(" public override short[][] reduce_table() {return _reduce_table;}"); cout.WriteLine(); goto_table_time = DateTime.Now.Ticks - start_time; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Build the (internal) parser from the previously parsed specification. * This includes:<ul> * <li> Computing nullability of non-terminals. * <li> Computing first sets of non-terminals and productions. * <li> Building the viable prefix recognizer machine. * <li> Filling in the (internal) parse tables. * <li> Checking for unreduced productions. * </ul> */ protected static void build_parser() { /* compute nullability of all non terminals */ if (opt_do_debug || print_progress) System.Console.Error.WriteLine(" Computing non-terminal nullability..."); non_terminal.compute_nullability(); nullability_end = DateTime.Now.Ticks; /* compute first sets of all non terminals */ if (opt_do_debug || print_progress) System.Console.Error.WriteLine(" Computing first sets..."); non_terminal.compute_first_sets(); first_end = DateTime.Now.Ticks; /* build the LR viable prefix recognition machine */ if (opt_do_debug || print_progress) System.Console.Error.WriteLine(" Building state machine..."); start_state = lalr_state.build_machine(emit.start_production); machine_end = DateTime.Now.Ticks; /* build the LR parser action and reduce-goto tables */ if (opt_do_debug || print_progress) System.Console.Error.WriteLine(" Filling in tables..."); action_table = new parse_action_table(); reduce_table = new parse_reduce_table(); IEnumerator st = lalr_state.all(); while ( st.MoveNext() ) { lalr_state lst = (lalr_state)st.Current; lst.build_table_entries( action_table, reduce_table); } table_end = DateTime.Now.Ticks; /* check and warn for non-reduced productions */ if (opt_do_debug || print_progress) System.Console.Error.WriteLine(" Checking for non-reduced productions..."); action_table.check_reductions(); reduce_check_end = DateTime.Now.Ticks; /* if we have more conflicts than we expected issue a message and die */ if (emit.num_conflicts > expect_conflicts) { System.Console.Error.WriteLine("*** More conflicts encountered than expected " + "-- parser generation aborted"); lexer.error_count++; // indicate the problem. // we'll die on return, after clean up. } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Emit the parser subclass with embedded tables. * @param out stream to produce output on. * @param action_table internal representation of the action table. * @param reduce_table internal representation of the reduce-goto table. * @param start_st start state of the parse machine. * @param start_prod start production of the grammar. * @param compact_reduces do we use most frequent reduce as default? * @param suppress_scanner should scanner be suppressed for compatibility? */ public static void parser( TextWriter cout, parse_action_table action_table, parse_reduce_table reduce_table, int start_st, production start_prod, bool compact_reduces, bool suppress_scanner) { long start_time = DateTime.Now.Ticks; /* top of file */ cout.WriteLine(); cout.WriteLine("//----------------------------------------------------"); cout.WriteLine("// The following code was generated by " + version.title_str); cout.WriteLine("// " + DateTime.Now); cout.WriteLine("//----------------------------------------------------"); cout.WriteLine(); emit_package(cout); /* user supplied imports */ IEnumerator myEnum= import_list.GetEnumerator(); while (myEnum.MoveNext()) cout.WriteLine("using " + myEnum.Current.ToString() + ";"); /* class header */ cout.WriteLine(); cout.WriteLine("/** "+version.title_str+" generated parser."); cout.WriteLine(" * @version " + DateTime.Now); cout.WriteLine(" */"); cout.WriteLine("public class " + parser_class_name + " : TUVienna.CS_CUP.Runtime.lr_parser {"); /* constructors [CSA/davidm, 24-jul-99] */ cout.WriteLine(); cout.WriteLine(" /** Default constructor. */"); cout.WriteLine(" public " + parser_class_name + "():base() {;}"); if (!suppress_scanner) { cout.WriteLine(); cout.WriteLine(" /** Constructor which sets the default scanner. */"); cout.WriteLine(" public " + parser_class_name + "(TUVienna.CS_CUP.Runtime.Scanner s): base(s) {;}"); } /* emit the various tables */ emit_production_table(cout); do_action_table(cout, action_table, compact_reduces); do_reduce_table(cout, reduce_table); /* instance of the action encapsulation class */ cout.WriteLine(" /** Instance of action encapsulation class. */"); cout.WriteLine(" protected " + pre("actions") + " action_obj;"); cout.WriteLine(); /* action object initializer */ cout.WriteLine(" /** Action encapsulation object initializer. */"); cout.WriteLine(" protected override void init_actions()"); cout.WriteLine(" {"); cout.WriteLine(" action_obj = new " + pre("actions") + "(this);"); cout.WriteLine(" }"); cout.WriteLine(); /* access to action code */ cout.WriteLine(" /** Invoke a user supplied parse action. */"); cout.WriteLine(" public override TUVienna.CS_CUP.Runtime.Symbol do_action("); cout.WriteLine(" int act_num,"); cout.WriteLine(" TUVienna.CS_CUP.Runtime.lr_parser parser,"); cout.WriteLine(" System.Collections.Stack xstack1,"); cout.WriteLine(" int top)"); cout.WriteLine(" {"); cout.WriteLine(" mStack CUP_parser_stack= new mStack(xstack1);"); cout.WriteLine(" /* call code in generated class */"); cout.WriteLine(" return action_obj." + pre("do_action(") + "act_num, parser, stack, top);"); cout.WriteLine(" }"); cout.WriteLine(""); /* method to tell the parser about the start state */ cout.WriteLine(" /** Indicates start state. */"); cout.WriteLine(" public override int start_state() {return " + start_st + ";}"); /* method to indicate start production */ cout.WriteLine(" /** Indicates start production. */"); cout.WriteLine(" public override int start_production() {return " + start_production.index() + ";}"); cout.WriteLine(); /* methods to indicate EOF and error symbol indexes */ cout.WriteLine(" /** <code>EOF</code> Symbol index. */"); cout.WriteLine(" public override int EOF_sym() {return " + terminal.EOF.index() + ";}"); cout.WriteLine(); cout.WriteLine(" /** <code>error</code> Symbol index. */"); cout.WriteLine(" public override int error_sym() {return " + terminal.error.index() + ";}"); cout.WriteLine(); /* user supplied code for user_init() */ if (init_code != null) { cout.WriteLine(); cout.WriteLine(" /** User initialization code. */"); cout.WriteLine(" public override void user_init() "); cout.WriteLine(" {"); cout.WriteLine(init_code); cout.WriteLine(" }"); } /* user supplied code for scan */ if (scan_code != null) { cout.WriteLine(); cout.WriteLine(" /** Scan to get the next Symbol. */"); cout.WriteLine(" public override TUVienna.CS_CUP.Runtime.Symbol scan()"); cout.WriteLine(" {"); cout.WriteLine(scan_code); cout.WriteLine(" }"); } /* user supplied code */ if (parser_code != null) { cout.WriteLine(); cout.WriteLine(parser_code); } /* end of class */ cout.WriteLine("}"); /* put out the action code class */ emit_action_code(cout, start_prod); if (package_name!=null) cout.WriteLine("}"); parser_time = DateTime.Now.Ticks - start_time; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Emit the reduce-goto table. * @param out stream to produce output on. * @param red_tab the internal representation of the reduce-goto table. */ protected static void do_reduce_table( TextWriter cout, parse_reduce_table red_tab) { lalr_state goto_st; long start_time = DateTime.Now.Ticks; /* collect values for reduce-goto table */ short[][] reduce_goto_table = new short[red_tab.num_states()][]; /* do each row of the reduce-goto table */ for (int i=0; i<red_tab.num_states(); i++) { /* make temporary table for the row. */ short[] temp_table = new short[2*parse_reduce_row.size()]; int nentries = 0; /* do each entry in the row */ for (int j=0; j<parse_reduce_row.size(); j++) { /* get the entry */ goto_st = red_tab.under_state[i].under_non_term[j]; /* if we have none, skip it */ if (goto_st != null) { /* make entries for the index and the value */ temp_table[nentries++] = (short) j; temp_table[nentries++] = (short) goto_st.index(); } } /* now we know how big to make the row. */ reduce_goto_table[i] = new short[nentries+2]; Array.Copy(temp_table, reduce_goto_table[i], nentries); /* end row with default value */ reduce_goto_table[i][nentries++] = -1; reduce_goto_table[i][nentries++] = -1; } /* emit the table. */ cout.WriteLine(); cout.WriteLine(" /** <code>reduce_goto</code> table. */"); cout.WriteLine(" protected static readonly short[][] _reduce_table = "); cout.Write (" unpackFromStrings("); do_table_as_string(cout, reduce_goto_table); cout.WriteLine(");"); /* do the public accessor method */ cout.WriteLine(); cout.WriteLine(" /** Access to <code>reduce_goto</code> table. */"); cout.WriteLine(" public override short[][] reduce_table() {return _reduce_table;}"); cout.WriteLine(); goto_table_time = DateTime.Now.Ticks - start_time; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Emit the parser subclass with embedded tables. * @param out stream to produce output on. * @param action_table internal representation of the action table. * @param reduce_table internal representation of the reduce-goto table. * @param start_st start state of the parse machine. * @param start_prod start production of the grammar. * @param compact_reduces do we use most frequent reduce as default? * @param suppress_scanner should scanner be suppressed for compatibility? */ public static void parser( TextWriter cout, parse_action_table action_table, parse_reduce_table reduce_table, int start_st, production start_prod, bool compact_reduces, bool suppress_scanner) { long start_time = DateTime.Now.Ticks; /* top of file */ cout.WriteLine(); cout.WriteLine("//----------------------------------------------------"); cout.WriteLine("// The following code was generated by " + version.title_str); cout.WriteLine("// " + DateTime.Now); cout.WriteLine("//----------------------------------------------------"); cout.WriteLine(); emit_package(cout); /* user supplied imports */ IEnumerator myEnum = import_list.GetEnumerator(); while (myEnum.MoveNext()) { cout.WriteLine("using " + myEnum.Current.ToString() + ";"); } /* class header */ cout.WriteLine(); cout.WriteLine("/** " + version.title_str + " generated parser."); cout.WriteLine(" * @version " + DateTime.Now); cout.WriteLine(" */"); cout.WriteLine("public class " + parser_class_name + " : TUVienna.CS_CUP.Runtime.lr_parser {"); /* constructors [CSA/davidm, 24-jul-99] */ cout.WriteLine(); cout.WriteLine(" /** Default constructor. */"); cout.WriteLine(" public " + parser_class_name + "():base() {;}"); if (!suppress_scanner) { cout.WriteLine(); cout.WriteLine(" /** Constructor which sets the default scanner. */"); cout.WriteLine(" public " + parser_class_name + "(TUVienna.CS_CUP.Runtime.Scanner s): base(s) {;}"); } /* emit the various tables */ emit_production_table(cout); do_action_table(cout, action_table, compact_reduces); do_reduce_table(cout, reduce_table); /* instance of the action encapsulation class */ cout.WriteLine(" /** Instance of action encapsulation class. */"); cout.WriteLine(" protected " + pre("actions") + " action_obj;"); cout.WriteLine(); /* action object initializer */ cout.WriteLine(" /** Action encapsulation object initializer. */"); cout.WriteLine(" protected override void init_actions()"); cout.WriteLine(" {"); cout.WriteLine(" action_obj = new " + pre("actions") + "(this);"); cout.WriteLine(" }"); cout.WriteLine(); /* access to action code */ cout.WriteLine(" /** Invoke a user supplied parse action. */"); cout.WriteLine(" public override TUVienna.CS_CUP.Runtime.Symbol do_action("); cout.WriteLine(" int act_num,"); cout.WriteLine(" TUVienna.CS_CUP.Runtime.lr_parser parser,"); cout.WriteLine(" System.Collections.Stack xstack1,"); cout.WriteLine(" int top)"); cout.WriteLine(" {"); cout.WriteLine(" mStack CUP_parser_stack= new mStack(xstack1);"); cout.WriteLine(" /* call code in generated class */"); cout.WriteLine(" return action_obj." + pre("do_action(") + "act_num, parser, stack, top);"); cout.WriteLine(" }"); cout.WriteLine(""); /* method to tell the parser about the start state */ cout.WriteLine(" /** Indicates start state. */"); cout.WriteLine(" public override int start_state() {return " + start_st + ";}"); /* method to indicate start production */ cout.WriteLine(" /** Indicates start production. */"); cout.WriteLine(" public override int start_production() {return " + start_production.index() + ";}"); cout.WriteLine(); /* methods to indicate EOF and error symbol indexes */ cout.WriteLine(" /** <code>EOF</code> Symbol index. */"); cout.WriteLine(" public override int EOF_sym() {return " + terminal.EOF.index() + ";}"); cout.WriteLine(); cout.WriteLine(" /** <code>error</code> Symbol index. */"); cout.WriteLine(" public override int error_sym() {return " + terminal.error.index() + ";}"); cout.WriteLine(); /* user supplied code for user_init() */ if (init_code != null) { cout.WriteLine(); cout.WriteLine(" /** User initialization code. */"); cout.WriteLine(" public override void user_init() "); cout.WriteLine(" {"); cout.WriteLine(init_code); cout.WriteLine(" }"); } /* user supplied code for scan */ if (scan_code != null) { cout.WriteLine(); cout.WriteLine(" /** Scan to get the next Symbol. */"); cout.WriteLine(" public override TUVienna.CS_CUP.Runtime.Symbol scan()"); cout.WriteLine(" {"); cout.WriteLine(scan_code); cout.WriteLine(" }"); } /* user supplied code */ if (parser_code != null) { cout.WriteLine(); cout.WriteLine(parser_code); } /* end of class */ cout.WriteLine("}"); /* put out the action code class */ emit_action_code(cout, start_prod); if (package_name != null) { cout.WriteLine("}"); } parser_time = DateTime.Now.Ticks - start_time; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fill in the parse table entries for this state. There are two * parse tables that encode the viable prefix recognition machine, an * action table and a reduce-goto table. The rows in each table * correspond to states of the machine. The columns of the action table * are indexed by terminal symbols and correspond to either transitions * out of the state (shift entries) or reductions from the state to some * previous state saved on the stack (reduce entries). All entries in the * action table that are not shifts or reduces, represent errors. The * reduce-goto table is indexed by non terminals and represents transitions * out of a state on that non-terminal.<p> * Conflicts occur if more than one action needs to go in one entry of the * action table (this cannot happen with the reduce-goto table). Conflicts * are resolved by always shifting for shift/reduce conflicts and choosing * the lowest numbered production (hence the one that appeared first in * the specification) in reduce/reduce conflicts. All conflicts are * reported and if more conflicts are detected than were declared by the * user, code generation is aborted. * * @param act_table the action table to put entries in. * @param reduce_table the reduce-goto table to put entries in. */ public void build_table_entries( parse_action_table act_table, parse_reduce_table reduce_table) { parse_action_row our_act_row; parse_reduce_row our_red_row; lalr_item itm; parse_action act, other_act; symbol sym; terminal_set conflict_set = new terminal_set(); /* pull out our rows from the tables */ our_act_row = act_table.under_state[index()]; our_red_row = reduce_table.under_state[index()]; /* consider each item in our state */ IEnumerator i = items().all(); while (i.MoveNext()) { itm = (lalr_item)i.Current; /* if its completed (dot at end) then reduce under the lookahead */ if (itm.dot_at_end()) { act = new reduce_action(itm.the_production()); /* consider each lookahead symbol */ for (int t = 0; t < terminal.number(); t++) { /* skip over the ones not in the lookahead */ if (!itm.lookahead().contains(t)) { continue; } /* if we don't already have an action put this one in */ if (our_act_row.under_term[t].kind() == parse_action.ERROR) { our_act_row.under_term[t] = act; } else { /* we now have at least one conflict */ terminal term = terminal.find(t); other_act = our_act_row.under_term[t]; /* if the other act was not a shift */ if ((other_act.kind() != parse_action.SHIFT) && (other_act.kind() != parse_action.NONASSOC)) { /* if we have lower index hence priority, replace it*/ if (itm.the_production().index() < ((reduce_action)other_act).reduce_with().index()) { /* replace the action */ our_act_row.under_term[t] = act; } } else { /* Check precedences,see if problem is correctable */ if (fix_with_precedence(itm.the_production(), t, our_act_row, act)) { term = null; } } if (term != null) { conflict_set.add(term); } } } } } /* consider each outgoing transition */ for (lalr_transition trans = transitions(); trans != null; trans = trans.next()) { /* if its on an terminal add a shift entry */ sym = trans.on_symbol(); if (!sym.is_non_term()) { act = new shift_action(trans.to_state()); /* if we don't already have an action put this one in */ if (our_act_row.under_term[sym.index()].kind() == parse_action.ERROR) { our_act_row.under_term[sym.index()] = act; } else { /* we now have at least one conflict */ production p = ((reduce_action)our_act_row.under_term[sym.index()]).reduce_with(); /* shift always wins */ if (!fix_with_precedence(p, sym.index(), our_act_row, act)) { our_act_row.under_term[sym.index()] = act; conflict_set.add(terminal.find(sym.index())); } } } else { /* for non terminals add an entry to the reduce-goto table */ our_red_row.under_non_term[sym.index()] = trans.to_state(); } } /* if we end up with conflict(s), report them */ if (!conflict_set.empty()) { report_conflicts(conflict_set); } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fill in the parse table entries for this state. There are two * parse tables that encode the viable prefix recognition machine, an * action table and a reduce-goto table. The rows in each table * correspond to states of the machine. The columns of the action table * are indexed by terminal symbols and correspond to either transitions * out of the state (shift entries) or reductions from the state to some * previous state saved on the stack (reduce entries). All entries in the * action table that are not shifts or reduces, represent errors. The * reduce-goto table is indexed by non terminals and represents transitions * out of a state on that non-terminal.<p> * Conflicts occur if more than one action needs to go in one entry of the * action table (this cannot happen with the reduce-goto table). Conflicts * are resolved by always shifting for shift/reduce conflicts and choosing * the lowest numbered production (hence the one that appeared first in * the specification) in reduce/reduce conflicts. All conflicts are * reported and if more conflicts are detected than were declared by the * user, code generation is aborted. * * @param act_table the action table to put entries in. * @param reduce_table the reduce-goto table to put entries in. */ public void build_table_entries( parse_action_table act_table, parse_reduce_table reduce_table) { parse_action_row our_act_row; parse_reduce_row our_red_row; lalr_item itm; parse_action act, other_act; symbol sym; terminal_set conflict_set = new terminal_set(); /* pull out our rows from the tables */ our_act_row = act_table.under_state[index()]; our_red_row = reduce_table.under_state[index()]; /* consider each item in our state */ IEnumerator i = items().all(); while ( i.MoveNext() ) { itm = (lalr_item)i.Current; /* if its completed (dot at end) then reduce under the lookahead */ if (itm.dot_at_end()) { act = new reduce_action(itm.the_production()); /* consider each lookahead symbol */ for (int t = 0; t < terminal.number(); t++) { /* skip over the ones not in the lookahead */ if (!itm.lookahead().contains(t)) continue; /* if we don't already have an action put this one in */ if (our_act_row.under_term[t].kind() == parse_action.ERROR) { our_act_row.under_term[t] = act; } else { /* we now have at least one conflict */ terminal term = terminal.find(t); other_act = our_act_row.under_term[t]; /* if the other act was not a shift */ if ((other_act.kind() != parse_action.SHIFT) && (other_act.kind() != parse_action.NONASSOC)) { /* if we have lower index hence priority, replace it*/ if (itm.the_production().index() < ((reduce_action)other_act).reduce_with().index()) { /* replace the action */ our_act_row.under_term[t] = act; } } else { /* Check precedences,see if problem is correctable */ if(fix_with_precedence(itm.the_production(), t, our_act_row, act)) { term = null; } } if(term!=null) { conflict_set.add(term); } } } } } /* consider each outgoing transition */ for (lalr_transition trans=transitions(); trans!=null; trans=trans.next()) { /* if its on an terminal add a shift entry */ sym = trans.on_symbol(); if (!sym.is_non_term()) { act = new shift_action(trans.to_state()); /* if we don't already have an action put this one in */ if ( our_act_row.under_term[sym.index()].kind() == parse_action.ERROR) { our_act_row.under_term[sym.index()] = act; } else { /* we now have at least one conflict */ production p = ((reduce_action)our_act_row.under_term[sym.index()]).reduce_with(); /* shift always wins */ if (!fix_with_precedence(p, sym.index(), our_act_row, act)) { our_act_row.under_term[sym.index()] = act; conflict_set.add(terminal.find(sym.index())); } } } else { /* for non terminals add an entry to the reduce-goto table */ our_red_row.under_non_term[sym.index()] = trans.to_state(); } } /* if we end up with conflict(s), report them */ if (!conflict_set.empty()) report_conflicts(conflict_set); }