/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add a single terminal to the Set. * @param sym the terminal being added. * @return true if this changes the Set. */ public bool add(terminal sym) { bool result; not_null(sym); /* see if we already have this */ result = _elements.Get(sym.index()); /* if not we add it */ if (!result) { _elements.Set(sym.index(), true); } return(result); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if the Set contains a particular terminal. * @param sym the terminal symbol we are looking for. */ public bool contains(terminal sym) { not_null(sym); return(_elements.Get(sym.index())); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Remove a terminal if it is in the Set. * @param sym the terminal being removed. */ public void remove(terminal sym) { not_null(sym); _elements.Set(sym.index(), false); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Procedure that attempts to fix a shift/reduce error by using * precedences. --frankf 6/26/96 * * if a production (also called rule) or the lookahead terminal * has a precedence, then the table can be fixed. if the rule * has greater precedence than the terminal, a reduce by that rule * in inserted in the table. If the terminal has a higher precedence, * it is shifted. if they have equal precedence, then the associativity * of the precedence is used to determine what to put in the table: * if the precedence is left associative, the action is to reduce. * if the precedence is right associative, the action is to shift. * if the precedence is non associative, then it is a syntax error. * * @param p the production * @param term_index the index of the lokahead terminal * @param parse_action_row a row of the action table * @param act the rule in conflict with the table entry */ protected bool fix_with_precedence( production p, int term_index, parse_action_row table_row, parse_action act) { terminal term = terminal.find(term_index); /* if the production has a precedence number, it can be fixed */ if (p.precedence_num() > assoc.no_prec) { /* if production precedes terminal, put reduce in table */ if (p.precedence_num() > term.precedence_num()) { table_row.under_term[term_index] = insert_reduce(table_row.under_term[term_index], act); return(true); } /* if terminal precedes rule, put shift in table */ else if (p.precedence_num() < term.precedence_num()) { table_row.under_term[term_index] = insert_shift(table_row.under_term[term_index], act); return(true); } else /* they are == precedence */ /* equal precedences have equal sides, so only need to * look at one: if it is right, put shift in table */ { if (term.precedence_side() == assoc.right) { table_row.under_term[term_index] = insert_shift(table_row.under_term[term_index], act); return(true); } /* if it is left, put reduce in table */ else if (term.precedence_side() == assoc.left) { table_row.under_term[term_index] = insert_reduce(table_row.under_term[term_index], act); return(true); } /* if it is nonassoc, we're not allowed to have two nonassocs * of equal precedence in a row, so put in NONASSOC */ else if (term.precedence_side() == assoc.nonassoc) { table_row.under_term[term_index] = new nonassoc_action(); return(true); } else { /* something really went wrong */ throw new internal_error("Unable to resolve conflict correctly"); } } } /* check if terminal has precedence, if so, shift, since * rule does not have precedence */ else if (term.precedence_num() > assoc.no_prec) { table_row.under_term[term_index] = insert_shift(table_row.under_term[term_index], act); return(true); } /* otherwise, neither the rule nor the terminal has a precedence, * so it can't be fixed. */ return(false); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** 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); } }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if the Set contains a particular terminal. * @param sym the terminal symbol we are looking for. */ public bool contains(terminal sym) { not_null(sym); return _elements.Get(sym.index()); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Remove a terminal if it is in the Set. * @param sym the terminal being removed. */ public void remove(terminal sym) { not_null(sym); _elements.Set(sym.index(),false); }
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add a single terminal to the Set. * @param sym the terminal being added. * @return true if this changes the Set. */ public bool add(terminal sym) { bool result; not_null(sym); /* see if we already have this */ result = _elements.Get(sym.index()); /* if not we add it */ if (!result) _elements.Set(sym.index(),true); return result; }