/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison. */ /* equality comparison, but with different name as Equal because * it's only logical equation. That means that Sets of different length but * padded only with 0's are equal */ public bool equals(BitArray set1, terminal_set set2) { if (set2 == null || set1 == null) { return(false); } else { int max = System.Math.Max(set1.Length, set2._elements.Length); bool[] ar1 = new bool[max]; bool[] ar2 = new bool[max]; set1.CopyTo(ar1, 0); set2._elements.CopyTo(ar2, 0); bool eq = true; for (int i = 0; i < max; i++) { if (ar1[i] != ar2[i]) { eq = false; } } return(eq); } }
/*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Propagate incoming lookaheads through this item to others need to * be changed. * @params incoming symbols to potentially be added to lookahead of this item. */ public void propagate_lookaheads(terminal_set incoming) { bool change = false; /* if we don't need to propagate, then bail out now */ if (!needs_propagation && (incoming == null || incoming.empty())) { return; } /* if we have null incoming, treat as an empty Set */ if (incoming != null) { /* add the incoming to the lookahead of this item */ change = lookahead().add(incoming); } /* if we changed or need it anyway, propagate across our links */ if (change || needs_propagation) { /* don't need to propagate again */ needs_propagation = false; /* propagate our lookahead into each item we are linked to */ IEnumerator myEnum = propagate_items().GetEnumerator(); while (myEnum.MoveNext()) { ((lalr_item)myEnum.Current).propagate_lookaheads(lookahead()); } } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Calculate lookahead representing symbols that could appear after the * symbol that the dot is currently in front of. Note: this routine must * not be invoked before first sets and nullability has been calculated * for all non terminals. */ public terminal_set calc_lookahead(terminal_set lookahead_after) { terminal_set result; int pos; production_part part; symbol sym; /* sanity check */ if (dot_at_end()) { throw new internal_error( "Attempt to calculate a lookahead Set with a completed item"); } /* start with an empty result */ result = new terminal_set(); /* consider all nullable symbols after the one to the right of the dot */ for (pos = dot_pos() + 1; pos < the_production().rhs_length(); pos++) { part = the_production().rhs(pos); /* consider what kind of production part it is -- skip actions */ if (!part.is_action()) { sym = ((symbol_part)part).the_symbol(); /* if its a terminal add it in and we are done */ if (!sym.is_non_term()) { result.add((terminal)sym); return(result); } else { /* otherwise add in first Set of the non terminal */ result.add(((non_terminal)sym).first_set()); /* if its nullable we continue adding, if not, we are done */ if (!((non_terminal)sym).nullable()) { return(result); } } } } /* if we get here everything past the dot was nullable * we add in the lookahead for after the production and we are done */ result.add(lookahead_after); return(result); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this Set intersects another. * @param other the other Set in question. */ public bool intersects(terminal_set other) { not_null(other); /* make a copy of the other Set */ BitArray copy = (BitArray)other._elements.Clone(); /* xor out our values */ copy.Xor(this._elements); /* see if its different */ return(!equals(copy, other)); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add (union) in a complete Set. * @param other the Set being added. * @return true if this changes the Set. */ public bool add(terminal_set other) { not_null(other); /* make a copy */ BitArray copy = (BitArray)_elements.Clone(); /* or in the other Set */ equalize(ref _elements, ref other._elements); _elements.Or(other._elements); /* changed if we are not the same as the copy */ return(!equals(_elements, copy)); }
public bool is_subset_of(terminal_set other) { not_null(other); /* make a copy of the other Set */ BitArray copy_other = (BitArray)other._elements.Clone(); equalize(ref copy_other, ref _elements); /* and or in */ copy_other.Or(_elements); /* if it hasn't changed, we were a subset */ return(equals(copy_other, other)); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this Set is an (improper) superset of another. * @param other the Set we are testing against. */ public bool is_superset_of(terminal_set other) { not_null(other); return(other.is_subset_of(this)); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Produce warning messages for all conflicts found in this state. */ protected void report_conflicts(terminal_set conflict_set) { lalr_item itm, compare; bool after_itm; /* consider each element */ IEnumerator itms = items().all(); while ( itms.MoveNext() ) { itm = (lalr_item)itms.Current; /* clear the S/R conflict Set for this item */ /* if it results in a reduce, it could be a conflict */ if (itm.dot_at_end()) { /* not yet after itm */ after_itm = false; /* compare this item against all others looking for conflicts */ IEnumerator comps = items().all(); while (comps.MoveNext() ) { compare = (lalr_item)comps.Current; /* if this is the item, next one is after it */ if (itm == compare) after_itm = true; /* only look at it if its not the same item */ if (itm != compare) { /* is it a reduce */ if (compare.dot_at_end()) { /* only look at reduces after itm */ if (after_itm) /* does the comparison item conflict? */ if (compare.lookahead().intersects(itm.lookahead())) /* report a reduce/reduce conflict */ report_reduce_reduce(itm, compare); } } } /* report S/R conflicts under all the symbols we conflict under */ for (int t = 0; t < terminal.number(); t++) if (conflict_set.contains(t)) report_shift_reduce(itm,t); } } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor with default position (dot at start). * @param prod the production for the item. * @param look the Set of lookahead symbols. */ public lalr_item(production prod, terminal_set look) : this(prod, 0, look) { // this(prod,0,look); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor with default position (dot at start). * @param prod the production for the item. * @param look the Set of lookahead symbols. */ public lalr_item(production prod, terminal_set look) : this(prod,0,look) { // this(prod,0,look); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add (union) in a complete Set. * @param other the Set being added. * @return true if this changes the Set. */ public bool add(terminal_set other) { not_null(other); /* make a copy */ BitArray copy = (BitArray)_elements.Clone(); /* or in the other Set */ equalize(ref _elements,ref other._elements); _elements.Or(other._elements); /* changed if we are not the same as the copy */ return !equals(_elements,copy); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** 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); } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Produce warning messages for all conflicts found in this state. */ protected void report_conflicts(terminal_set conflict_set) { lalr_item itm, compare; bool after_itm; /* consider each element */ IEnumerator itms = items().all(); while (itms.MoveNext()) { itm = (lalr_item)itms.Current; /* clear the S/R conflict Set for this item */ /* if it results in a reduce, it could be a conflict */ if (itm.dot_at_end()) { /* not yet after itm */ after_itm = false; /* compare this item against all others looking for conflicts */ IEnumerator comps = items().all(); while (comps.MoveNext()) { compare = (lalr_item)comps.Current; /* if this is the item, next one is after it */ if (itm == compare) { after_itm = true; } /* only look at it if its not the same item */ if (itm != compare) { /* is it a reduce */ if (compare.dot_at_end()) { /* only look at reduces after itm */ if (after_itm) { /* does the comparison item conflict? */ if (compare.lookahead().intersects(itm.lookahead())) { /* report a reduce/reduce conflict */ report_reduce_reduce(itm, compare); } } } } } /* report S/R conflicts under all the symbols we conflict under */ for (int t = 0; t < terminal.number(); t++) { if (conflict_set.contains(t)) { report_shift_reduce(itm, t); } } } } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor for cloning from another Set. * @param other the Set we are cloning from. */ public terminal_set(terminal_set other) { not_null(other); _elements = (BitArray)other._elements.Clone(); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison. */ /* equality comparison, but with different name as Equal because * it's only logical equation. That means that Sets of different length but * padded only with 0's are equal */ public bool equals(BitArray set1,terminal_set set2) { if (set2 == null||set1==null) return false; else { int max=System.Math.Max(set1.Length,set2._elements.Length); bool[] ar1=new bool[max]; bool[] ar2=new bool[max]; set1.CopyTo(ar1,0); set2._elements.CopyTo(ar2,0); bool eq=true; for (int i=0;i<max;i++) if (ar1[i]!=ar2[i]) eq=false; return eq; } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this Set intersects another. * @param other the other Set in question. */ public bool intersects(terminal_set other) { not_null(other); /* make a copy of the other Set */ BitArray copy = (BitArray)other._elements.Clone(); /* xor out our values */ copy.Xor(this._elements); /* see if its different */ return !equals(copy,other); }
public bool is_subset_of(terminal_set other) { not_null(other); /* make a copy of the other Set */ BitArray copy_other = (BitArray)other._elements.Clone(); equalize(ref copy_other,ref _elements); /* and or in */ copy_other.Or(_elements); /* if it hasn't changed, we were a subset */ return equals(copy_other,other); }
/*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Propagate incoming lookaheads through this item to others need to * be changed. * @params incoming symbols to potentially be added to lookahead of this item. */ public void propagate_lookaheads(terminal_set incoming) { bool change = false; /* if we don't need to propagate, then bail out now */ if (!needs_propagation && (incoming == null || incoming.empty())) return; /* if we have null incoming, treat as an empty Set */ if (incoming != null) { /* add the incoming to the lookahead of this item */ change = lookahead().add(incoming); } /* if we changed or need it anyway, propagate across our links */ if (change || needs_propagation) { /* don't need to propagate again */ needs_propagation = false; /* propagate our lookahead into each item we are linked to */ IEnumerator myEnum= propagate_items().GetEnumerator(); while (myEnum.MoveNext()) ((lalr_item)myEnum.Current).propagate_lookaheads(lookahead()); } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this Set is an (improper) superset of another. * @param other the Set we are testing against. */ public bool is_superset_of(terminal_set other) { not_null(other); return other.is_subset_of(this); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Calculate lookahead representing symbols that could appear after the * symbol that the dot is currently in front of. Note: this routine must * not be invoked before first sets and nullability has been calculated * for all non terminals. */ public terminal_set calc_lookahead(terminal_set lookahead_after) { terminal_set result; int pos; production_part part; symbol sym; /* sanity check */ if (dot_at_end()) throw new internal_error( "Attempt to calculate a lookahead Set with a completed item"); /* start with an empty result */ result = new terminal_set(); /* consider all nullable symbols after the one to the right of the dot */ for (pos = dot_pos()+1; pos < the_production().rhs_length(); pos++) { part = the_production().rhs(pos); /* consider what kind of production part it is -- skip actions */ if (!part.is_action()) { sym = ((symbol_part)part).the_symbol(); /* if its a terminal add it in and we are done */ if (!sym.is_non_term()) { result.add((terminal)sym); return result; } else { /* otherwise add in first Set of the non terminal */ result.add(((non_terminal)sym).first_set()); /* if its nullable we continue adding, if not, we are done */ if (!((non_terminal)sym).nullable()) return result; } } } /* if we get here everything past the dot was nullable we add in the lookahead for after the production and we are done */ result.add(lookahead_after); return result; }
/*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. * @param prod the production for the item. * @param pos the position of the "dot" within the production. * @param look the Set of lookahead symbols. */ public lalr_item(production prod, int pos, terminal_set look) : base(prod, pos) { _lookahead = look; _propagate_items = new Stack(); needs_propagation = true; }
/*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. * @param prod the production for the item. * @param pos the position of the "dot" within the production. * @param look the Set of lookahead symbols. */ public lalr_item(production prod, int pos, terminal_set look) : base(prod,pos) { _lookahead = look; _propagate_items = new Stack(); needs_propagation = true; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** 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); }