def build_LR0_automaton(G: Grammar): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [start_item] visited = {start_item: automaton} while pending: current_item = pending.pop() if current_item.IsReduceItem: continue current_state = visited[current_item] next_symbol = current_item.NextSymbol next_item = current_item.NextItem() #- $(X --> a.cB) ---c---> (X --> ac.B) con c in V_T #- $(X --> a.YB) ---Y---> (X --> aY.B) con Y in V_N next_state = get_state(visited, pending, next_item) current_state.add_transition(next_symbol.Name, next_state) if next_symbol in G.nonTerminals: sym_productions = G.symbDict[next_symbol.Name].productions #- $(X --> a.YB) ---e---> (Y --> .Z) con Y in V_N for pr in [Item(x, 0) for x in sym_productions]: trans_state = get_state(visited, pending, pr) current_state.add_epsilon_transition(trans_state) return automaton.to_deterministic(lr0_formatter)
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
def build_LR0_automaton(G): assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [start_item] visited = {start_item: automaton} while pending: current_item = pending.pop() if current_item.IsReduceItem: continue # (Decide which transitions to add) # agregar las epsilon transiciones # a estados donde el item posee producciones a partir del simbolo actual en la posicion 0 # y agregar la transicion a partir del simbolo siguiente next_item = current_item.NextItem() try: next_state = visited[next_item] except KeyError: next_state = State(next_item, True) visited[next_item] = next_state pending.append(next_item) if current_item.NextSymbol.IsNonTerminal: epsilon_productions = current_item.NextSymbol.productions else: epsilon_productions = None current_state = visited[current_item] # (Adding the decided transitions) current_state.add_transition(current_item.NextSymbol.Name, next_state) if epsilon_productions: for eproduction in epsilon_productions: epItem = Item(eproduction, 0) try: epState = visited[epItem] except KeyError: epState = State(epItem, True) visited[epItem] = epState pending.append(epItem) current_state.add_epsilon_transition(epState) return automaton
def build_lr0_automaton(G): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) start = frozenset([start_item]) automaton = State(closure_lr0(start), 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: kernel = goto_lr0(current_closure, symbol) if kernel == frozenset(): continue try: next_state = visited[kernel] except KeyError: next_state = visited[kernel] = State(closure_lr0(kernel), True) pending.append(kernel) current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
def build_LALR_automaton(G): assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" lr1_automaton = build_LR1_automaton(G) same_kernel = {} for node in lr1_automaton: just_center = frozenset([item.Center() for item in node.state]) try: same_kernel[just_center].append(node) except KeyError: same_kernel[just_center] = [node] start = frozenset([item.Center() for item in lr1_automaton.state ]) # como cabecera solo quedan los items sin lookahead automaton = State( lr1_automaton.state, True ) # en visited se guarda el estado que corresponde a la fusion de estaods ocn el mismo nucleo pending = [start] visited = {start: automaton} while pending: current = pending.pop() current_state = visited[current] # se van a actualizar # todos los estados con los que el estado actual tiene alguna transicion lr1_state = same_kernel[current][0] # chequear que cada estado del cjto analizado tenga esa transicion for symbol in G.terminals + G.nonTerminals: if lr1_state.has_transition(symbol.Name): state = lr1_state.transitions[symbol.Name][0] center_items = frozenset( [item.Center() for item in state.state]) try: next_state = visited[center_items] except KeyError: kernel_set = same_kernel[center_items] items_with_lookahead = {} for node in kernel_set: for item in node.state: try: current_item = items_with_lookahead[ item.Center()] except KeyError: current_item = items_with_lookahead[ item.Center()] = set() current_item.update(item.lookaheads) completed_items = [ Item(item.production, item.pos, lookaheads) for item, lookaheads in items_with_lookahead.items() ] next_state = State(frozenset(completed_items), True) visited[center_items] = next_state pending.append(center_items) current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
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
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)
def build_LR0_automaton(G): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [start_item] visited = {start_item: automaton} while pending: current_item = pending.pop() if current_item.IsReduceItem: continue # Your code here!!! (Decide which transitions to add) current_state = visited[current_item] next_symbol = current_item.NextSymbol next_item = current_item.NextItem() try: next_state = visited[next_item] except KeyError: next_state = State(next_item, True) visited[next_item] = next_state current_state.add_transition(next_symbol.Name, next_state) # print('Added trans: ', current_state, f'==={next_symbol.Name}===>', next_state) pending.append(next_item) if next_symbol.IsNonTerminal: # If symbol is non terminal, add e-productions to Y->.alpha for prod in next_symbol.productions: new_item = Item(prod, 0) try: new_state = visited[new_item] item_was_found = True except KeyError: new_state = State(new_item, True) visited[new_item] = new_state item_was_found = False current_state.add_epsilon_transition(new_state) # print('Added e-trans:', current_state, '==>', new_state) if not item_was_found: pending.append(new_item) return automaton
def build_LR0_automaton(G): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [start_item] visited = {start_item: automaton} while pending: current_item = pending.pop() if current_item.IsReduceItem: continue # Your code here!!! (Decide which transitions to add) new_item = current_item.NextItem() transition_symbol = current_item.NextSymbol.Name next_items = [(new_item, transition_symbol)] if current_item.NextSymbol in G.nonTerminals: for production in current_item.NextSymbol.productions: new_item = Item(production, 0) next_items.append((new_item, G.Epsilon)) current_state = visited[current_item] # Your code here!!! (Add the decided transitions) for item, symbol in next_items: try: state = visited[item] except KeyError: state = State(item, True) visited[item] = state pending.append(item) if symbol == G.Epsilon: current_state.add_epsilon_transition(state) else: current_state.add_transition(symbol, state) return automaton
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]
def compress(self, items): centers = {} for item in items: center = item.Center() try: lookaheads = centers[center] except KeyError: centers[center] = lookaheads = set() lookaheads.update(item.lookaheads) return { Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() }
def build_LR0_automaton(G): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [ start_item ] visited = { start_item: automaton } while pending: current_item = pending.pop() if current_item.IsReduceItem: continue state = visited[current_item] next_item = current_item.NextItem() try: new_state = visited[next_item] except KeyError: new_state = visited[next_item] = State(next_item, True) pending.append(next_item) next_symbol = current_item.NextSymbol state.add_transition(next_symbol.Name, new_state) if next_symbol.IsNonTerminal: for prod in next_symbol.productions: item = Item(prod, 0) try: visited[item] except KeyError: visited[item] = State(item, True) pending.append(item) state.add_epsilon_transition(visited[item]) current_state = visited[current_item] return automaton
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]
def build_LR0_automaton(G): assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' start_production = G.startSymbol.productions[0] start_item = Item(start_production, 0) automaton = State(start_item, True) pending = [start_item] visited = {start_item: automaton} while pending: current_item = pending.pop() if current_item.IsReduceItem: continue next_item = current_item.NextItem() symbol = current_item.NextSymbol try: visited[current_item].add_transition(symbol.Name, visited[next_item]) except: visited[next_item] = State(next_item, True) visited[current_item].add_transition(symbol.Name, visited[next_item]) pending.append(next_item) if symbol.IsNonTerminal: prod = symbol.productions for p in prod: item = Item(p, 0) try: visited[current_item].add_epsilon_transition(visited[item]) except KeyError: visited[item] = State(item, True) visited[current_item].add_epsilon_transition(visited[item]) pending.append(item) return automaton
def build_LALR1_automaton(G): automaton = build_LR1_automaton(G) stKernel = {} for node in automaton: kernel = frozenset([item.Center() for item in node.state]) try: stKernel[kernel].append(node) except KeyError: stKernel[kernel] = [node] initial = frozenset([item.Center() for item in automaton.state]) automaton = State(automaton.state, True) visited = {initial: automaton} pending = [initial] while pending: current = pending.pop() current_state = visited[current] lr1_state = stKernel[current][0] for symbol in G.terminals + G.nonTerminals: if symbol.Name in lr1_state.transitions: dest_core = frozenset([ item.Center() for item in lr1_state.transitions[symbol.Name][0].state ]) try: next_state = visited[dest_core] except KeyError: union_core = {center: set() for center in dest_core} for node in stKernel[dest_core]: for item in node.state: union_core[item.Center()].update(item.lookaheads) union_core = frozenset([ Item(center.production, center.pos, lookaheads=lookaheads) for center, lookaheads in union_core.items() ]) next_state = State(union_core, True) visited[dest_core] = next_state pending.append(dest_core) current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
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
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]
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
def build_lalr_automaton(G): def centers(items: [Item]): return frozenset(item.Center() for item in items) def lookaheads(items: [Item]): return {item.Center(): item.lookaheads for item in items} def subset(items1, items2): return all(items1[i] <= items2[i] for i in items1) 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, (G.EOF, )) start = State(frozenset(closure_lr1([start_item], firsts)), True) pending = [start_item] visisted_centers = {centers(start.state): start} visited = {start_item: start} while pending: current_state = visited[pending.pop()] for symbol in G.terminals + G.nonTerminals: next_item = frozenset(goto_lr1(current_state.state, symbol, firsts)) if next_item: try: next_state = visisted_centers[centers(next_item)] if not subset(lookaheads(next_item), lookaheads(next_state.state)): next_state.state = compress( list(next_state.state) + list(next_item)) pending.append(frozenset(next_state.state)) visited[frozenset(next_state.state)] = next_state except KeyError: next_state = State(next_item, True) pending += [next_item] visisted_centers[centers(next_item)] = next_state visited[next_item] = next_state current_state.add_transition(symbol.Name, next_state) return start
def find_conflict(self): conflicts = [] automaton_reverse, state_dict = state_transpose(self.automaton) for key, value in self.action.items(): if type(value) == type(set()): conflict_productions = [ x[1] for x in value if isinstance(x[1], Production) ] for production in conflict_productions: conflict_state = state_dict[key[0]][0] conflict_item = find_conflict_item(conflict_state, production) stack = [(conflict_state, conflict_item)] sentence = [y for y in production.Right] sentence.reverse() current_state = conflict_state current_item = conflict_item for y in sentence: current_item = Item(current_item.production, current_item.pos - 1, current_item.lookaheads) current_state = go_back(current_state, y, current_item, state_dict) stack.append((current_state, current_item)) stack.reverse() initial_item = find_initial_item(self.automaton) path = [(self.automaton, initial_item, False)] visited = {(initial_item, self.automaton.idx)} find_path_to( stack[0][0], stack[0][1], self.automaton, initial_item, path, visited ) # una lista de tuplas que es (estado en que estoy,item en el que estoy) terminals = items_to_terminals(path[:len(path) - 1], stack) conflicts.append( self._generate_error(value, terminals, [x[1] for x in path] + [x[1] for x in stack[1:]], key[0], key[1])) break return conflicts
def build_LR1_automaton(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]) # como cabecera solo queda el kernel closure = closure_lr1(start, firsts) automaton = State(frozenset(closure), True) # en visited si se guarda el estado completo pending = [start] visited = {start: automaton} while pending: current = pending.pop() current_state = visited[current] closure = closure_lr1(current, firsts) for symbol in G.terminals + G.nonTerminals: # (Get/Build `next_state`) # closure = closure_lr1(current,firsts) goto = goto_lr1(closure, symbol, firsts, True) if not goto: continue try: next_state = visited[goto] except KeyError: next_state = visited[goto] = State( frozenset(closure_lr1(goto, firsts)), True) pending.append(goto) current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
def build_LR1_automaton(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 = 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: # Your code here!!! (Get/Build `next_state`) next_state_key = goto_lr1(current_state.state, symbol, just_kernel=True) # next_state_key = frozenset([i.NextItem() for i in current_state.state if i.NextSymbol == symbol]) if not next_state_key: continue try: next_state = visited[next_state_key] except KeyError: next_state_items = goto_lr1(current_state.state, symbol, firsts) next_state = State(frozenset(next_state_items), True) pending.append(next_state_key) visited[next_state_key] = next_state current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
def FindStart(automata, state_conf, reduce_item_conflict): #Calcular las transiciones inversas ReverseAutomaton(automata) #Reducir el item de conflicto symbols_to_reduce = [] for symbol in reduce_item_conflict.production.Right: symbols_to_reduce.append(symbol) items_way_reverse = [(reduce_item_conflict, state_conf)] current_state = state_conf current_item = reduce_item_conflict item_pos = current_item.pos while symbols_to_reduce: #Mover al estado anterior symbol = symbols_to_reduce.pop() current_state = current_state.reverse_transitions[symbol.Name][0] item_pos -= 1 items_way_reverse.append((Item(reduce_item_conflict.production, item_pos), current_state)) return items_way_reverse[::-1]
def build_lr1_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=(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] current_closure = current_state.state for symbol in G.terminals + G.nonTerminals: kernel = goto_lr1(current_closure, symbol, just_kernel=True) if kernel == frozenset(): continue try: next_state = visited[kernel] except KeyError: goto = closure_lr1(kernel, firsts) visited[kernel] = next_state = State(frozenset(goto), True) pending.append(kernel) current_state.add_transition(symbol.Name, next_state) automaton.set_formatter(multiline_formatter) return automaton
def expand(self, item, firsts): next_symbol = item.NextSymbol if next_symbol is None or not next_symbol.IsNonTerminal: return [] lookaheads = ContainerSet() new_items = [] previews = item.Preview() for preview in previews: sentence = self.G.Epsilon for symbol in preview: sentence = sentence + symbol try: prev_first = firsts[sentence] except KeyError: prev_first = firsts[sentence] = compute_local_first(firsts, preview) lookaheads.update(prev_first) for prod in next_symbol.productions: new_item = Item(prod, 0, lookaheads = lookaheads) new_items.append(new_item) return new_items