Loading demo.py +11 −5 Original line number Original line Diff line number Diff line Loading @@ -9,7 +9,8 @@ def make_dfa(states: Set[str], characters: Set[str], new_init = State(init) new_init = State(init) new_states: Set[State] = set() new_states: Set[State] = set() dfa = DFA(new_states.add(new_init), set(), {}, new_init, set()) new_states.add(new_init) dfa = DFA(new_states, set(), {}, new_init, set()) for name in states: for name in states: state = State(name) state = State(name) Loading Loading @@ -181,16 +182,21 @@ def main(): print(parser.dfa_to_str(dfa_4, True)) print(parser.dfa_to_str(dfa_4, True)) print() print() dfareg = dfa_4.dfa_to_reg() dfareg = dfa_4.dfa_to_reg() print("DFA transformated to REG:") print("DFA transformed to REG:") print(parser.reg_to_str(dfareg, True)) print(parser.reg_to_str(dfareg, True)) print() print() regdfa = dfareg.reg_to_nfa() regdfa = dfareg.reg_to_nfa() print("REG transformated to NFA:") print("REG transformed to NFA:") print(parser.nfa_to_str(regdfa, True)) print(parser.nfa_to_str(regdfa, True)) print() print() #det = nfa1.determinize() print("__________________________________") #print(parser.dfa_to_str(det, True)) print("NFA.determinize()") print("Determinization of NFA to DFA:") det = nfa1.determinize() print(parser.nfa_to_str(nfa1, True)) print() print(parser.dfa_to_str(det, True)) print("__________________________________") print("__________________________________") print("DFA.is_equivalent()") print("DFA.is_equivalent()") Loading objects.py +31 −38 Original line number Original line Diff line number Diff line from __future__ import annotations from __future__ import annotations from typing import Set, List, Dict, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from enum import Enum from enum import Enum import enum import enum from copy import deepcopy from copy import deepcopy Loading Loading @@ -69,7 +69,7 @@ class State: class REG: class REG: Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') type_var = TypeVar('type_var') # TODO should accept init -> epsilon # TODO should accept init -> epsilon Loading Loading @@ -97,7 +97,7 @@ class REG: for nonterminal in self.rules: for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: for rule in self.rules[nonterminal]: if type(rule) == Terminal: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name assert rule in self.terminals, "unknown terminal " + rule.name else: else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[0] in self.terminals, "unknown terminal " + rule[0].name Loading Loading @@ -129,7 +129,7 @@ class REG: for rule in self.rules[nonterminal]: for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final # rule A -> a becomes d(A, a) = final if type(rule) == Terminal: # TODO and a is not \eps if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) character = Character(rule.name) if (state, character) in transition: if (state, character) in transition: transition[state, character].add(final) transition[state, character].add(final) Loading Loading @@ -186,7 +186,8 @@ class DFA: for (state, character) in self.transition: for (state, character) in self.transition: assert state in self.states, "unknown state " + state.name assert state in self.states, "unknown state " + state.name assert character in self.characters, "unknown character " + character.name assert character in self.characters, "unknown character " + character.name assert self.transition[state, character] in self.states, "unknown state " + self.transition[state, character].name assert self.transition[state, character] in self.states, "unknown state " + self.transition[ state, character].name assert self.init in self.states, "init not in states" assert self.init in self.states, "init not in states" for state in self.final: for state in self.final: Loading Loading @@ -331,17 +332,8 @@ class DFA: return dfa return dfa # TODO sorted(set, key = lambda x: x.name) sorted_terminals def sort_characters(self) -> List[Character]: def sort_characters(self) -> List[Character]: to_sort = list(deepcopy(self.characters)) return sorted(self.characters, key=lambda x: x.name) names = [] for character in to_sort: names.append((character.name, character)) names.sort() sorted_characters = [] for name, character in names: sorted_characters.append(character) return sorted_characters def minimize(self) -> DFA: def minimize(self) -> DFA: dfa = deepcopy(self) dfa = deepcopy(self) Loading Loading @@ -450,7 +442,7 @@ class DFA: def dfa_to_reg(self) -> REG: def dfa_to_reg(self) -> REG: nonterminals: Set[Nonterminal] = set() nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] = dict() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() for state in self.states: for state in self.states: nonterminal = Nonterminal(state.name) nonterminal = Nonterminal(state.name) Loading @@ -473,7 +465,7 @@ class DFA: else: else: rules[init] = {(terminal, nonterminal2)} rules[init] = {(terminal, nonterminal2)} if move in self.final: if move in self.final: rules[init].add((terminal)) rules[init].add(terminal) else: else: nonterminal1 = Nonterminal(state.name) nonterminal1 = Nonterminal(state.name) nonterminal2 = Nonterminal(move.name) nonterminal2 = Nonterminal(move.name) Loading Loading @@ -508,7 +500,7 @@ class DFA: # Ha! # Ha! def is_universal(self): def is_universal(self): return self.is_empty(self.complement()) return self.complement().is_empty() def is_equivalent(self, dfa: DFA) -> bool: def is_equivalent(self, dfa: DFA) -> bool: self.complement() self.complement() Loading Loading @@ -543,42 +535,43 @@ class NFA: self.final = self.set_or_none(final) self.final = self.set_or_none(final) def determinize(self) -> DFA: def determinize(self) -> DFA: states = set(frozenset({self.init})) states: Set[FrozenSet[State]] = set() states.add(frozenset({self.init})) transition = {} transition = {} final = set() final = set() done: Set[State] = set() done: Set[FrozenSet[State]] = set() todo = states.difference(done) while len(states.difference(done)) > 0: while len(todo) > 0: subset = (states.difference(done)).pop() # arbitrary element from set subset = iter(todo).next() # arbitrary element from set if len(subset.intersection(self.final)) > 0: if subset.difference(self.final) > 0: final.add(subset) final.add(subset) for character in self.characters: for character in self.characters: new_subset = set() new_subset: Set[State] = set() for state in subset: for state in subset: if (state, character) in self.transition: if (state, character) in self.transition: new_subset.add(self.transition[state, character]) new_subset = new_subset.union(self.transition[state, character]) states.add(new_subset) transition[subset, character] = new_subset states.add(frozenset(new_subset)) transition[subset, character] = frozenset(new_subset) done.add(subset) done.add(subset) new_states: Set[State] = set() new_states: Set[State] = set() new_transition: Dict[Tuple[State, Character], State] = dict() new_transition: Dict[Tuple[State, Character], State] = dict() new_final: Set[State] = set() new_final: Set[State] = set() for state in states: new_states.add(self.unset(state)) for state_set in states: for state in final: new_states.add(self.unset(state_set)) new_final.add(self.unset(state)) for state_set in final: for state, character in transition: new_final.add(self.unset(state_set)) new_transition[self.unset(state), character] = self.unset(self.transition[state, character]) for state_set, character in transition: new_transition[self.unset(state_set), character] = self.unset(transition[state_set, character]) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) return dfa return dfa def unset(self, states: Set[State]) -> State: def unset(self, states: FrozenSet[State]) -> State: return State('_'.join(set(map(lambda x: x.name, states)))) return State('_'.join(set(map(lambda x: x.name, sorted(states, key=lambda x: x.name))))) # would be function for in epsilon NFA # would be function for in epsilon NFA def eliminate_epsilon(self) -> NFA: def eliminate_epsilon(self) -> NFA: Loading parser.py +8 −8 Original line number Original line Diff line number Diff line from typing import List, Dict, Tuple, Optional from typing import List, Dict, Tuple, Optional import re import re from objects import REG, DFA, Terminal from objects import REG, DFA, NFA, Terminal # TODO ask: commas at the ends of lines or not? # TODO ask: commas at the ends of lines or not? Loading Loading @@ -38,7 +38,7 @@ class Parser: out += (rule.name + "->") out += (rule.name + "->") for variant in rewrite: for variant in rewrite: if type(variant) == Terminal: if isinstance(variant, Terminal): out += variant.name out += variant.name else: else: for i in range(len(variant)): for i in range(len(variant)): Loading Loading @@ -88,24 +88,24 @@ class Parser: return transition + "\n" + final return transition + "\n" + final def nfa_to_str(self, dfa: DFA, full : bool = False) -> str: def nfa_to_str(self, nfa: NFA, full : bool = False) -> str: # full - verbose description of DFA - only for development, dismiss later # full - verbose description of DFA - only for development, dismiss later states = "{" states = "{" for state in dfa.states: for state in nfa.states: states += state.name + "," states += state.name + "," states = states[:-1] + "}" states = states[:-1] + "}" # Vlada: states = ",".join(dfa.states) but I use it wrong or what # Vlada: states = ",".join(dfa.states) but I use it wrong or what characters = "{" characters = "{" for character in dfa.characters: for character in nfa.characters: characters += character.name + "," characters += character.name + "," characters = characters[:-1] + "}" characters = characters[:-1] + "}" transition = "" transition = "" for key, set_states in dfa.transition.items(): for key, set_states in nfa.transition.items(): state_1, terminal = key state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")={" transition += "(" + state_1.name + "," + terminal.name + ")={" for state in set_states: for state in set_states: Loading @@ -113,10 +113,10 @@ class Parser: transition = transition[:-1] + "}\n" transition = transition[:-1] + "}\n" transition = "{" + transition[:-1] + "}" transition = "{" + transition[:-1] + "}" init = dfa.init.name init = nfa.init.name final = "F={" final = "F={" for state in dfa.final: for state in nfa.final: final += state.name + "," final += state.name + "," final = final[:-1] + "}" final = final[:-1] + "}" Loading Loading
demo.py +11 −5 Original line number Original line Diff line number Diff line Loading @@ -9,7 +9,8 @@ def make_dfa(states: Set[str], characters: Set[str], new_init = State(init) new_init = State(init) new_states: Set[State] = set() new_states: Set[State] = set() dfa = DFA(new_states.add(new_init), set(), {}, new_init, set()) new_states.add(new_init) dfa = DFA(new_states, set(), {}, new_init, set()) for name in states: for name in states: state = State(name) state = State(name) Loading Loading @@ -181,16 +182,21 @@ def main(): print(parser.dfa_to_str(dfa_4, True)) print(parser.dfa_to_str(dfa_4, True)) print() print() dfareg = dfa_4.dfa_to_reg() dfareg = dfa_4.dfa_to_reg() print("DFA transformated to REG:") print("DFA transformed to REG:") print(parser.reg_to_str(dfareg, True)) print(parser.reg_to_str(dfareg, True)) print() print() regdfa = dfareg.reg_to_nfa() regdfa = dfareg.reg_to_nfa() print("REG transformated to NFA:") print("REG transformed to NFA:") print(parser.nfa_to_str(regdfa, True)) print(parser.nfa_to_str(regdfa, True)) print() print() #det = nfa1.determinize() print("__________________________________") #print(parser.dfa_to_str(det, True)) print("NFA.determinize()") print("Determinization of NFA to DFA:") det = nfa1.determinize() print(parser.nfa_to_str(nfa1, True)) print() print(parser.dfa_to_str(det, True)) print("__________________________________") print("__________________________________") print("DFA.is_equivalent()") print("DFA.is_equivalent()") Loading
objects.py +31 −38 Original line number Original line Diff line number Diff line from __future__ import annotations from __future__ import annotations from typing import Set, List, Dict, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from enum import Enum from enum import Enum import enum import enum from copy import deepcopy from copy import deepcopy Loading Loading @@ -69,7 +69,7 @@ class State: class REG: class REG: Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') type_var = TypeVar('type_var') # TODO should accept init -> epsilon # TODO should accept init -> epsilon Loading Loading @@ -97,7 +97,7 @@ class REG: for nonterminal in self.rules: for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: for rule in self.rules[nonterminal]: if type(rule) == Terminal: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name assert rule in self.terminals, "unknown terminal " + rule.name else: else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[0] in self.terminals, "unknown terminal " + rule[0].name Loading Loading @@ -129,7 +129,7 @@ class REG: for rule in self.rules[nonterminal]: for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final # rule A -> a becomes d(A, a) = final if type(rule) == Terminal: # TODO and a is not \eps if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) character = Character(rule.name) if (state, character) in transition: if (state, character) in transition: transition[state, character].add(final) transition[state, character].add(final) Loading Loading @@ -186,7 +186,8 @@ class DFA: for (state, character) in self.transition: for (state, character) in self.transition: assert state in self.states, "unknown state " + state.name assert state in self.states, "unknown state " + state.name assert character in self.characters, "unknown character " + character.name assert character in self.characters, "unknown character " + character.name assert self.transition[state, character] in self.states, "unknown state " + self.transition[state, character].name assert self.transition[state, character] in self.states, "unknown state " + self.transition[ state, character].name assert self.init in self.states, "init not in states" assert self.init in self.states, "init not in states" for state in self.final: for state in self.final: Loading Loading @@ -331,17 +332,8 @@ class DFA: return dfa return dfa # TODO sorted(set, key = lambda x: x.name) sorted_terminals def sort_characters(self) -> List[Character]: def sort_characters(self) -> List[Character]: to_sort = list(deepcopy(self.characters)) return sorted(self.characters, key=lambda x: x.name) names = [] for character in to_sort: names.append((character.name, character)) names.sort() sorted_characters = [] for name, character in names: sorted_characters.append(character) return sorted_characters def minimize(self) -> DFA: def minimize(self) -> DFA: dfa = deepcopy(self) dfa = deepcopy(self) Loading Loading @@ -450,7 +442,7 @@ class DFA: def dfa_to_reg(self) -> REG: def dfa_to_reg(self) -> REG: nonterminals: Set[Nonterminal] = set() nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] = dict() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() for state in self.states: for state in self.states: nonterminal = Nonterminal(state.name) nonterminal = Nonterminal(state.name) Loading @@ -473,7 +465,7 @@ class DFA: else: else: rules[init] = {(terminal, nonterminal2)} rules[init] = {(terminal, nonterminal2)} if move in self.final: if move in self.final: rules[init].add((terminal)) rules[init].add(terminal) else: else: nonterminal1 = Nonterminal(state.name) nonterminal1 = Nonterminal(state.name) nonterminal2 = Nonterminal(move.name) nonterminal2 = Nonterminal(move.name) Loading Loading @@ -508,7 +500,7 @@ class DFA: # Ha! # Ha! def is_universal(self): def is_universal(self): return self.is_empty(self.complement()) return self.complement().is_empty() def is_equivalent(self, dfa: DFA) -> bool: def is_equivalent(self, dfa: DFA) -> bool: self.complement() self.complement() Loading Loading @@ -543,42 +535,43 @@ class NFA: self.final = self.set_or_none(final) self.final = self.set_or_none(final) def determinize(self) -> DFA: def determinize(self) -> DFA: states = set(frozenset({self.init})) states: Set[FrozenSet[State]] = set() states.add(frozenset({self.init})) transition = {} transition = {} final = set() final = set() done: Set[State] = set() done: Set[FrozenSet[State]] = set() todo = states.difference(done) while len(states.difference(done)) > 0: while len(todo) > 0: subset = (states.difference(done)).pop() # arbitrary element from set subset = iter(todo).next() # arbitrary element from set if len(subset.intersection(self.final)) > 0: if subset.difference(self.final) > 0: final.add(subset) final.add(subset) for character in self.characters: for character in self.characters: new_subset = set() new_subset: Set[State] = set() for state in subset: for state in subset: if (state, character) in self.transition: if (state, character) in self.transition: new_subset.add(self.transition[state, character]) new_subset = new_subset.union(self.transition[state, character]) states.add(new_subset) transition[subset, character] = new_subset states.add(frozenset(new_subset)) transition[subset, character] = frozenset(new_subset) done.add(subset) done.add(subset) new_states: Set[State] = set() new_states: Set[State] = set() new_transition: Dict[Tuple[State, Character], State] = dict() new_transition: Dict[Tuple[State, Character], State] = dict() new_final: Set[State] = set() new_final: Set[State] = set() for state in states: new_states.add(self.unset(state)) for state_set in states: for state in final: new_states.add(self.unset(state_set)) new_final.add(self.unset(state)) for state_set in final: for state, character in transition: new_final.add(self.unset(state_set)) new_transition[self.unset(state), character] = self.unset(self.transition[state, character]) for state_set, character in transition: new_transition[self.unset(state_set), character] = self.unset(transition[state_set, character]) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) return dfa return dfa def unset(self, states: Set[State]) -> State: def unset(self, states: FrozenSet[State]) -> State: return State('_'.join(set(map(lambda x: x.name, states)))) return State('_'.join(set(map(lambda x: x.name, sorted(states, key=lambda x: x.name))))) # would be function for in epsilon NFA # would be function for in epsilon NFA def eliminate_epsilon(self) -> NFA: def eliminate_epsilon(self) -> NFA: Loading
parser.py +8 −8 Original line number Original line Diff line number Diff line from typing import List, Dict, Tuple, Optional from typing import List, Dict, Tuple, Optional import re import re from objects import REG, DFA, Terminal from objects import REG, DFA, NFA, Terminal # TODO ask: commas at the ends of lines or not? # TODO ask: commas at the ends of lines or not? Loading Loading @@ -38,7 +38,7 @@ class Parser: out += (rule.name + "->") out += (rule.name + "->") for variant in rewrite: for variant in rewrite: if type(variant) == Terminal: if isinstance(variant, Terminal): out += variant.name out += variant.name else: else: for i in range(len(variant)): for i in range(len(variant)): Loading Loading @@ -88,24 +88,24 @@ class Parser: return transition + "\n" + final return transition + "\n" + final def nfa_to_str(self, dfa: DFA, full : bool = False) -> str: def nfa_to_str(self, nfa: NFA, full : bool = False) -> str: # full - verbose description of DFA - only for development, dismiss later # full - verbose description of DFA - only for development, dismiss later states = "{" states = "{" for state in dfa.states: for state in nfa.states: states += state.name + "," states += state.name + "," states = states[:-1] + "}" states = states[:-1] + "}" # Vlada: states = ",".join(dfa.states) but I use it wrong or what # Vlada: states = ",".join(dfa.states) but I use it wrong or what characters = "{" characters = "{" for character in dfa.characters: for character in nfa.characters: characters += character.name + "," characters += character.name + "," characters = characters[:-1] + "}" characters = characters[:-1] + "}" transition = "" transition = "" for key, set_states in dfa.transition.items(): for key, set_states in nfa.transition.items(): state_1, terminal = key state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")={" transition += "(" + state_1.name + "," + terminal.name + ")={" for state in set_states: for state in set_states: Loading @@ -113,10 +113,10 @@ class Parser: transition = transition[:-1] + "}\n" transition = transition[:-1] + "}\n" transition = "{" + transition[:-1] + "}" transition = "{" + transition[:-1] + "}" init = dfa.init.name init = nfa.init.name final = "F={" final = "F={" for state in dfa.final: for state in nfa.final: final += state.name + "," final += state.name + "," final = final[:-1] + "}" final = final[:-1] + "}" Loading