Compare commits

...

3 Commits

Author SHA1 Message Date
Juhani Krekelä d7bab30809 Add regex_to_regex.py 2019-06-01 20:26:40 +03:00
Juhani Krekelä 440aedbf64 Add regex_to_nfa.py 2019-06-01 20:21:18 +03:00
Juhani Krekelä 4a789f6b16 Move prettyprint() to nfa.py 2019-06-01 19:36:22 +03:00
4 changed files with 152 additions and 32 deletions

31
nfa.py
View File

@ -8,3 +8,34 @@ def copy_nfa(nfa):
transitions_copy[from_state] = nfa.transitions[from_state].copy()
return NFA(nfa.start, nfa.accept, transitions_copy)
def prettyprint(nfa):
def process_state(state):
nonlocal start, accept
t = ''
if state == start:
# Bold
t += '\x1b[1m'
if state in accept:
# Green
t += '\x1b[32m'
if t != '':
return t + str(state) + '\x1b[0m'
else:
return str(state)
start, accept, transitions = nfa
states = transitions.keys()
print('\t' + '\t'.join(map(process_state, states)))
for from_state in states:
t = []
for to_state in states:
if to_state in transitions[from_state]:
t.append(str(transitions[from_state][to_state]))
else:
t.append('\x1b[90m-\x1b[0m')
print(process_state(from_state) + '\t' + '\t'.join(t))

View File

@ -1,7 +1,7 @@
import enum
from regex import lit, concat, bar, star
from nfa import NFA, copy_nfa
from nfa import NFA, copy_nfa, prettyprint
def remove_states(nfa):
start, accept, transitions = nfa
@ -109,37 +109,6 @@ def to_regex(nfa):
return processed.transitions[_.start][_.end]
def prettyprint(nfa):
def process_state(state):
nonlocal start, accept
t = ''
if state == start:
# Bold
t += '\x1b[1m'
if state in accept:
# Green
t += '\x1b[32m'
if t != '':
return t + str(state) + '\x1b[0m'
else:
return str(state)
start, accept, transitions = nfa
states = transitions.keys()
print('\t' + '\t'.join(map(process_state, states)))
for from_state in states:
t = []
for to_state in states:
if to_state in transitions[from_state]:
t.append(str(transitions[from_state][to_state]))
else:
t.append('\x1b[90m-\x1b[0m')
print(process_state(from_state) + '\t' + '\t'.join(t))
def main():
nfa = NFA('start', ['0'], {
'start': {'1': lit('i'), '2': lit('d')},

105
regex_to_nfa.py Normal file
View File

@ -0,0 +1,105 @@
from regex import Literal, Concatenation, Alternation, Star, lit, concat, bar, star
from nfa import NFA, prettyprint
def to_nfa(regex):
def new_state():
nonlocal state_name_counter, transitions
state_name = state_name_counter
state_name_counter += 1
transitions[state_name] = {}
return state_name
def worker(node):
nonlocal transitions
if type(node) == Literal:
# text
# (start) ---------> (end)
start_state = new_state()
end_state = new_state()
transitions[start_state][end_state] = lit(node.text)
return (start_state, end_state)
elif type(node) == Concatenation:
# (start) → […] → […] → […]
start_state = new_state()
prev_state = start_state
for element in node.elements:
inner_start, inner_end = worker(element)
# (prev) → (inner_start) → […]
transitions[prev_state][inner_start] = lit('')
# Link next element straight to the inner end
# state
prev_state = inner_end
return (start_state, prev_state)
elif type(node) == Alternation:
# +-> […] --+
# | |
# (start) --+-> […] --+-> (end)
# | |
# +-> […] --+
start_state = new_state()
end_state = new_state()
for element in node.elements:
inner_start, inner_end = worker(element)
# (start) → (inner_start) → […]
transitions[start_state][inner_start] = lit('')
# […] → (inner_end) → (end)
transitions[inner_end][end_state] = lit('')
return (start_state, end_state)
elif type(node) == Star:
# +- […] <-+
# | |
# v |
# (start) --+--> (end)
start_state = new_state()
end_state = new_state()
inner_start, inner_end = worker(node.element)
# (start) → (inner_start) → […]
transitions[start_state][inner_start] = lit('')
# […] → (inner_end) → (start)
transitions[inner_end][start_state] = lit('')
# (start) → (end)
transitions[start_state][end_state] = lit('')
return (start_state, end_state)
else:
raise ValueError('node has to be Literal, Concatenation, Alternation, or Star')
state_name_counter = 0
transitions = {}
start_state, end_state = worker(regex)
return NFA(start_state, [end_state], transitions)
def main():
regex = concat(lit('x'), star(bar(lit('a'), lit('b'))), lit('y'))
print(regex)
nfa = to_nfa(regex)
prettyprint(nfa)
if __name__ == '__main__':
main()

15
regex_to_regex.py Normal file
View File

@ -0,0 +1,15 @@
from regex import lit, concat, bar, star
from regex_to_nfa import to_nfa
from nfa_to_regex import to_regex
def main():
regex = concat(bar(lit('foo'), lit('bar')), bar(lit('baz'), lit('qux')))
print(regex)
nfa = to_nfa(regex)
regex_prime = to_regex(nfa)
print(regex_prime)
if __name__ == '__main__':
main()