/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** 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 action table. * @param out stream to produce output on. * @param act_tab the internal representation of the action table. * @param compact_reduces do we use the most frequent reduce as default? */ protected static void do_action_table( TextWriter cout, parse_action_table act_tab, bool compact_reduces) { parse_action_row row; parse_action act; int red; long start_time = DateTime.Now.Ticks; /* collect values for the action table */ short[][] action_table = new short[act_tab.num_states()][]; /* do each state (row) of the action table */ for (int i = 0; i < act_tab.num_states(); i++) { /* get the row */ row = act_tab.under_state[i]; /* determine the default for the row */ if (compact_reduces) row.compute_default(); else row.default_reduce = -1; /* make temporary table for the row. */ short[] temp_table = new short[2*parse_action_row.size()]; int nentries = 0; /* do each column */ for (int j = 0; j < parse_action_row.size(); j++) { /* extract the action from the table */ act = row.under_term[j]; /* skip error entries these are all defaulted out */ if (act.kind() != parse_action.ERROR) { /* first put in the symbol index, then the actual entry */ /* shifts get positive entries of state number + 1 */ if (act.kind() == parse_action.SHIFT) { /* make entry */ temp_table[nentries++] = (short) j; temp_table[nentries++] = (short) (((shift_action)act).shift_to().index() + 1); } /* reduce actions get negated entries of production# + 1 */ else if (act.kind() == parse_action.REDUCE) { /* if its the default entry let it get defaulted out */ red = ((reduce_action)act).reduce_with().index(); if (red != row.default_reduce) { /* make entry */ temp_table[nentries++] = (short) j; temp_table[nentries++] = (short) (-(red+1)); } } else if (act.kind() == parse_action.NONASSOC) { /* do nothing, since we just want a syntax error */ } /* shouldn't be anything else */ else throw new internal_error("Unrecognized action code " + act.kind() + " found in parse table"); } } /* now we know how big to make the row */ action_table[i] = new short[nentries + 2]; //System.arraycopy(temp_table, 0, action_table[i], 0, nentries); Array.Copy(temp_table,action_table[i],nentries); /* finish off the row with a default entry */ action_table[i][nentries++] = -1; if (row.default_reduce != -1) action_table[i][nentries++] = (short) (-(row.default_reduce+1)); else action_table[i][nentries++] = 0; } /* finish off the init of the table */ cout.WriteLine(); cout.WriteLine(" /** Parse-action table. */"); cout.WriteLine(" protected static readonly short[][] _action_table = "); cout.Write (" unpackFromStrings("); do_table_as_string(cout, action_table); cout.WriteLine(");"); /* do the public accessor method */ cout.WriteLine(); cout.WriteLine(" /** Access to parse-action table. */"); cout.WriteLine(" public override short[][] action_table() {return _action_table;}"); action_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; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Emit the action table. * @param out stream to produce output on. * @param act_tab the internal representation of the action table. * @param compact_reduces do we use the most frequent reduce as default? */ protected static void do_action_table( TextWriter cout, parse_action_table act_tab, bool compact_reduces) { parse_action_row row; parse_action act; int red; long start_time = DateTime.Now.Ticks; /* collect values for the action table */ short[][] action_table = new short[act_tab.num_states()][]; /* do each state (row) of the action table */ for (int i = 0; i < act_tab.num_states(); i++) { /* get the row */ row = act_tab.under_state[i]; /* determine the default for the row */ if (compact_reduces) { row.compute_default(); } else { row.default_reduce = -1; } /* make temporary table for the row. */ short[] temp_table = new short[2 * parse_action_row.size()]; int nentries = 0; /* do each column */ for (int j = 0; j < parse_action_row.size(); j++) { /* extract the action from the table */ act = row.under_term[j]; /* skip error entries these are all defaulted out */ if (act.kind() != parse_action.ERROR) { /* first put in the symbol index, then the actual entry */ /* shifts get positive entries of state number + 1 */ if (act.kind() == parse_action.SHIFT) { /* make entry */ temp_table[nentries++] = (short)j; temp_table[nentries++] = (short) (((shift_action)act).shift_to().index() + 1); } /* reduce actions get negated entries of production# + 1 */ else if (act.kind() == parse_action.REDUCE) { /* if its the default entry let it get defaulted out */ red = ((reduce_action)act).reduce_with().index(); if (red != row.default_reduce) { /* make entry */ temp_table[nentries++] = (short)j; temp_table[nentries++] = (short)(-(red + 1)); } } else if (act.kind() == parse_action.NONASSOC) { /* do nothing, since we just want a syntax error */ } /* shouldn't be anything else */ else { throw new internal_error("Unrecognized action code " + act.kind() + " found in parse table"); } } } /* now we know how big to make the row */ action_table[i] = new short[nentries + 2]; //System.arraycopy(temp_table, 0, action_table[i], 0, nentries); Array.Copy(temp_table, action_table[i], nentries); /* finish off the row with a default entry */ action_table[i][nentries++] = -1; if (row.default_reduce != -1) { action_table[i][nentries++] = (short)(-(row.default_reduce + 1)); } else { action_table[i][nentries++] = 0; } } /* finish off the init of the table */ cout.WriteLine(); cout.WriteLine(" /** Parse-action table. */"); cout.WriteLine(" protected static readonly short[][] _action_table = "); cout.Write(" unpackFromStrings("); do_table_as_string(cout, action_table); cout.WriteLine(");"); /* do the public accessor method */ cout.WriteLine(); cout.WriteLine(" /** Access to parse-action table. */"); cout.WriteLine(" public override short[][] action_table() {return _action_table;}"); action_table_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); }