Index: third_party/cython/src/Cython/Plex/Machines.py |
diff --git a/third_party/cython/src/Cython/Plex/Machines.py b/third_party/cython/src/Cython/Plex/Machines.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..531d68e95bca07a4cf60e7319a48da1af4c13eb6 |
--- /dev/null |
+++ b/third_party/cython/src/Cython/Plex/Machines.py |
@@ -0,0 +1,256 @@ |
+#======================================================================= |
+# |
+# Python Lexical Analyser |
+# |
+# Classes for building NFAs and DFAs |
+# |
+#======================================================================= |
+ |
+import sys |
+ |
+from Transitions import TransitionMap |
+ |
+LOWEST_PRIORITY = -sys.maxint |
+ |
+class Machine(object): |
+ """A collection of Nodes representing an NFA or DFA.""" |
+ states = None # [Node] |
+ next_state_number = 1 |
+ initial_states = None # {(name, bol): Node} |
+ |
+ def __init__(self): |
+ self.states = [] |
+ self.initial_states = {} |
+ |
+ def __del__(self): |
+ #print "Destroying", self ### |
+ for state in self.states: |
+ state.destroy() |
+ |
+ def new_state(self): |
+ """Add a new state to the machine and return it.""" |
+ s = Node() |
+ n = self.next_state_number |
+ self.next_state_number = n + 1 |
+ s.number = n |
+ self.states.append(s) |
+ return s |
+ |
+ def new_initial_state(self, name): |
+ state = self.new_state() |
+ self.make_initial_state(name, state) |
+ return state |
+ |
+ def make_initial_state(self, name, state): |
+ self.initial_states[name] = state |
+ |
+ def get_initial_state(self, name): |
+ return self.initial_states[name] |
+ |
+ def dump(self, file): |
+ file.write("Plex.Machine:\n") |
+ if self.initial_states is not None: |
+ file.write(" Initial states:\n") |
+ for (name, state) in self.initial_states.iteritems(): |
+ file.write(" '%s': %d\n" % (name, state.number)) |
+ for s in self.states: |
+ s.dump(file) |
+ |
+class Node(object): |
+ """A state of an NFA or DFA.""" |
+ transitions = None # TransitionMap |
+ action = None # Action |
+ action_priority = None # integer |
+ number = 0 # for debug output |
+ epsilon_closure = None # used by nfa_to_dfa() |
+ |
+ def __init__(self): |
+ # Preinitialise the list of empty transitions, because |
+ # the nfa-to-dfa algorithm needs it |
+ #self.transitions = {'':[]} |
+ self.transitions = TransitionMap() |
+ self.action_priority = LOWEST_PRIORITY |
+ |
+ def destroy(self): |
+ #print "Destroying", self ### |
+ self.transitions = None |
+ self.action = None |
+ self.epsilon_closure = None |
+ |
+ def add_transition(self, event, new_state): |
+ self.transitions.add(event, new_state) |
+ |
+ def link_to(self, state): |
+ """Add an epsilon-move from this state to another state.""" |
+ self.add_transition('', state) |
+ |
+ def set_action(self, action, priority): |
+ """Make this an accepting state with the given action. If |
+ there is already an action, choose the action with highest |
+ priority.""" |
+ if priority > self.action_priority: |
+ self.action = action |
+ self.action_priority = priority |
+ |
+ def get_action(self): |
+ return self.action |
+ |
+ def get_action_priority(self): |
+ return self.action_priority |
+ |
+ def is_accepting(self): |
+ return self.action is not None |
+ |
+ def __str__(self): |
+ return "State %d" % self.number |
+ |
+ def dump(self, file): |
+ # Header |
+ file.write(" State %d:\n" % self.number) |
+ # Transitions |
+# self.dump_transitions(file) |
+ self.transitions.dump(file) |
+ # Action |
+ action = self.action |
+ priority = self.action_priority |
+ if action is not None: |
+ file.write(" %s [priority %d]\n" % (action, priority)) |
+ |
+ def __lt__(self, other): |
+ return self.number < other.number |
+ |
+class FastMachine(object): |
+ """ |
+ FastMachine is a deterministic machine represented in a way that |
+ allows fast scanning. |
+ """ |
+ initial_states = None # {state_name:state} |
+ states = None # [state] |
+ # where state = {event:state, 'else':state, 'action':Action} |
+ next_number = 1 # for debugging |
+ |
+ new_state_template = { |
+ '':None, 'bol':None, 'eol':None, 'eof':None, 'else':None |
+ } |
+ |
+ def __init__(self, old_machine = None): |
+ self.initial_states = initial_states = {} |
+ self.states = [] |
+ if old_machine: |
+ self.old_to_new = old_to_new = {} |
+ for old_state in old_machine.states: |
+ new_state = self.new_state() |
+ old_to_new[old_state] = new_state |
+ for name, old_state in old_machine.initial_states.iteritems(): |
+ initial_states[name] = old_to_new[old_state] |
+ for old_state in old_machine.states: |
+ new_state = old_to_new[old_state] |
+ for event, old_state_set in old_state.transitions.iteritems(): |
+ if old_state_set: |
+ new_state[event] = old_to_new[old_state_set.keys()[0]] |
+ else: |
+ new_state[event] = None |
+ new_state['action'] = old_state.action |
+ |
+ def __del__(self): |
+ for state in self.states: |
+ state.clear() |
+ |
+ def new_state(self, action = None): |
+ number = self.next_number |
+ self.next_number = number + 1 |
+ result = self.new_state_template.copy() |
+ result['number'] = number |
+ result['action'] = action |
+ self.states.append(result) |
+ return result |
+ |
+ def make_initial_state(self, name, state): |
+ self.initial_states[name] = state |
+ |
+ def add_transitions(self, state, event, new_state, maxint=sys.maxint): |
+ if type(event) is tuple: |
+ code0, code1 = event |
+ if code0 == -maxint: |
+ state['else'] = new_state |
+ elif code1 != maxint: |
+ while code0 < code1: |
+ state[chr(code0)] = new_state |
+ code0 = code0 + 1 |
+ else: |
+ state[event] = new_state |
+ |
+ def get_initial_state(self, name): |
+ return self.initial_states[name] |
+ |
+ def dump(self, file): |
+ file.write("Plex.FastMachine:\n") |
+ file.write(" Initial states:\n") |
+ for name, state in self.initial_states.iteritems(): |
+ file.write(" %s: %s\n" % (repr(name), state['number'])) |
+ for state in self.states: |
+ self.dump_state(state, file) |
+ |
+ def dump_state(self, state, file): |
+ # Header |
+ file.write(" State %d:\n" % state['number']) |
+ # Transitions |
+ self.dump_transitions(state, file) |
+ # Action |
+ action = state['action'] |
+ if action is not None: |
+ file.write(" %s\n" % action) |
+ |
+ def dump_transitions(self, state, file): |
+ chars_leading_to_state = {} |
+ special_to_state = {} |
+ for (c, s) in state.iteritems(): |
+ if len(c) == 1: |
+ chars = chars_leading_to_state.get(id(s), None) |
+ if chars is None: |
+ chars = [] |
+ chars_leading_to_state[id(s)] = chars |
+ chars.append(c) |
+ elif len(c) <= 4: |
+ special_to_state[c] = s |
+ ranges_to_state = {} |
+ for state in self.states: |
+ char_list = chars_leading_to_state.get(id(state), None) |
+ if char_list: |
+ ranges = self.chars_to_ranges(char_list) |
+ ranges_to_state[ranges] = state |
+ ranges_list = ranges_to_state.keys() |
+ ranges_list.sort() |
+ for ranges in ranges_list: |
+ key = self.ranges_to_string(ranges) |
+ state = ranges_to_state[ranges] |
+ file.write(" %s --> State %d\n" % (key, state['number'])) |
+ for key in ('bol', 'eol', 'eof', 'else'): |
+ state = special_to_state.get(key, None) |
+ if state: |
+ file.write(" %s --> State %d\n" % (key, state['number'])) |
+ |
+ def chars_to_ranges(self, char_list): |
+ char_list.sort() |
+ i = 0 |
+ n = len(char_list) |
+ result = [] |
+ while i < n: |
+ c1 = ord(char_list[i]) |
+ c2 = c1 |
+ i = i + 1 |
+ while i < n and ord(char_list[i]) == c2 + 1: |
+ i = i + 1 |
+ c2 = c2 + 1 |
+ result.append((chr(c1), chr(c2))) |
+ return tuple(result) |
+ |
+ def ranges_to_string(self, range_list): |
+ return ','.join(map(self.range_to_string, range_list)) |
+ |
+ def range_to_string(self, range_tuple): |
+ (c1, c2) = range_tuple |
+ if c1 == c2: |
+ return repr(c1) |
+ else: |
+ return "%s..%s" % (repr(c1), repr(c2)) |