def build_larl1_automaton(G, firsts=None):
    assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented'

    if not firsts:
        firsts = compute_firsts(G)
    firsts[G.EOF] = ContainerSet(G.EOF)

    start_production = G.startSymbol.productions[0]
    start_item = Item(start_production, 0, lookaheads=ContainerSet(G.EOF))
    start = frozenset([start_item.Center()])

    closure = closure_lr1([start_item], firsts)
    automaton = State(frozenset(closure), True)

    pending = [start]
    visited = {start: automaton}

    while pending:
        current = pending.pop()
        current_state = visited[current]

        current_closure = current_state.state
        for symbol in G.terminals + G.nonTerminals:
            goto = goto_lr1(current_closure, symbol, just_kernel=True)
            closure = closure_lr1(goto, firsts)
            center = frozenset(item.Center() for item in goto)

            if center == frozenset():
                continue

            try:
                next_state = visited[center]
                centers = {item.Center(): item for item in next_state.state}
                centers = {
                    item.Center(): (centers[item.Center()], item)
                    for item in closure
                }

                updated_items = set()
                for c, (itemA, itemB) in centers.items():
                    item = Item(c.production, c.pos,
                                itemA.lookaheads | itemB.lookaheads)
                    updated_items.add(item)

                updated_items = frozenset(updated_items)
                if next_state.state != updated_items:
                    pending.append(center)
                next_state.state = updated_items
            except KeyError:
                visited[center] = next_state = State(frozenset(closure), True)
                pending.append(center)

            if current_state[symbol.Name] is None:
                current_state.add_transition(symbol.Name, next_state)
            else:
                assert current_state.get(
                    symbol.Name) is next_state, 'Bad build!!!'

    automaton.set_formatter(multiline_formatter)
    return automaton
Beispiel #2
0
def compute_follows(G, firsts):
    follows = {}
    change = True

    # init Follow(Vn)
    for nonterminal in G.nonTerminals:
        follows[nonterminal] = ContainerSet()
    follows[G.startSymbol] = 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]

            for i, symbol in enumerate(alpha):
                if symbol.IsNonTerminal:
                    beta = alpha[i + 1:]
                    first_beta = _compute_local_first(firsts, beta)
                    change |= follows[symbol].update(first_beta)
                    if first_beta.contains_epsilon or len(beta) == 0:
                        change |= follows[symbol].update(follow_X)

    # Follow(Vn)
    return follows
Beispiel #3
0
def compute_follows(G, firsts):
    follows = {}
    change = True

    local_firsts = {}

    for nonterminal in G.nonTerminals:
        follows[nonterminal] = ContainerSet()
    follows[G.startSymbol] = ContainerSet(G.EOF)

    while change:
        change = False

        for production in G.Productions:
            X = production.Left
            alpha = production.Right

            follow_X = follows[X]

            for i, Y in enumerate(alpha):
                if Y.IsNonTerminal:
                    try:
                        beta_f = local_firsts[alpha, i]
                    except KeyError:
                        beta_f = local_firsts[alpha, i] = compute_local_first(
                            firsts, islice(alpha, i + 1, None))
                    change |= follows[Y].update(beta_f)
                    if beta_f.contains_epsilon:
                        change |= follows[Y].update(follow_X)

    return follows
Beispiel #4
0
def compute_firsts(G):
    
    firsts = {}
    change = True
    # init First(Vt)
    for terminal in G.terminals:
        firsts[terminal] = ContainerSet(terminal)
    # init First(Vn)
    for nonterminal in G.nonTerminals:
        firsts[nonterminal] = ContainerSet()
    while change:
        change = False
        # P: X -> alpha
        for production in G.Productions:
            X = production.Left
            alpha = production.Right
            # get current First(X)
            first_X = firsts[X]
            # init First(alpha)
            try:
                first_alpha = firsts[alpha]
            except KeyError:
                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
Beispiel #5
0
def compute_firsts(G):
    firsts = {}
    change = True

    for terminal in G.terminals:
        firsts[terminal] = ContainerSet(terminal)

    for nonterminal in G.nonTerminals:
        firsts[nonterminal] = ContainerSet()

    while change:
        change = False

        # P: X -> alpha
        for production in G.Productions:
            X, alpha = production

            first_X = firsts[X]

            try:
                first_alpha = firsts[alpha]
            except KeyError:
                first_alpha = firsts[alpha] = ContainerSet()

            local_first = compute_local_first(firsts, alpha)

            change |= first_alpha.hard_update(local_first)
            change |= first_X.hard_update(local_first)

    return firsts
Beispiel #6
0
def expand(item, firsts):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []

    lookaheads = ContainerSet()
    for preview in item.Preview():
        lookaheads.hard_update(compute_local_first(firsts, preview))

    assert not lookaheads.contains_epsilon
    return [Item(prod, 0, lookaheads) for prod in next_symbol.productions]
Beispiel #7
0
    def Compact_Automata(self, automata):
        new_states = {}
        for state in automata:
            new_states[state] = state

        states_to_compress = []

        for state1 in automata:
            if not new_states[state1] == state1:
                continue
            states_to_compress = [state1] 
            for state2 in automata:
                if state1 == state2 or not new_states[state2] == state2:
                    continue
                
                node1 = state1.state
                node2 = state2.state

                are_equals = False
                if len(node1) == len(node2):
                    for item1 in node1:
                        are_equals = False
                        for item2 in node2:
                            if item1.Center() == item2.Center():
                                are_equals = True
                        if not are_equals:
                            break

                if are_equals:
                    states_to_compress.append(state2)

            compress_set = ContainerSet()

            for state in states_to_compress:
                node = state.state
                compress_set.update(ContainerSet(*node))

            new_node = self.compress(compress_set)
            new_state = State(frozenset(new_node), True)
            
            for state in states_to_compress:
                new_states[state] = new_state

        new_automata = new_states[automata]

        for state in automata:
            for key in state.transitions:
                for to_state in state.transitions[key]:
                    try:
                        assert new_states[to_state] in new_states[state].transitions[key] 
                    except:
                        new_states[state].add_transition(key, new_states[to_state])   
                        
        return new_automata
Beispiel #8
0
def expand(item, firsts):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []

    lookaheads = ContainerSet()
    # Your code here!!! (Compute lookahead for child items)
    for string in item.Preview():
        lookaheads.update(compute_local_first(firsts, string))

    assert not lookaheads.contains_epsilon
    # Your code here!!! (Build and return child items)
    return [Item(prod, 0, lookaheads) for prod in next_symbol.productions]
Beispiel #9
0
def compute_local_first_queue(firsts, alpha):
    first_alpha = ContainerSet()
    temp = []
    try:
        alpha_is_epsilon = alpha.IsEpsilon
    except:
        alpha_is_epsilon = False

    if alpha_is_epsilon:
        first_alpha.set_epsilon(True)
        return first_alpha

    breaked = False
    while len(alpha) > 0:
        symbol = alpha.pop()
        temp.append(symbol)
        first_alpha.update(firsts[symbol])
        if not firsts[symbol].contains_epsilon:
            breaked = True
            break

    if not breaked:
        first_alpha.set_epsilon(True)

    while len(temp) > 0:
        alpha.append(temp.pop())
    return first_alpha
    def ComputeLocalFirst(firsts: dict, alpha) -> ContainerSet:
        """
        Computa el conjunto First de la cadena alpha, esta cadena puede 
        tener tanto terminales como non-terminales.
        """
        first_alpha = ContainerSet()

        try:
            alpha_is_epsilon = alpha.IsEpsilon
        except:
            alpha_is_epsilon = False

        # alpha == epsilon ? First(alpha) = { epsilon }
        if alpha_is_epsilon:
            first_alpha.set_epsilon()

        # alpha = X1 ... XN
        # First(Xi) subset of First(alpha)
        # epsilon  in First(X1)...First(Xi) ? First(Xi+1) subset of First(X) & First(alpha)
        # epsilon in First(X1)...First(XN) ? epsilon in First(X) & First(alpha)
        else:
            for symbol in alpha:
                first_symbol = firsts[symbol]
                first_alpha.update(first_symbol)
                if not first_symbol.contains_epsilon:
                    break
            else:
                first_alpha.set_epsilon()

        return first_alpha
Beispiel #11
0
def compute_local_first(firsts, alpha):    
    """
    Computes First(alpha), given First(Vt) and First(Vn) 
    alpha in (Vt U Vn)*
    """
    first_alpha = ContainerSet()
    
    try:
        alpha_is_epsilon = alpha.IsEpsilon
    except:
        alpha_is_epsilon = False

    # alpha == epsilon ? First(alpha) = { epsilon }
    if alpha_is_epsilon:
        first_alpha.set_epsilon()

    # alpha = X1 ... XN
    # First(Xi) subset of First(alpha)
    # epsilon  in First(X1)...First(Xi) ? First(Xi+1) subset of First(X) & First(alpha)
    # epsilon in First(X1)...First(XN) ? epsilon in First(X) & First(alpha)
    else:
        for symbol in alpha:
            first_symbol = firsts[symbol]
            first_alpha.update(first_symbol)
            if not first_symbol.contains_epsilon:
                break
        else:
            first_alpha.set_epsilon()

    return first_alpha
Beispiel #12
0
    def Expand(item, firsts):
        next_symbol = item.NextSymbol
        if next_symbol is None or not next_symbol.IsNonTerminal:
            return []

        lookaheads = ContainerSet()
        # (Compute lookahead for child items)
        for preview in item.Preview():
            lookaheads.hard_update(
                UtilsParsers.ComputeLocalFirst(firsts, preview))

        assert not lookaheads.contains_epsilon
        # (Build and return child items)
        return [Item(prod, 0, lookaheads) for prod in next_symbol.productions]
Beispiel #13
0
def expand(item, firsts):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []
    lookaheads = ContainerSet()
    for prev in item.Preview():
        new_first = compute_local_first(firsts, prev)
        lookaheads.update(new_first)

    assert not lookaheads.contains_epsilon
    result = []
    for prod in next_symbol.productions:
        result.append(Item(prod, 0, lookaheads))

    return result
def expand(item, firsts):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []

    lookaheads = ContainerSet()
    # Your code here!!! (Compute lookahead for child items)
    for preview in item.Preview():
        lookaheads.hard_update(compute_local_first(firsts, preview))

    assert not lookaheads.contains_epsilon
    # Your code here!!! (Build and return child items)
    items = []
    for production in next_symbol.productions:
        items.append(Item(production, 0, lookaheads))
    return items
Beispiel #15
0
def expand(item, firsts):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []

    lookaheads = ContainerSet(
    )  # lookahead = que yo quiero ver cuando vaya a reducir
    # Your code here!!! (Compute lookahead for child items)

    for prev in item.Preview():
        lookaheads.update(compute_local_first(firsts, prev))

    assert not lookaheads.contains_epsilon

    # Your code here!!! (Build and return child items)
    return [Item(x, 0, lookaheads) for x in next_symbol.productions]
Beispiel #16
0
def expand(item, firsts):
    next_symbol = item.NextSymbol

    if next_symbol is None or next_symbol.IsTerminal:
        return []

    lookaheads = ContainerSet()
    result = []
    for preview in item.Preview():
        lookaheads.update(compute_local_firsts(firsts, preview))

    assert not lookaheads.contains_epsilon, "lookaheads contains epsilon"
    result = []
    for i, production in enumerate(next_symbol.productions):
        result.append(Item(production, 0, lookaheads))
    return result
Beispiel #17
0
    def build_LR1_automaton(self, G):
        assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented'
        
        firsts = compute_firsts(G)
        firsts[G.EOF] = ContainerSet(G.EOF)
        
        start_production = G.startSymbol.productions[0]
        start_item = Item(start_production, 0, lookaheads=(G.EOF,))
        start = frozenset([start_item])
        
        closure = self.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:
                closure_current = self.closure_lr1(current, firsts)
                goto = self.goto_lr1(closure_current, symbol, just_kernel=True)
                if len(goto) == 0:
                    continue
                try:
                    next_state = visited[goto]
                except KeyError:
                    next_closure = self.closure_lr1(goto, firsts)
                    visited[goto] = next_state = State(frozenset(next_closure), True)
                    pending.append(goto)

                current_state.add_transition(symbol.Name, next_state)
        
        automaton.set_formatter(multiline_formatter)
        return automaton
Beispiel #18
0
def expand(item, firsts, with_lookaheads=True):
    next_symbol = item.NextSymbol
    if next_symbol is None or not next_symbol.IsNonTerminal:
        return []

    if with_lookaheads:
        lookaheads = ContainerSet()
        # Your code here!!! (Compute lookahead for child items)
        preview = item.Preview()
        for sentence in preview:
            lookaheads.update(compute_local_first(firsts, sentence))
            assert not lookaheads.contains_epsilon

    return [
        Item(production, 0, [l for l in lookaheads])
        for production in next_symbol.productions
    ]
def closure_lr0(items):
    closure = ContainerSet(*items)

    pending = list(items)
    while pending:
        current = pending.pop()
        symbol = current.NextSymbol

        if current.IsReduceItem or symbol.IsTerminal:
            continue

        new_items = [
            Item(p, 0) for p in symbol.productions if Item(p, 0) not in closure
        ]
        pending += new_items
        closure.extend(new_items)
    return frozenset(closure)
Beispiel #20
0
def compute_follows(G, firsts):
    follows = {}
    change = True

    local_firsts = {}

    # init Follow(Vn)
    for nonterminal in G.nonTerminals:
        follows[nonterminal] = ContainerSet()
    follows[G.startSymbol] = 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)
            ###################################################
            #                   <CODE_HERE>                   #
            ###################################################

            ##
            for it, val in enumerate(alpha):
                if val.IsNonTerminal:
                    follows_val = follows[val]

                    try:
                        first = local_firsts[alpha, it]
                    except:
                        first = local_firsts[alpha, it] = compute_local_first(
                            firsts, islice(alpha, it + 1, None))

                    change |= follows_val.update(first)
                    if first.contains_epsilon:
                        change |= follows_val.update(follow_X)

    return follows
Beispiel #21
0
 def follows(self):
     G = self.G
     return {
         G['E']:
         ContainerSet(G[')'], G.EOF, contains_epsilon=False),
         G['T']:
         ContainerSet(G['|'], G[')'], G.EOF, contains_epsilon=False),
         G['F']:
         ContainerSet(G['symbol'],
                      G['|'],
                      G['('],
                      G[')'],
                      G.EOF,
                      contains_epsilon=False),
         G['A']:
         ContainerSet(G['symbol'],
                      G.EOF,
                      G['|'],
                      G['*'],
                      G['('],
                      G[')'],
                      contains_epsilon=False),
         G['X']:
         ContainerSet(G[')'], G.EOF, contains_epsilon=False),
         G['Y']:
         ContainerSet(G['|'], G[')'], G.EOF, contains_epsilon=False),
         G['Z']:
         ContainerSet(G['symbol'],
                      G.EOF,
                      G['|'],
                      G['('],
                      G[')'],
                      contains_epsilon=False)
     }
Beispiel #22
0
def compute_follows(G, firsts):
    follows = {}
    change = True

    local_firsts = {}

    # init Follow(Vn)
    for nonterminal in G.nonTerminals:
        follows[nonterminal] = ContainerSet()
    follows[G.startSymbol] = 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, symbol in enumerate(alpha):
                if symbol.IsNonTerminal:
                    follow_Y = follows[symbol]

                    try:
                        first_beta = local_firsts[alpha, i]
                    except KeyError:
                        first_beta = local_firsts[alpha,
                                                  i] = compute_local_first(
                                                      firsts,
                                                      islice(
                                                          alpha, i + 1, None))

                    change |= follow_Y.update(first_beta)

                    if first_beta.contains_epsilon:
                        change |= follow_Y.update(follow_X)

    # Follow(Vn)
    return follows
Beispiel #23
0
def compute_follows(G, firsts):
    follows = {}
    change = True

    local_firsts = {}

    # init Follow(Vn)
    for nonterminal in G.nonTerminals:
        follows[nonterminal] = ContainerSet()
    follows[G.startSymbol] = 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]

            for i, Y in enumerate(alpha):

                if not Y.IsTerminal:

                    follow_y = follows[Y]

                    try:
                        first_beta = local_firsts[alpha, i]
                    except KeyError:
                        first_beta = local_firsts[alpha,
                                                  i] = compute_local_first(
                                                      firsts,
                                                      islice(
                                                          alpha, i + 1, None))

                    change |= follow_y.update(first_beta)

                    if i == len(alpha) - 1 or first_beta.contains_epsilon:
                        change |= follow_y.update(follow_x)

    # Follow(Vn)
    return follows
def closure_lr1(items, firsts):
    closure = ContainerSet(*items)
    changed = True
    while changed:
        new_items = ContainerSet()
        for item in closure:
            new_items.extend(expand(item, firsts))
        changed = closure.update(new_items)
    return compress(closure)
    def ComputeFirsts(G: Grammar) -> dict:
        """
        Calcula el conjunto First de los terminales, los no-terminales
        y las partes derechas de la gramatica.
        """
        firsts = {}
        change = True

        # init First(Vt)
        for terminal in G.terminals:
            firsts[terminal] = ContainerSet(terminal)

        # init First(Vn)
        for nonterminal in G.nonTerminals:
            firsts[nonterminal] = ContainerSet()

        while change:
            change = False

            # P: X -> alpha
            for production in G.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 = UtilsParsers.ComputeLocalFirst(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 ComputeFollows(G: Grammar, firsts: dict) -> dict:
        """
        Calcula el conjunto Follow de todos los no terminales de la
        gramatica.
        """
        follows = {}
        change = True
        local_firsts = {}

        # init Follow(Vn)
        for nonterminal in G.nonTerminals:
            follows[nonterminal] = ContainerSet()
        follows[G.startSymbol] = 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, symbol in enumerate(alpha):
                    if symbol.IsNonTerminal:
                        follow_symbol = follows[symbol]
                        beta = alpha[i + 1:]
                        try:
                            first_beta = local_firsts[beta]
                        except KeyError:
                            first_beta = local_firsts[
                                beta] = UtilsParsers.ComputeLocalFirst(
                                    firsts, beta)
                        change |= follow_symbol.update(first_beta)
                        if first_beta.contains_epsilon or len(beta) == 0:
                            change |= follow_symbol.update(follow_X)

        return follows
Beispiel #27
0
def epsilon_closure(automaton, states):
    Y = [s for s in states]
    x = {s for s in states}
    while Y:
        z = Y.pop()
        epsilon_transitions = automaton.epsilon_transitions(z)
        for G in epsilon_transitions:
            if G not in x:
                x.add(G)
                Y.append(G)
    return ContainerSet(*x)
Beispiel #28
0
    def _build_parsing_table(self):
        G = self._G
        firsts = self._firsts
        follows = self._follows

        # init parsing table
        M = {}

        # P: X -> alpha
        for production in G.Productions:
            X = production.Left
            alpha = production.Right

            term = [item for item in G.terminals]
            term.append(G.EOF)

            for item in term:
                if item in firsts[alpha]:
                    if (tuple([X, item]) in M and M[tuple([X, item])] == [
                            production,
                    ]) or tuple([X, item]) not in M:
                        M[tuple([X, item])] = [
                            production,
                        ]
                    else:
                        M[tuple([X, item])].append(production)

                if firsts[alpha].contains_epsilon and (item in follows[X]):
                    if (tuple([X, item]) in M and M[tuple([X, item])] == [
                            production,
                    ]) or tuple([X, item]) not in M:
                        temp_container = ContainerSet()
                        temp_container.set_epsilon()
                        M[tuple([X, item])] = [
                            production,
                        ]
                    else:
                        M[tuple([X, item])].append(production)

        # parsing table is ready!!!
        return M
Beispiel #29
0
def build_parsing_table(G, firsts, follows):
    # init parsing table
    M = {}

    # P: X -> alpha
    for production in G.Productions:
        X = production.Left
        alpha = production.Right

        term = G.terminals
        term.append(G.EOF)

        for item in term:
            if item in firsts[alpha]:
                if (tuple([X, item]) in M and M[tuple([X, item])] == [
                        production,
                ]) or tuple([X, item]) not in M:
                    M[tuple([X, item])] = [
                        production,
                    ]
                else:
                    st.error('La gramatica no es LL(1)')
                    return None
                    #raise EnvironmentError("Error de insercion en la tabla, problemas en la produccion: ", production, " Existe conflicto!")

            if firsts[alpha].contains_epsilon and (item in follows[X]):
                if (tuple([X, item]) in M and M[tuple([X, item])] == [
                        production,
                ]) or tuple([X, item]) not in M:
                    temp_container = ContainerSet()
                    temp_container.set_epsilon()
                    M[tuple([X, item])] = [
                        production,
                    ]
                else:
                    st.error('La gramatica no es LL(1)')
                    return None
                    #raise EnvironmentError("Error de insercion en la tabla, problemas en la produccion: ", production, " Existe conflicto!")

    # parsing table is ready!!!
    return M
Beispiel #30
0
 def follows(self):
     G = self.G
     return {
         G['E']:
         ContainerSet(G[')'], G.EOF, contains_epsilon=False),
         G['T']:
         ContainerSet(G[')'], G['-'], G.EOF, G['+'],
                      contains_epsilon=False),
         G['F']:
         ContainerSet(G['-'],
                      G.EOF,
                      G['*'],
                      G['/'],
                      G[')'],
                      G['+'],
                      contains_epsilon=False),
         G['X']:
         ContainerSet(G[')'], G.EOF, contains_epsilon=False),
         G['Y']:
         ContainerSet(G[')'], G['-'], G.EOF, G['+'], contains_epsilon=False)
     }