diff --git a/rply/parsergenerator.py b/rply/parsergenerator.py index f2ed8ee..5df004a 100644 --- a/rply/parsergenerator.py +++ b/rply/parsergenerator.py @@ -316,74 +316,86 @@ def from_grammar(cls, grammar): st_goto = {} for p in I: if p.getlength() == p.lr_index + 1: + if p.name == "S'": # Start symbol. Accept! st_action["$end"] = 0 st_actionp["$end"] = p - else: - laheads = p.lookaheads[st] - for a in laheads: - if a in st_action: - r = st_action[a] - if r > 0: - sprec, slevel = grammar.productions[st_actionp[a].number].prec - rprec, rlevel = grammar.precedence.get(a, ("right", 0)) - if (slevel < rlevel) or (slevel == rlevel and rprec == "left"): - st_action[a] = -p.number - st_actionp[a] = p - if not slevel and not rlevel: - sr_conflicts.append((st, repr(a), "reduce")) - grammar.productions[p.number].reduced += 1 - elif not (slevel == rlevel and rprec == "nonassoc"): - if not rlevel: - sr_conflicts.append((st, repr(a), "shift")) - elif r < 0: - oldp = grammar.productions[-r] - pp = grammar.productions[p.number] - if oldp.number > pp.number: - st_action[a] = -p.number - st_actionp[a] = p - chosenp, rejectp = pp, oldp - grammar.productions[p.number].reduced += 1 - grammar.productions[oldp.number].reduced -= 1 - else: - chosenp, rejectp = oldp, pp - rr_conflicts.append((st, repr(chosenp), repr(rejectp))) - else: - raise ParserGeneratorError("Unknown conflict in state %d" % st) - else: + continue + + laheads = p.lookaheads[st] + for a in laheads: + + if a not in st_action: + st_action[a] = -p.number + st_actionp[a] = p + grammar.productions[p.number].reduced += 1 + continue + + r = st_action[a] + if r > 0: + sprec, slevel = grammar.productions[st_actionp[a].number].prec + rprec, rlevel = grammar.precedence.get(a, ("right", 0)) + if (slevel < rlevel) or (slevel == rlevel and rprec == "left"): st_action[a] = -p.number st_actionp[a] = p + if not slevel and not rlevel: + sr_conflicts.append((st, repr(a), "reduce")) grammar.productions[p.number].reduced += 1 + elif not (slevel == rlevel and rprec == "nonassoc"): + if not rlevel: + sr_conflicts.append((st, repr(a), "shift")) + elif r < 0: + oldp = grammar.productions[-r] + pp = grammar.productions[p.number] + if oldp.number > pp.number: + st_action[a] = -p.number + st_actionp[a] = p + chosenp, rejectp = pp, oldp + grammar.productions[p.number].reduced += 1 + grammar.productions[oldp.number].reduced -= 1 + else: + chosenp, rejectp = oldp, pp + rr_conflicts.append((st, repr(chosenp), repr(rejectp))) + else: + raise ParserGeneratorError("Unknown conflict in state %d" % st) + else: + i = p.lr_index a = p.prod[i + 1] - if a in grammar.terminals: - g = cls.lr0_goto(I, a, add_count, goto_cache) - j = cidhash.get(g, -1) - if j >= 0: - if a in st_action: - r = st_action[a] - if r > 0: - if r != j: - raise ParserGeneratorError("Shift/shift conflict in state %d" % st) - elif r < 0: - rprec, rlevel = grammar.productions[st_actionp[a].number].prec - sprec, slevel = grammar.precedence.get(a, ("right", 0)) - if (slevel > rlevel) or (slevel == rlevel and rprec == "right"): - grammar.productions[st_actionp[a].number].reduced -= 1 - st_action[a] = j - st_actionp[a] = p - if not rlevel: - sr_conflicts.append((st, repr(a), "shift")) - elif not (slevel == rlevel and rprec == "nonassoc"): - if not slevel and not rlevel: - sr_conflicts.append((st, repr(a), "reduce")) - else: - raise ParserGeneratorError("Unknown conflict in state %d" % st) - else: - st_action[a] = j - st_actionp[a] = p + if a not in grammar.terminals: + continue + + g = cls.lr0_goto(I, a, add_count, goto_cache) + j = cidhash.get(g, -1) + if j < 0: + continue + + if a not in st_action: + st_action[a] = j + st_actionp[a] = p + continue + + r = st_action[a] + if r > 0: + if r != j: + raise ParserGeneratorError("Shift/shift conflict in state %d" % st) + elif r < 0: + rprec, rlevel = grammar.productions[st_actionp[a].number].prec + sprec, slevel = grammar.precedence.get(a, ("right", 0)) + if (slevel > rlevel) or (slevel == rlevel and rprec == "right"): + grammar.productions[st_actionp[a].number].reduced -= 1 + st_action[a] = j + st_actionp[a] = p + if not rlevel: + sr_conflicts.append((st, repr(a), "shift")) + elif not (slevel == rlevel and rprec == "nonassoc"): + if not slevel and not rlevel: + sr_conflicts.append((st, repr(a), "reduce")) + else: + raise ParserGeneratorError("Unknown conflict in state %d" % st) + nkeys = set() for ii in I: for s in ii.unique_syms: