diff options
Diffstat (limited to 'debian/pyrex/pyrex-0.9.9/Pyrex/Plex/Machines.py')
-rwxr-xr-x | debian/pyrex/pyrex-0.9.9/Pyrex/Plex/Machines.py | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/debian/pyrex/pyrex-0.9.9/Pyrex/Plex/Machines.py b/debian/pyrex/pyrex-0.9.9/Pyrex/Plex/Machines.py new file mode 100755 index 00000000..fb9ba717 --- /dev/null +++ b/debian/pyrex/pyrex-0.9.9/Pyrex/Plex/Machines.py @@ -0,0 +1,326 @@ +#======================================================================= +# +# Python Lexical Analyser +# +# Classes for building NFAs and DFAs +# +#======================================================================= + +import string +import sys +from sys import maxint +from types import TupleType + +from Transitions import TransitionMap + +LOWEST_PRIORITY = -sys.maxint + +class Machine: + """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.items(): + file.write(" '%s': %d\n" % (name, state.number)) + for s in self.states: + s.dump(file) + +class Node: + """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 merge_actions(self, other_state): +# """Merge actions of other state into this state according +# to their priorities.""" +# action = other_state.get_action() +# priority = other_state.get_action_priority() +# self.set_action(action, priority) + + def is_accepting(self): + return self.action is not None + + def __str__(self): + return "State %d" % self.number + + def dump(self, file): + import string + # 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)) + + +class FastMachine: + """ + 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.items(): + 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.items(): + 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): + if type(event) == TupleType: + 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.items(): + 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): + import string + # 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.items(): + 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 string.join(map(self.range_to_string, range_list), ",") + + def range_to_string(self, (c1, c2)): + if c1 == c2: + return repr(c1) + else: + return "%s..%s" % (repr(c1), repr(c2)) +## +## (Superseded by Machines.FastMachine) +## +## class StateTableMachine: +## """ +## StateTableMachine is an alternative representation of a Machine +## that can be run more efficiently. +## """ +## initial_states = None # {state_name:state_index} +## states = None # [([state] indexed by char code, Action)] + +## special_map = {'bol':256, 'eol':257, 'eof':258} + +## def __init__(self, m): +## """ +## Initialise StateTableMachine from Machine |m|. +## """ +## initial_states = self.initial_states = {} +## states = self.states = [None] +## old_to_new = {} +## i = 1 +## for old_state in m.states: +## new_state = ([0] * 259, old_state.get_action()) +## states.append(new_state) +## old_to_new[old_state] = i # new_state +## i = i + 1 +## for name, old_state in m.initial_states.items(): +## initial_states[name] = old_to_new[old_state] +## for old_state in m.states: +## new_state_index = old_to_new[old_state] +## new_table = states[new_state_index][0] +## transitions = old_state.transitions +## for c, old_targets in transitions.items(): +## if old_targets: +## old_target = old_targets[0] +## new_target_index = old_to_new[old_target] +## if len(c) == 1: +## a = ord(c) +## else: +## a = self.special_map[c] +## new_table[a] = states[new_target_index] + +## def dump(self, f): +## f.write("Plex.StateTableMachine:\n") +## f.write(" Initial states:\n") +## for name, index in self.initial_states.items(): +## f.write(" %s: State %d\n" % ( +## repr(name), id(self.states[index]))) +## for i in xrange(1, len(self.states)): +## table, action = self.states[i] +## f.write(" State %d:" % i) +## if action: +## f.write("%s" % action) +## f.write("\n") +## f.write(" %s\n" % map(id,table)) + + + + + + |