Loading objects.py +135 −108 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional from typing import Set, List, Dict, Tuple, Optional from enum import Enum from copy import deepcopy # TODO ask: out or in the class #Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] # TODO Mypy typecheck class Operation(Enum): Union = 1 Intersection = 2 class Terminal: def __init__(self, name=str): def __init__(self, name: str): # str = "a"): self.name = name def __eq__(self, object): if isinstance(object, Terminal): return object.name == self.name return False def __hash__(self): return hash(self.name) class Nonterminal: def __init__(self, name=str): def __init__(self, name: str): self.name = name class State: def __init__(self, name=str): def __init__(self, name: str): self.name = name class REG: def __init__(self, nonterminals, terminals, rules, init): self.nonterminals = Set[Nonterminal] self.terminals = Set[Terminal] self.rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] self.init = Nonterminal Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] class DFA: def __init__(self, states, terminals, rules, init): self.states = Set[State] self.terminals = Set[Terminal] self.transition = Dict[Tuple[State, Terminal], State] self.init = State self.final = Set[State] def __init__(self, nonterminals: Set[Nonterminal], \ terminals: Set[Terminal], \ rules: Rules, \ init: Nonterminal): self.nonterminals = nonterminals self.terminals = terminals self.rules = rules self.init = init class DFA: Transition = Dict[Tuple[State, Terminal], State] def __init__(self, states: Set[State], \ terminals: Set[Terminal], \ transition: Transition, \ init: State, \ final: Set[State]): self.states = states self.terminals = terminals self.transition = transition self.init = init self.final = final # def total(self) -> DFA: def total(self): total = Dict[Tuple[State, Terminal], State] hell = State("h") self.states.add(hell) for state in self.states: for terminal in self.terminals: if (state, term) in self.transition: total[state, term] = self.transition[state, term] dfa = deepcopy(self) #total: Transition total = {} # better way? id = 0 hell = State(str(id)) while hell in dfa.states: id += 1 hell.name = str(id) dfa.states.add(hell) print(dfa.states) for state in dfa.states: for terminal in dfa.terminals: if (state, terminal) in dfa.transition: total[state, terminal] = dfa.transition[state, terminal] else: total[state, term] = hell total[state, terminal] = hell self.transition = total # TODO ask: or make/return copy of original DFA? dfa.transition = total return dfa # def complement(self) -> DFA: def complement(self): new_final = Set[State] for state in self.states: if state not in self.final: dfa = deepcopy(self) new_final: Set[State] for state in dfa.states: if state not in dfa.final: new_final.add(state) self.final = new_final # TODO ask: same as total class NFA: def __init__(self, states, terminals, transition, init, final): self.states = Set[State] self.terminals = Set[Terminal] self.transition = Dict[Tuple[State, Terminal], Set[State]] self.init = State self.final = Set[State] dfa.final = new_final return dfa # TODO ask: where to have this kind of functions? # TODO ask: "union" & "intersection" like this? def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: @staticmethod # def composition(dfa_1: DFA, dfa_2: DFA, operation: Operation) -> DFA: def composition(dfa_1, dfa_2, operation: Operation): dfa = DFA() # new states Loading @@ -89,9 +115,9 @@ def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: # new final if state_1 in dfa_1.final or state_2 in dfa_2.final: if operation == "union": if operation == Operation.Union: dfa.final.add(state) elif operation == "intersection" and \ elif operation == Operation.Intersection and \ state_1 in dfa_1.final and \ state_2 in dfa_2.final: dfa.final.add(state) Loading @@ -105,25 +131,26 @@ def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: return dfa @staticmethod # def union(dfa_1: DFA, dfa_2: DFA) -> DFA: def union(dfa_1, dfa_2): composition(dfa_1, dfa_2, Union) def test_dfa() -> DFA: dfa = DFA q_0 = State("q_0") q_1 = State("q_1") a = Terminal("a") dfa.init = q_0 dfa.final = {q_0} dfa.terminals = {a} dfa.transition = dict() dfa.transition[q_0, a] = q_1 dfa.transition[q_1, a] = q_1 return dfa @staticmethod # def intersection(dfa_1: DFA, dfa_2: DFA) -> DFA: def intersection(dfa_1, dfa_2): composition(dfa_1, dfa_2, Intersection) class NFA: def __init__(self, states: Set[State], \ terminals: Set[Terminal], \ transition: Dict[Tuple[State, Terminal], Set[State]], \ init: State, \ final: Set[State]): self.states = states self.terminals = terminal self.transition = transition self.init = init self.final = final dfa = test_dfa() print(len(dfa.transition)) dfa.total() print(len(dfa.transition)) b = Terminal("b") dfa.terminals.add(b) dfa.total() print(len(dfa.transition)) No newline at end of file parser.py +54 −22 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re import objects from objects import REG, DFA class Parser: Loading @@ -8,11 +8,10 @@ class Parser: pass # TODO ask: how should reg, dfa, ... look like? test_reg = ((S,A,B,C),(a,b,c),P,S) / P={S->a|aA|b, / test_reg = "((S,A,B,C),(a,b,c),P,S) \ P={S->a|aA|b, \ A->c}" def reg_to_str(self, reg: REG) -> str: out = "((" for neterminal in reg.neterminals: Loading @@ -25,11 +24,11 @@ test_reg = ((S,A,B,C),(a,b,c),P,S) / out.append(",") out.append(terminal) out.append(",P," + reg.init + ")\nP=") out.append(rules_to_str(self, reg.rules) out.append(rules_to_str(self, reg.rules)) return out # Rules = Dict[Nonterminal, List[Tuple[Terminal, Optional[Nonterminal]]]] # TODO ask: from objects import rules (as type)? def rules_to_str(self, rules): out = "{" Loading @@ -49,11 +48,44 @@ test_reg = ((S,A,B,C),(a,b,c),P,S) / return (out[:len(out) - 2] + "}") # def str_to_reg(self, source: str) -> REG: # re.match(...((nt),(t),P,S)\n rest test_dfa = "(0,a)=1\n(1,a)=0\nF={1}" def dfa_to_str(self, dfa: DFA, full=False) -> str: # full - verbose description of DFA - only for development, dismiss later def str_to_reg(self, source: str) -> REG: re.match(...((nt),(t),P,S)\n rest states = "{" for state in dfa.states: states += state.name + "," states = states[:-1] + "}" terminals = "{" for state in dfa.terminals: terminals += state.name + "," terminals = terminals[:-1] + "}" transition = "{" for key, state_2 in dfa.transition.items(): state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")=" + state_2.name + "\n" transition = transition[:-1] + "}" init = dfa.init.name final = "F={" for state in dfa.final: final += state.name + "," final = final[:-1] + "}" if full: return "DFA = (" + states + "," + terminals + ",d," + \ init + "," + final + ")\n" + "d = " + transition else: return transition + "\n" + final # all: string <-> formal object # reg Loading test.py 0 → 100644 +39 −0 Original line number Diff line number Diff line from parser import Parser from objects import Terminal, State, DFA def test_dfa(): q_0 = State("q_0") q_1 = State("q_1") a = Terminal("a") states = {q_0, q_1} init = q_0 final = {q_0} terminals = {a} transition = dict() transition[q_0, a] = q_1 transition[q_1, a] = q_1 dfa = DFA(states, terminals, transition, init, final) print(dfa) return dfa def main(): dfa = test_dfa() parser = Parser() # test: dfa_to_str print(parser.dfa_to_str(dfa)) print() print(parser.dfa_to_str(dfa, True)) # test: add terminal, make total #print(len(dfa.transition)) b = Terminal("b") dfa.terminals.add(b) tot_dfa = dfa.total() #print(len(dfa.transition)) print(parser.dfa_to_str(tot_dfa, True)) main() No newline at end of file Loading
objects.py +135 −108 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional from typing import Set, List, Dict, Tuple, Optional from enum import Enum from copy import deepcopy # TODO ask: out or in the class #Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] # TODO Mypy typecheck class Operation(Enum): Union = 1 Intersection = 2 class Terminal: def __init__(self, name=str): def __init__(self, name: str): # str = "a"): self.name = name def __eq__(self, object): if isinstance(object, Terminal): return object.name == self.name return False def __hash__(self): return hash(self.name) class Nonterminal: def __init__(self, name=str): def __init__(self, name: str): self.name = name class State: def __init__(self, name=str): def __init__(self, name: str): self.name = name class REG: def __init__(self, nonterminals, terminals, rules, init): self.nonterminals = Set[Nonterminal] self.terminals = Set[Terminal] self.rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] self.init = Nonterminal Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] class DFA: def __init__(self, states, terminals, rules, init): self.states = Set[State] self.terminals = Set[Terminal] self.transition = Dict[Tuple[State, Terminal], State] self.init = State self.final = Set[State] def __init__(self, nonterminals: Set[Nonterminal], \ terminals: Set[Terminal], \ rules: Rules, \ init: Nonterminal): self.nonterminals = nonterminals self.terminals = terminals self.rules = rules self.init = init class DFA: Transition = Dict[Tuple[State, Terminal], State] def __init__(self, states: Set[State], \ terminals: Set[Terminal], \ transition: Transition, \ init: State, \ final: Set[State]): self.states = states self.terminals = terminals self.transition = transition self.init = init self.final = final # def total(self) -> DFA: def total(self): total = Dict[Tuple[State, Terminal], State] hell = State("h") self.states.add(hell) for state in self.states: for terminal in self.terminals: if (state, term) in self.transition: total[state, term] = self.transition[state, term] dfa = deepcopy(self) #total: Transition total = {} # better way? id = 0 hell = State(str(id)) while hell in dfa.states: id += 1 hell.name = str(id) dfa.states.add(hell) print(dfa.states) for state in dfa.states: for terminal in dfa.terminals: if (state, terminal) in dfa.transition: total[state, terminal] = dfa.transition[state, terminal] else: total[state, term] = hell total[state, terminal] = hell self.transition = total # TODO ask: or make/return copy of original DFA? dfa.transition = total return dfa # def complement(self) -> DFA: def complement(self): new_final = Set[State] for state in self.states: if state not in self.final: dfa = deepcopy(self) new_final: Set[State] for state in dfa.states: if state not in dfa.final: new_final.add(state) self.final = new_final # TODO ask: same as total class NFA: def __init__(self, states, terminals, transition, init, final): self.states = Set[State] self.terminals = Set[Terminal] self.transition = Dict[Tuple[State, Terminal], Set[State]] self.init = State self.final = Set[State] dfa.final = new_final return dfa # TODO ask: where to have this kind of functions? # TODO ask: "union" & "intersection" like this? def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: @staticmethod # def composition(dfa_1: DFA, dfa_2: DFA, operation: Operation) -> DFA: def composition(dfa_1, dfa_2, operation: Operation): dfa = DFA() # new states Loading @@ -89,9 +115,9 @@ def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: # new final if state_1 in dfa_1.final or state_2 in dfa_2.final: if operation == "union": if operation == Operation.Union: dfa.final.add(state) elif operation == "intersection" and \ elif operation == Operation.Intersection and \ state_1 in dfa_1.final and \ state_2 in dfa_2.final: dfa.final.add(state) Loading @@ -105,25 +131,26 @@ def composition(dfa_1: DFA, dfa_2: DFA, operation: str) -> DFA: return dfa @staticmethod # def union(dfa_1: DFA, dfa_2: DFA) -> DFA: def union(dfa_1, dfa_2): composition(dfa_1, dfa_2, Union) def test_dfa() -> DFA: dfa = DFA q_0 = State("q_0") q_1 = State("q_1") a = Terminal("a") dfa.init = q_0 dfa.final = {q_0} dfa.terminals = {a} dfa.transition = dict() dfa.transition[q_0, a] = q_1 dfa.transition[q_1, a] = q_1 return dfa @staticmethod # def intersection(dfa_1: DFA, dfa_2: DFA) -> DFA: def intersection(dfa_1, dfa_2): composition(dfa_1, dfa_2, Intersection) class NFA: def __init__(self, states: Set[State], \ terminals: Set[Terminal], \ transition: Dict[Tuple[State, Terminal], Set[State]], \ init: State, \ final: Set[State]): self.states = states self.terminals = terminal self.transition = transition self.init = init self.final = final dfa = test_dfa() print(len(dfa.transition)) dfa.total() print(len(dfa.transition)) b = Terminal("b") dfa.terminals.add(b) dfa.total() print(len(dfa.transition)) No newline at end of file
parser.py +54 −22 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re import objects from objects import REG, DFA class Parser: Loading @@ -8,11 +8,10 @@ class Parser: pass # TODO ask: how should reg, dfa, ... look like? test_reg = ((S,A,B,C),(a,b,c),P,S) / P={S->a|aA|b, / test_reg = "((S,A,B,C),(a,b,c),P,S) \ P={S->a|aA|b, \ A->c}" def reg_to_str(self, reg: REG) -> str: out = "((" for neterminal in reg.neterminals: Loading @@ -25,11 +24,11 @@ test_reg = ((S,A,B,C),(a,b,c),P,S) / out.append(",") out.append(terminal) out.append(",P," + reg.init + ")\nP=") out.append(rules_to_str(self, reg.rules) out.append(rules_to_str(self, reg.rules)) return out # Rules = Dict[Nonterminal, List[Tuple[Terminal, Optional[Nonterminal]]]] # TODO ask: from objects import rules (as type)? def rules_to_str(self, rules): out = "{" Loading @@ -49,11 +48,44 @@ test_reg = ((S,A,B,C),(a,b,c),P,S) / return (out[:len(out) - 2] + "}") # def str_to_reg(self, source: str) -> REG: # re.match(...((nt),(t),P,S)\n rest test_dfa = "(0,a)=1\n(1,a)=0\nF={1}" def dfa_to_str(self, dfa: DFA, full=False) -> str: # full - verbose description of DFA - only for development, dismiss later def str_to_reg(self, source: str) -> REG: re.match(...((nt),(t),P,S)\n rest states = "{" for state in dfa.states: states += state.name + "," states = states[:-1] + "}" terminals = "{" for state in dfa.terminals: terminals += state.name + "," terminals = terminals[:-1] + "}" transition = "{" for key, state_2 in dfa.transition.items(): state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")=" + state_2.name + "\n" transition = transition[:-1] + "}" init = dfa.init.name final = "F={" for state in dfa.final: final += state.name + "," final = final[:-1] + "}" if full: return "DFA = (" + states + "," + terminals + ",d," + \ init + "," + final + ")\n" + "d = " + transition else: return transition + "\n" + final # all: string <-> formal object # reg Loading
test.py 0 → 100644 +39 −0 Original line number Diff line number Diff line from parser import Parser from objects import Terminal, State, DFA def test_dfa(): q_0 = State("q_0") q_1 = State("q_1") a = Terminal("a") states = {q_0, q_1} init = q_0 final = {q_0} terminals = {a} transition = dict() transition[q_0, a] = q_1 transition[q_1, a] = q_1 dfa = DFA(states, terminals, transition, init, final) print(dfa) return dfa def main(): dfa = test_dfa() parser = Parser() # test: dfa_to_str print(parser.dfa_to_str(dfa)) print() print(parser.dfa_to_str(dfa, True)) # test: add terminal, make total #print(len(dfa.transition)) b = Terminal("b") dfa.terminals.add(b) tot_dfa = dfa.total() #print(len(dfa.transition)) print(parser.dfa_to_str(tot_dfa, True)) main() No newline at end of file