| Index: third_party/cython/src/Cython/Plex/DFA.py
|
| diff --git a/third_party/cython/src/Cython/Plex/DFA.py b/third_party/cython/src/Cython/Plex/DFA.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..510d39318cea2b7ef1676620e0229137263fad7f
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Cython/Plex/DFA.py
|
| @@ -0,0 +1,156 @@
|
| +#=======================================================================
|
| +#
|
| +# Python Lexical Analyser
|
| +#
|
| +# Converting NFA to DFA
|
| +#
|
| +#=======================================================================
|
| +
|
| +import Machines
|
| +from Machines import LOWEST_PRIORITY
|
| +from Transitions import TransitionMap
|
| +
|
| +def nfa_to_dfa(old_machine, debug = None):
|
| + """
|
| + Given a nondeterministic Machine, return a new equivalent
|
| + Machine which is deterministic.
|
| + """
|
| + # We build a new machine whose states correspond to sets of states
|
| + # in the old machine. Initially we add a new state corresponding to
|
| + # the epsilon-closure of each initial old state. Then we give transitions
|
| + # to each new state which are the union of all transitions out of any
|
| + # of the corresponding old states. The new state reached on a given
|
| + # character is the one corresponding to the set of states reachable
|
| + # on that character from any of the old states. As new combinations of
|
| + # old states are created, new states are added as needed until closure
|
| + # is reached.
|
| + new_machine = Machines.FastMachine()
|
| + state_map = StateMap(new_machine)
|
| + # Seed the process using the initial states of the old machine.
|
| + # Make the corresponding new states into initial states of the new
|
| + # machine with the same names.
|
| + for (key, old_state) in old_machine.initial_states.iteritems():
|
| + new_state = state_map.old_to_new(epsilon_closure(old_state))
|
| + new_machine.make_initial_state(key, new_state)
|
| + # Tricky bit here: we add things to the end of this list while we're
|
| + # iterating over it. The iteration stops when closure is achieved.
|
| + for new_state in new_machine.states:
|
| + transitions = TransitionMap()
|
| + for old_state in state_map.new_to_old(new_state):
|
| + for event, old_target_states in old_state.transitions.iteritems():
|
| + if event and old_target_states:
|
| + transitions.add_set(event, set_epsilon_closure(old_target_states))
|
| + for event, old_states in transitions.iteritems():
|
| + new_machine.add_transitions(new_state, event, state_map.old_to_new(old_states))
|
| + if debug:
|
| + debug.write("\n===== State Mapping =====\n")
|
| + state_map.dump(debug)
|
| + return new_machine
|
| +
|
| +def set_epsilon_closure(state_set):
|
| + """
|
| + Given a set of states, return the union of the epsilon
|
| + closures of its member states.
|
| + """
|
| + result = {}
|
| + for state1 in state_set:
|
| + for state2 in epsilon_closure(state1):
|
| + result[state2] = 1
|
| + return result
|
| +
|
| +def epsilon_closure(state):
|
| + """
|
| + Return the set of states reachable from the given state
|
| + by epsilon moves.
|
| + """
|
| + # Cache the result
|
| + result = state.epsilon_closure
|
| + if result is None:
|
| + result = {}
|
| + state.epsilon_closure = result
|
| + add_to_epsilon_closure(result, state)
|
| + return result
|
| +
|
| +def add_to_epsilon_closure(state_set, state):
|
| + """
|
| + Recursively add to |state_set| states reachable from the given state
|
| + by epsilon moves.
|
| + """
|
| + if not state_set.get(state, 0):
|
| + state_set[state] = 1
|
| + state_set_2 = state.transitions.get_epsilon()
|
| + if state_set_2:
|
| + for state2 in state_set_2:
|
| + add_to_epsilon_closure(state_set, state2)
|
| +
|
| +class StateMap(object):
|
| + """
|
| + Helper class used by nfa_to_dfa() to map back and forth between
|
| + sets of states from the old machine and states of the new machine.
|
| + """
|
| + new_machine = None # Machine
|
| + old_to_new_dict = None # {(old_state,...) : new_state}
|
| + new_to_old_dict = None # {id(new_state) : old_state_set}
|
| +
|
| + def __init__(self, new_machine):
|
| + self.new_machine = new_machine
|
| + self.old_to_new_dict = {}
|
| + self.new_to_old_dict= {}
|
| +
|
| + def old_to_new(self, old_state_set):
|
| + """
|
| + Return the state of the new machine corresponding to the
|
| + set of old machine states represented by |state_set|. A new
|
| + state will be created if necessary. If any of the old states
|
| + are accepting states, the new state will be an accepting state
|
| + with the highest priority action from the old states.
|
| + """
|
| + key = self.make_key(old_state_set)
|
| + new_state = self.old_to_new_dict.get(key, None)
|
| + if not new_state:
|
| + action = self.highest_priority_action(old_state_set)
|
| + new_state = self.new_machine.new_state(action)
|
| + self.old_to_new_dict[key] = new_state
|
| + self.new_to_old_dict[id(new_state)] = old_state_set
|
| + #for old_state in old_state_set.keys():
|
| + #new_state.merge_actions(old_state)
|
| + return new_state
|
| +
|
| + def highest_priority_action(self, state_set):
|
| + best_action = None
|
| + best_priority = LOWEST_PRIORITY
|
| + for state in state_set:
|
| + priority = state.action_priority
|
| + if priority > best_priority:
|
| + best_action = state.action
|
| + best_priority = priority
|
| + return best_action
|
| +
|
| +# def old_to_new_set(self, old_state_set):
|
| +# """
|
| +# Return the new state corresponding to a set of old states as
|
| +# a singleton set.
|
| +# """
|
| +# return {self.old_to_new(old_state_set):1}
|
| +
|
| + def new_to_old(self, new_state):
|
| + """Given a new state, return a set of corresponding old states."""
|
| + return self.new_to_old_dict[id(new_state)]
|
| +
|
| + def make_key(self, state_set):
|
| + """
|
| + Convert a set of states into a uniquified
|
| + sorted tuple suitable for use as a dictionary key.
|
| + """
|
| + lst = list(state_set)
|
| + lst.sort()
|
| + return tuple(lst)
|
| +
|
| + def dump(self, file):
|
| + from Transitions import state_set_str
|
| + for new_state in self.new_machine.states:
|
| + old_state_set = self.new_to_old_dict[id(new_state)]
|
| + file.write(" State %s <-- %s\n" % (
|
| + new_state['number'], state_set_str(old_state_set)))
|
| +
|
| +
|
|
|