def expand(item, firsts): next_symbol = item.next_symbol if next_symbol is None or not next_symbol.is_nonterminal: return [] lookaheads = ContainerSet() # Compute lookahead for child items for preview in item.preview(): preview_firsts = compute_local_first(firsts, preview) lookaheads.update(preview_firsts) assert not lookaheads.contains_epsilon # Build and return child items return [Item(prod, 0, lookaheads) for prod in next_symbol.productions]
def epsilon_closure(automaton, states): pending = [s for s in states] closure = {s for s in states} while pending: state = pending.pop() dest_states = automaton.epsilon_transitions(state) closure.update({s for s in dest_states}) pending.extend(dest_states) return ContainerSet(*closure)
def compute_firsts(grammar): firsts = {} change = True # init First(Vt) for terminal in grammar.terminals: firsts[terminal] = ContainerSet(terminal) # init First(Vn) for nonterminal in grammar.nonterminals: firsts[nonterminal] = ContainerSet() while change: change = False # P: X -> alpha for production in grammar.productions: X = production.left alpha = production.right # get current First(X) first_X = firsts[X] # init First(alpha) try: first_alpha = firsts[alpha] except: first_alpha = firsts[alpha] = ContainerSet() # CurrentFirst(alpha)??? local_first = compute_local_first(firsts, alpha) # update First(X) and First(alpha) from CurrentFirst(alpha) change |= first_alpha.hard_update(local_first) change |= first_X.hard_update(local_first) # First(Vt) + First(Vt) + First(RightSides) return firsts
def compute_follows(g, firsts): follows = {} change = True local_firsts = {} # init Follow(Vn) for nonterminal in g.nonterminals: follows[nonterminal] = ContainerSet() follows[g.start_symbol] = ContainerSet(g.eof) while change: change = False # P: X -> alpha for production in g.productions: x = production.left alpha = production.right follow_x = follows[x] # X -> zeta Y beta # First(beta) - { epsilon } subset of Follow(Y) # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) for i, y in enumerate(alpha): if y not in g.nonterminals: continue beta = alpha[i + 1:] if beta: if beta not in local_firsts: local_firsts[beta] = compute_local_first(firsts, beta) change |= follows[y].update(local_firsts[beta]) if not beta or local_firsts[beta].contains_epsilon: change |= follows[y].update(follow_x) # Follow(Vn) return follows
def closure_lr1(items, firsts): closure = ContainerSet(*items) changed = True while changed: changed = False new_items = ContainerSet() for item in closure: new_items.extend(expand(item, firsts)) changed = closure.update(new_items) return compress(closure)
def build_lr1_automaton(G): assert len(G.start_symbol.productions) == 1, "Grammar must be augmented" firsts = compute_firsts(G) firsts[G.eof] = ContainerSet(G.eof) start_production = G.start_symbol.productions[0] start_item = Item(start_production, 0, lookaheads=(G.eof, )) start = frozenset([start_item]) closure = closure_lr1(start, firsts) automaton = State(frozenset(closure), True) pending = [start] visited = {start: automaton} while pending: current = pending.pop() current_state = visited[current] for symbol in G.terminals + G.nonterminals: # Get/Build `next_state` next_ = frozenset( goto_lr1(closure_lr1(current, firsts), symbol, just_kernel=True)) if not next_: continue try: next_state = visited[next_] except KeyError: pending.append(next_) next_closure = frozenset(closure_lr1(next_, firsts)) next_state = visited[next_] = State(next_closure, True) current_state.add_transition(symbol.name, next_state) automaton.set_formatter(multiline_formatter) return automaton
def compute_local_first(firsts, alpha): first_alpha = ContainerSet() # alpha = X1 ... XN # First(Xi) subconjunto First(alpha) # epsilon pertenece a First(X1)...First(Xi) ? # First(Xi+1) subconjunto de First(X) y First(alpha) # epsilon pertenece a First(X1)...First(XN) ? # epsilon pertence a First(X) y al First(alpha) for s in alpha: first_alpha.update(firsts[s]) if not firsts[s].contains_epsilon: break else: first_alpha.set_epsilon() return first_alpha
X %= plus + T + X, lambda h, s: s[3], None, None, lambda h, s: h[0] + s[2] X %= minus + T + X, lambda h, s: s[3], None, None, lambda h, s: h[0] - s[2] X %= grammar.epsilon, lambda h, s: h[0] T %= F + Y, lambda h, s: s[2], None, lambda h, s: s[1] Y %= star + F + Y, lambda h, s: s[3], None, None, lambda h, s: h[0] * s[2] Y %= div + F + Y, lambda h, s: s[3], None, None, lambda h, s: h[0] / s[2] Y %= grammar.epsilon, lambda h, s: h[0] F %= opar + E + cpar, lambda h, s: s[2], None, None, None F %= num, lambda h, s: float(s[1]), None firsts = { grammar["+"]: ContainerSet(grammar["+"], contains_epsilon=False), grammar["-"]: ContainerSet(grammar["-"], contains_epsilon=False), grammar["*"]: ContainerSet(grammar["*"], contains_epsilon=False), grammar["/"]: ContainerSet(grammar["/"], contains_epsilon=False), grammar["("]: ContainerSet(grammar["("], contains_epsilon=False), grammar[")"]: ContainerSet(grammar[")"], contains_epsilon=False), grammar["num"]: ContainerSet(grammar["num"], contains_epsilon=False), grammar["E"]: ContainerSet(grammar["num"], grammar["("], contains_epsilon=False), grammar["T"]: