/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /// <summary>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. /// </summary> public virtual 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); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /// <summary>Update (and return) the first set based on current NT firsts. /// This assumes that nullability has already been computed for all non /// terminals and productions. /// </summary> public virtual terminal_set check_first_set() { int part; symbol sym; /* walk down the right hand side till we get past all nullables */ for (part = 0; part < rhs_length(); part++) { /* only look at non-actions */ if (!rhs(part).is_action()) { sym = ((symbol_part)rhs(part)).the_symbol(); /* is it a non-terminal?*/ if (sym.is_non_term()) { /* add in current firsts from that NT */ _first_set.add(((non_terminal)sym).first_set()); /* if its not nullable, we are done */ if (!((non_terminal)sym).nullable()) { break; } } else { /* its a terminal -- add that to the set */ _first_set.add((terminal)sym); /* we are done */ break; } } } /* return our updated first set */ return(first_set()); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /// <summary>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. /// </summary> public virtual 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; }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /// <summary>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. /// * /// </summary> /// <param name="act_table"> the action table to put entries in. /// </param> /// <param name="reduce_table">the reduce-goto table to put entries in. /// /// </param> public virtual 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 */ //UPGRADE_TODO: method 'java.util.Enumeration.hasMoreElements' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationhasMoreElements"' for (System.Collections.IEnumerator i = items().all(); i.MoveNext(); ) { //UPGRADE_TODO: method 'java.util.Enumeration.nextElement' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationnextElement"' 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); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /// <summary>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. /// * /// </summary> /// <param name="act_table"> the action table to put entries in. /// </param> /// <param name="reduce_table">the reduce-goto table to put entries in. /// /// </param> public virtual 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 */ //UPGRADE_TODO: method 'java.util.Enumeration.hasMoreElements' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationhasMoreElements"' for (System.Collections.IEnumerator i = items().all(); i.MoveNext();) { //UPGRADE_TODO: method 'java.util.Enumeration.nextElement' was converted to ' ' which has a different behavior. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1073_javautilEnumerationnextElement"' 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); } }