1
#=======================================================================
3
# Python Lexical Analyser
5
# Converting NFA to DFA
7
#=======================================================================
10
from Machines import LOWEST_PRIORITY
11
from Transitions import TransitionMap
13
def nfa_to_dfa(old_machine, debug = None):
15
Given a nondeterministic Machine, return a new equivalent
16
Machine which is deterministic.
18
# We build a new machine whose states correspond to sets of states
19
# in the old machine. Initially we add a new state corresponding to
20
# the epsilon-closure of each initial old state. Then we give transitions
21
# to each new state which are the union of all transitions out of any
22
# of the corresponding old states. The new state reached on a given
23
# character is the one corresponding to the set of states reachable
24
# on that character from any of the old states. As new combinations of
25
# old states are created, new states are added as needed until closure
27
new_machine = Machines.FastMachine()
28
state_map = StateMap(new_machine)
29
# Seed the process using the initial states of the old machine.
30
# Make the corresponding new states into initial states of the new
31
# machine with the same names.
32
for (key, old_state) in old_machine.initial_states.items():
33
new_state = state_map.old_to_new(epsilon_closure(old_state))
34
new_machine.make_initial_state(key, new_state)
35
# Tricky bit here: we add things to the end of this list while we're
36
# iterating over it. The iteration stops when closure is achieved.
37
for new_state in new_machine.states:
38
transitions = TransitionMap()
39
for old_state in state_map.new_to_old(new_state).keys():
40
for event, old_target_states in old_state.transitions.items():
41
if event and old_target_states:
42
transitions.add_set(event, set_epsilon_closure(old_target_states))
43
for event, old_states in transitions.items():
44
new_machine.add_transitions(new_state, event, state_map.old_to_new(old_states))
46
debug.write("\n===== State Mapping =====\n")
50
def set_epsilon_closure(state_set):
52
Given a set of states, return the union of the epsilon
53
closures of its member states.
56
for state1 in state_set.keys():
57
for state2 in epsilon_closure(state1).keys():
61
def epsilon_closure(state):
63
Return the set of states reachable from the given state
67
result = state.epsilon_closure
70
state.epsilon_closure = result
71
add_to_epsilon_closure(result, state)
74
def add_to_epsilon_closure(state_set, state):
76
Recursively add to |state_set| states reachable from the given state
79
if not state_set.get(state, 0):
81
state_set_2 = state.transitions.get_epsilon()
83
for state2 in state_set_2.keys():
84
add_to_epsilon_closure(state_set, state2)
88
Helper class used by nfa_to_dfa() to map back and forth between
89
sets of states from the old machine and states of the new machine.
91
new_machine = None # Machine
92
old_to_new_dict = None # {(old_state,...) : new_state}
93
new_to_old_dict = None # {id(new_state) : old_state_set}
95
def __init__(self, new_machine):
96
self.new_machine = new_machine
97
self.old_to_new_dict = {}
98
self.new_to_old_dict= {}
100
def old_to_new(self, old_state_set):
102
Return the state of the new machine corresponding to the
103
set of old machine states represented by |state_set|. A new
104
state will be created if necessary. If any of the old states
105
are accepting states, the new state will be an accepting state
106
with the highest priority action from the old states.
108
key = self.make_key(old_state_set)
109
new_state = self.old_to_new_dict.get(key, None)
111
action = self.highest_priority_action(old_state_set)
112
new_state = self.new_machine.new_state(action)
113
self.old_to_new_dict[key] = new_state
114
self.new_to_old_dict[id(new_state)] = old_state_set
115
#for old_state in old_state_set.keys():
116
#new_state.merge_actions(old_state)
119
def highest_priority_action(self, state_set):
121
best_priority = LOWEST_PRIORITY
122
for state in state_set.keys():
123
priority = state.action_priority
124
if priority > best_priority:
125
best_action = state.action
126
best_priority = priority
129
# def old_to_new_set(self, old_state_set):
131
# Return the new state corresponding to a set of old states as
134
# return {self.old_to_new(old_state_set):1}
136
def new_to_old(self, new_state):
137
"""Given a new state, return a set of corresponding old states."""
138
return self.new_to_old_dict[id(new_state)]
140
def make_key(self, state_set):
142
Convert a set of states into a uniquified
143
sorted tuple suitable for use as a dictionary key.
145
lst = state_set.keys()
149
def dump(self, file):
150
from Transitions import state_set_str
151
for new_state in self.new_machine.states:
152
old_state_set = self.new_to_old_dict[id(new_state)]
153
file.write(" State %s <-- %s\n" % (
154
new_state['number'], state_set_str(old_state_set)))