Пример #1
0
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]
Пример #2
0
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)
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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)
Пример #6
0
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
Пример #7
0
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
Пример #8
0
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"]: