Loading demo.py +7 −6 Original line number Diff line number Diff line from parser import Parser from objects import Character, Terminal, Nonterminal, State, DFA, REG, NFA from objects import Composition as comp from typing import Set, Dict, Tuple from reg_automata import Character, State, DFA, NFA from reg_automata import Composition as comp from reg_grammars import REG, Terminal, Nonterminal from typing import Set, Dict, Tuple, Union def make_dfa(states: Set[str], characters: Set[str], Loading Loading @@ -38,7 +39,7 @@ def reg_1(): nonterminals = {S, A} init = S terminals = {a} rules = dict() rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() rules[S] = {(a, S), (a)} rules[A] = {(a)} reg = REG(nonterminals, terminals, rules, init) Loading @@ -52,7 +53,7 @@ def reg_2(): nonterminals = {S, A} init = S terminals = {a} rules = dict() rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() reg = REG(nonterminals, terminals, rules, init) return reg Loading @@ -60,7 +61,7 @@ def nfa_1(): q0 = State("q0") q1 = State("q1") q2 = State("q2") a = Terminal("a") a = Character("a") transition = {(q0, a): {q1, q2}, (q1, a): {q1}, (q2, a): {q2}} nfa = NFA({q0, q1, q2}, {a}, transition, q0, {q1, q2}) return nfa Loading parser.py +3 −2 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re from objects import REG, DFA, NFA, Terminal from reg_automata import DFA, NFA from reg_grammars import REG, Terminal # TODO ask: commas at the ends of lines or not? Loading Loading @@ -28,7 +29,7 @@ class Parser: return out # TODO ask: import rules def rules_to_str(self, rules: REG.Rules): def rules_to_str(self, rules: REG.Rules) -> str: out = "" for rule in rules: out = out[:-1] + (",\n") Loading objects.py→reg_automata.py +8 −117 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar, Any from enum import Enum import enum from copy import deepcopy Loading @@ -12,19 +12,6 @@ class Composition(Enum): Subtraction = enum.auto() class Terminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Terminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class Character: def __init__(self, name: str): self.name = name Loading @@ -42,19 +29,6 @@ class Eps: pass class Nonterminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Nonterminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class State: def __init__(self, name: str): self.name = name Loading @@ -68,90 +42,6 @@ class State: return hash(self.name) class REG: Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon 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 assert self.check # TODO ask about concept def check(self) -> bool: # scheme of grammar - empty sets and dicts are implemention only variant if len(self.nonterminals) == 0: assert len(self.terminals) == 0 and len(self.rules) == 0 and self.init == None, "nonempty scheme of grammar" return True nonterminal_names = set(map(lambda x: x.name, self.nonterminals)) terminal_names = set(map(lambda x: x.name, self.terminals)) assert len(nonterminal_names.intersection(terminal_names)) == 0, "name conflict" for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[1] in self.nonterminals, "unknown nonterminal " + rule[1].name assert self.init in self.nonterminals, "init not in nonterminals" return True def reg_to_nfa(self) -> NFA: init = State(self.init.name) states: Set[State] = set() for nonterminal in self.nonterminals: state = State(nonterminal.name) states.add(state) characters: Set[Character] = set() for terminal in self.terminals: character = Character(terminal.name) characters.add(character) final = State("new_final") # TODO assert that name is unique, as for hell in make_total states.add(final) transition: Dict[Tuple[State, Character], Set[State]] = dict() for nonterminal in self.rules: state = State(nonterminal.name) for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) else: transition[state, character] = {final} # rule A -> aB becomes d(A, a) = B elif (state, rule[0]) in transition: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character].add(move) else: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character] = {move} # TODO if init -> \eps: nfa.final.add(nfa.init) # I need to know how to treat \eps nfa = NFA(states, characters, transition, init, {final}) return nfa class DFA: Transition = Dict[Tuple[State, Character], State] type_var = TypeVar('type_var') Loading @@ -173,7 +63,7 @@ class DFA: self.transition = self.dict_or_none(transition) self.init = init self.final = self.set_or_none(final) assert self.check assert self.check() def check(self) -> bool: # # scheme of automaton - empty sets and dicts are implemention only variant Loading Loading @@ -439,7 +329,9 @@ class DFA: i += 1 return dfa def dfa_to_reg(self) -> REG: def dfa_to_reg(self) -> Any: from reg_grammars import REG, Terminal, Nonterminal nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() Loading Loading @@ -484,10 +376,9 @@ class DFA: return reg def is_empty(self) -> bool: reached: Deque[State] = deque() reached.append(self.init) # TODO ask: I need to do it like this bc State is not iterable - shall it be? reachable: Set[State] = set() reachable.add(self.init) reached: Deque[State] = deque([self.init]) reachable: Set[State] = {self.init} while len(reached) > 0: actual = reached.popleft() for character in self.characters: Loading reg_grammars.py 0 → 100644 +115 −0 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, Dict, Union, Tuple, TypeVar from reg_automata import Character, State, NFA class Terminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Terminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class Eps: pass class Nonterminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Nonterminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class REG: Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon 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 assert self.check # TODO ask about concept def check(self) -> bool: # scheme of grammar - empty sets and dicts are implemention only variant if len(self.nonterminals) == 0: assert len(self.terminals) == 0 and len(self.rules) == 0 and self.init == None, "nonempty scheme of grammar" return True nonterminal_names = set(map(lambda x: x.name, self.nonterminals)) terminal_names = set(map(lambda x: x.name, self.terminals)) assert len(nonterminal_names.intersection(terminal_names)) == 0, "name conflict" for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[1] in self.nonterminals, "unknown nonterminal " + rule[1].name assert self.init in self.nonterminals, "init not in nonterminals" return True def reg_to_nfa(self) -> NFA: init = State(self.init.name) states: Set[State] = set() for nonterminal in self.nonterminals: state = State(nonterminal.name) states.add(state) characters: Set[Character] = set() for terminal in self.terminals: character = Character(terminal.name) characters.add(character) final = State("new_final") # TODO assert that name is unique, as for hell in make_total states.add(final) transition: Dict[Tuple[State, Character], Set[State]] = dict() for nonterminal in self.rules: state = State(nonterminal.name) for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) else: transition[state, character] = {final} # rule A -> aB becomes d(A, a) = B elif (state, rule[0]) in transition: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character].add(move) else: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character] = {move} # TODO if init -> \eps: nfa.final.add(nfa.init) # I need to know how to treat \eps nfa = NFA(states, characters, transition, init, {final}) return nfa No newline at end of file Loading
demo.py +7 −6 Original line number Diff line number Diff line from parser import Parser from objects import Character, Terminal, Nonterminal, State, DFA, REG, NFA from objects import Composition as comp from typing import Set, Dict, Tuple from reg_automata import Character, State, DFA, NFA from reg_automata import Composition as comp from reg_grammars import REG, Terminal, Nonterminal from typing import Set, Dict, Tuple, Union def make_dfa(states: Set[str], characters: Set[str], Loading Loading @@ -38,7 +39,7 @@ def reg_1(): nonterminals = {S, A} init = S terminals = {a} rules = dict() rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() rules[S] = {(a, S), (a)} rules[A] = {(a)} reg = REG(nonterminals, terminals, rules, init) Loading @@ -52,7 +53,7 @@ def reg_2(): nonterminals = {S, A} init = S terminals = {a} rules = dict() rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() reg = REG(nonterminals, terminals, rules, init) return reg Loading @@ -60,7 +61,7 @@ def nfa_1(): q0 = State("q0") q1 = State("q1") q2 = State("q2") a = Terminal("a") a = Character("a") transition = {(q0, a): {q1, q2}, (q1, a): {q1}, (q2, a): {q2}} nfa = NFA({q0, q1, q2}, {a}, transition, q0, {q1, q2}) return nfa Loading
parser.py +3 −2 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re from objects import REG, DFA, NFA, Terminal from reg_automata import DFA, NFA from reg_grammars import REG, Terminal # TODO ask: commas at the ends of lines or not? Loading Loading @@ -28,7 +29,7 @@ class Parser: return out # TODO ask: import rules def rules_to_str(self, rules: REG.Rules): def rules_to_str(self, rules: REG.Rules) -> str: out = "" for rule in rules: out = out[:-1] + (",\n") Loading
objects.py→reg_automata.py +8 −117 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar, Any from enum import Enum import enum from copy import deepcopy Loading @@ -12,19 +12,6 @@ class Composition(Enum): Subtraction = enum.auto() class Terminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Terminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class Character: def __init__(self, name: str): self.name = name Loading @@ -42,19 +29,6 @@ class Eps: pass class Nonterminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Nonterminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class State: def __init__(self, name: str): self.name = name Loading @@ -68,90 +42,6 @@ class State: return hash(self.name) class REG: Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon 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 assert self.check # TODO ask about concept def check(self) -> bool: # scheme of grammar - empty sets and dicts are implemention only variant if len(self.nonterminals) == 0: assert len(self.terminals) == 0 and len(self.rules) == 0 and self.init == None, "nonempty scheme of grammar" return True nonterminal_names = set(map(lambda x: x.name, self.nonterminals)) terminal_names = set(map(lambda x: x.name, self.terminals)) assert len(nonterminal_names.intersection(terminal_names)) == 0, "name conflict" for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[1] in self.nonterminals, "unknown nonterminal " + rule[1].name assert self.init in self.nonterminals, "init not in nonterminals" return True def reg_to_nfa(self) -> NFA: init = State(self.init.name) states: Set[State] = set() for nonterminal in self.nonterminals: state = State(nonterminal.name) states.add(state) characters: Set[Character] = set() for terminal in self.terminals: character = Character(terminal.name) characters.add(character) final = State("new_final") # TODO assert that name is unique, as for hell in make_total states.add(final) transition: Dict[Tuple[State, Character], Set[State]] = dict() for nonterminal in self.rules: state = State(nonterminal.name) for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) else: transition[state, character] = {final} # rule A -> aB becomes d(A, a) = B elif (state, rule[0]) in transition: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character].add(move) else: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character] = {move} # TODO if init -> \eps: nfa.final.add(nfa.init) # I need to know how to treat \eps nfa = NFA(states, characters, transition, init, {final}) return nfa class DFA: Transition = Dict[Tuple[State, Character], State] type_var = TypeVar('type_var') Loading @@ -173,7 +63,7 @@ class DFA: self.transition = self.dict_or_none(transition) self.init = init self.final = self.set_or_none(final) assert self.check assert self.check() def check(self) -> bool: # # scheme of automaton - empty sets and dicts are implemention only variant Loading Loading @@ -439,7 +329,9 @@ class DFA: i += 1 return dfa def dfa_to_reg(self) -> REG: def dfa_to_reg(self) -> Any: from reg_grammars import REG, Terminal, Nonterminal nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() Loading Loading @@ -484,10 +376,9 @@ class DFA: return reg def is_empty(self) -> bool: reached: Deque[State] = deque() reached.append(self.init) # TODO ask: I need to do it like this bc State is not iterable - shall it be? reachable: Set[State] = set() reachable.add(self.init) reached: Deque[State] = deque([self.init]) reachable: Set[State] = {self.init} while len(reached) > 0: actual = reached.popleft() for character in self.characters: Loading
reg_grammars.py 0 → 100644 +115 −0 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, Dict, Union, Tuple, TypeVar from reg_automata import Character, State, NFA class Terminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Terminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class Eps: pass class Nonterminal: def __init__(self, name: str): self.name = name def __eq__(self, obj): if isinstance(obj, Nonterminal): return obj.name == self.name return False def __hash__(self): return hash(self.name) class REG: Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon 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 assert self.check # TODO ask about concept def check(self) -> bool: # scheme of grammar - empty sets and dicts are implemention only variant if len(self.nonterminals) == 0: assert len(self.terminals) == 0 and len(self.rules) == 0 and self.init == None, "nonempty scheme of grammar" return True nonterminal_names = set(map(lambda x: x.name, self.nonterminals)) terminal_names = set(map(lambda x: x.name, self.terminals)) assert len(nonterminal_names.intersection(terminal_names)) == 0, "name conflict" for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name assert rule[1] in self.nonterminals, "unknown nonterminal " + rule[1].name assert self.init in self.nonterminals, "init not in nonterminals" return True def reg_to_nfa(self) -> NFA: init = State(self.init.name) states: Set[State] = set() for nonterminal in self.nonterminals: state = State(nonterminal.name) states.add(state) characters: Set[Character] = set() for terminal in self.terminals: character = Character(terminal.name) characters.add(character) final = State("new_final") # TODO assert that name is unique, as for hell in make_total states.add(final) transition: Dict[Tuple[State, Character], Set[State]] = dict() for nonterminal in self.rules: state = State(nonterminal.name) for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) else: transition[state, character] = {final} # rule A -> aB becomes d(A, a) = B elif (state, rule[0]) in transition: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character].add(move) else: character = Character(rule[0].name) move = State(rule[1].name) transition[state, character] = {move} # TODO if init -> \eps: nfa.final.add(nfa.init) # I need to know how to treat \eps nfa = NFA(states, characters, transition, init, {final}) return nfa No newline at end of file