| OLD | NEW |
| 1 # Copyright 2014 the V8 project authors. All rights reserved. | 1 # Copyright 2014 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without | 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are | 3 # modification, are permitted provided that the following conditions are |
| 4 # met: | 4 # met: |
| 5 # | 5 # |
| 6 # * Redistributions of source code must retain the above copyright | 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above | 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following | 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided | 10 # disclaimer in the documentation and/or other materials provided |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 | 33 |
| 34 @staticmethod | 34 @staticmethod |
| 35 def generate(dfa, default_action): | 35 def generate(dfa, default_action): |
| 36 return BacktrackingGenerator(dfa, default_action, None).__generate() | 36 return BacktrackingGenerator(dfa, default_action, None).__generate() |
| 37 | 37 |
| 38 def __init__(self, dfa, default_action, log): | 38 def __init__(self, dfa, default_action, log): |
| 39 self.__dfa = dfa | 39 self.__dfa = dfa |
| 40 self.__default_action = default_action | 40 self.__default_action = default_action |
| 41 self.__log = log | 41 self.__log = log |
| 42 | 42 |
| 43 @staticmethod |
| 44 def __process_error_states(dfa, error_map, action_state_map): |
| 45 path_map = { k : [] for k in error_map.iterkeys()} |
| 46 error_states = set(error_map.iterkeys()) |
| 47 for path, states_in_path, terminal in dfa.path_iter(): |
| 48 matching = error_states & states_in_path |
| 49 if not matching: |
| 50 continue |
| 51 last_action = None |
| 52 path_length = 0 |
| 53 for (key, state) in path: |
| 54 if state in error_states: |
| 55 assert last_action != None |
| 56 path_map[state].append([k for k, s in path[1:path_length]]) |
| 57 elif state in action_state_map: |
| 58 last_action = state |
| 59 path_length += 1 |
| 60 print reduce(lambda acc, x : acc + len(x), path_map.itervalues(), 0) |
| 61 for state, key_paths in path_map.iteritems(): |
| 62 count = 0 |
| 63 action_str = map(str, error_map[state][0]) |
| 64 for key_path in key_paths: |
| 65 print "path %d %s %s" % ( |
| 66 state.node_number(), |
| 67 action_str, |
| 68 " --> ".join(map(str, key_path))) |
| 69 count += 1 |
| 70 if count > 10: |
| 71 break |
| 72 |
| 43 def __generate(self): | 73 def __generate(self): |
| 44 dfa = self.__dfa | 74 dfa = self.__dfa |
| 45 default_action = self.__default_action | 75 default_action = self.__default_action |
| 46 terminal_set = dfa.terminal_set() | 76 terminal_set = dfa.terminal_set() |
| 47 # Collect states that terminate currently. | 77 # Collect states that terminate currently. |
| 48 action_states = {} | 78 action_states = {} |
| 49 omega_states = set() | 79 omega_states = set() |
| 50 def f(state, acc): | 80 def f(state, acc): |
| 51 omega_state = state.omega_transition() | 81 omega_state = state.omega_transition() |
| 52 if omega_state == None: | 82 if omega_state == None: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 65 assert omega_states == terminal_set | 95 assert omega_states == terminal_set |
| 66 # Find nodes that need backtracking edges | 96 # Find nodes that need backtracking edges |
| 67 incoming_transitions = dfa.build_incoming_transitions_map() | 97 incoming_transitions = dfa.build_incoming_transitions_map() |
| 68 backtracking_map = {} | 98 backtracking_map = {} |
| 69 store_states = set() | 99 store_states = set() |
| 70 # Start node may be an edge case. | 100 # Start node may be an edge case. |
| 71 start_state = dfa.start_state() | 101 start_state = dfa.start_state() |
| 72 if (not start_state in incoming_transitions and | 102 if (not start_state in incoming_transitions and |
| 73 not start_state in action_states): | 103 not start_state in action_states): |
| 74 action_states[start_state] = default_action | 104 action_states[start_state] = default_action |
| 105 error_map = {} |
| 75 for state in incoming_transitions.iterkeys(): | 106 for state in incoming_transitions.iterkeys(): |
| 76 if state in omega_states or state in action_states: | 107 if state in omega_states or state in action_states: |
| 77 continue | 108 continue |
| 78 assert not state.omega_transition() | 109 assert not state.omega_transition() |
| 79 seen = set([state]) | 110 seen = set([state]) |
| 80 unchecked = set([state]) | 111 unchecked = set([state]) |
| 81 match_edge = set() | 112 match_edge = set() |
| 82 while unchecked: | 113 while unchecked: |
| 83 next = set() | 114 next = set() |
| 84 for unchecked_state in unchecked: | 115 for unchecked_state in unchecked: |
| 85 if not unchecked_state in incoming_transitions: | 116 if not unchecked_state in incoming_transitions: |
| 86 assert unchecked_state == start_state | 117 assert unchecked_state == start_state |
| 87 match_edge.add(unchecked_state) | 118 match_edge.add(unchecked_state) |
| 88 continue | 119 continue |
| 89 for (incoming_key, incoming_state) in incoming_transitions[unchecked_s
tate]: | 120 for (incoming_key, incoming_state) in incoming_transitions[unchecked_s
tate]: |
| 90 assert not incoming_state in omega_states | 121 assert not incoming_state in omega_states |
| 91 assert not incoming_key == TransitionKey.omega() | 122 assert not incoming_key == TransitionKey.omega() |
| 92 if incoming_state in seen: | 123 if incoming_state in seen: |
| 93 continue | 124 continue |
| 94 if incoming_state in action_states: | 125 if incoming_state in action_states: |
| 95 match_edge.add(incoming_state) | 126 match_edge.add(incoming_state) |
| 96 seen.add(incoming_state) | 127 seen.add(incoming_state) |
| 97 else: | 128 else: |
| 98 next.add(incoming_state) | 129 next.add(incoming_state) |
| 99 seen |= unchecked | 130 seen |= unchecked |
| 100 unchecked = next - seen | 131 unchecked = next - seen |
| 101 # accumulate unique actions | 132 # Accumulate unique actions. |
| 102 actions = set(map(lambda x : action_states[x].term(), match_edge)) | 133 actions = set(map(lambda x : action_states[x].term(), match_edge)) |
| 103 assert actions | 134 assert actions |
| 104 if not len(actions) == 1: | 135 if not len(actions) == 1: |
| 105 # TODO(dcarney): need to warn here after second pass | 136 error_map[state] = actions, match_edge |
| 106 # actions = set([default_action]) | |
| 107 continue | 137 continue |
| 108 action = iter(actions).next() | 138 action = iter(actions).next() |
| 109 # don't install default actions | 139 # don't install default actions |
| 110 if action == default_action.term(): | 140 if action == default_action.term(): |
| 111 continue | 141 continue |
| 112 store_states |= match_edge | 142 store_states |= match_edge |
| 113 backtracking_map[state.node_number()] = (action, match_edge) | 143 backtracking_map[state.node_number()] = (action, match_edge) |
| 144 # Bail if error occurred. |
| 145 if error_map: |
| 146 self.__process_error_states(dfa, error_map, action_states) |
| 147 raise Exception('ambiguous backtracking') |
| 148 # Now install backtracking everywhere. |
| 114 def install_backtracking_action(new_states, node_number): | 149 def install_backtracking_action(new_states, node_number): |
| 115 omega_state_id = str(node_number) + '_bt' | 150 omega_state_id = str(node_number) + '_bt' |
| 116 key = TransitionKey.omega() | 151 key = TransitionKey.omega() |
| 117 new_states[str(node_number)]['transitions'][key] = omega_state_id | 152 new_states[str(node_number)]['transitions'][key] = omega_state_id |
| 118 # install new state | 153 # install new state |
| 119 old_action = backtracking_map[node_number][0] | 154 old_action = backtracking_map[node_number][0] |
| 120 new_states[omega_state_id] = { | 155 new_states[omega_state_id] = { |
| 121 'transitions' : {}, | 156 'transitions' : {}, |
| 122 'action' : Action(Term('backtrack', old_action), 0), | 157 'action' : Action(Term('backtrack', old_action), 0), |
| 123 'terminal' : True, | 158 'terminal' : True, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 140 k : str(v.node_number()) for (k, v) in old_state.key_state_iter() }, | 175 k : str(v.node_number()) for (k, v) in old_state.key_state_iter() }, |
| 141 'action' : new_state_action(old_state), | 176 'action' : new_state_action(old_state), |
| 142 'terminal' : old_state in terminal_set | 177 'terminal' : old_state in terminal_set |
| 143 } | 178 } |
| 144 # install a backtracking action | 179 # install a backtracking action |
| 145 if node_number in backtracking_map: | 180 if node_number in backtracking_map: |
| 146 install_backtracking_action(new_states, node_number) | 181 install_backtracking_action(new_states, node_number) |
| 147 return new_states | 182 return new_states |
| 148 new_states = dfa.visit_all_states(convert, {}) | 183 new_states = dfa.visit_all_states(convert, {}) |
| 149 return Dfa(dfa.encoding(), str(start_state.node_number()), new_states) | 184 return Dfa(dfa.encoding(), str(start_state.node_number()), new_states) |
| OLD | NEW |