def closure(d_state, conf): # to prevent compute over and over again... if conf in d_state.busy: return set() else: d_state.busy.add(conf) ret = set() ret.add(conf) p, i, y, pi = conf.a_state, conf.alt, conf.stack, conf.pred if p.is_stop_state(): if y.is_empty(): for p2 in globals_holder.a_net.get_all_destinations_of(globals_holder.a_net.get_rule_of_state(p)): ret.update(closure(d_state, atn_config(p2, i, call_stack(), pi))) else: p1, y1 = y.copy_and_pop() ret.update(closure(d_state, atn_config(p1, i, y1, pi))) for t, s in p.transitions: if isinstance(t, non_terminal): # is a non-terminal edge transition depth = y.get_rec_depth(s) # recursion depth of t at state s if depth == 1: d_state.recursive_alts.add(i) if len(d_state.recursive_alts) > 1: raise Exception("Likely non-LL regular, recursive alts: " + str(d_state.recursive_alts) + ", rule: " + str(globals_holder.a_net.get_rule_of_state(p))) if depth >= MAX_REC_DEPTH: d_state.overflowed = True return ret # push destination state and doing closure with the starting state of t stk = y.copy() stk.push(s) ret.update(closure(d_state, atn_config(globals_holder.a_net.get_start_state(t), i, stk, pi))) elif hasattr(t, 'pred') or epsilon == t: # is predicate or epsilon transition ret.update(closure(d_state, atn_config(s, i, y, pi))) return ret
def create_dfa(a_start_state): ret = dfa() work = [] D0 = dfa_state() # dfa start state for this rule for alt in range(len(a_start_state.transitions)): # init all final states, num of start state transitions is num of alts f_i = dfa_state(alt) ret.add_dummy_final_state(alt, f_i) for i, (_, pa_i) in enumerate(a_start_state.transitions): pi = None first_t = iter(pa_i.transitions).next()[0] # may have only one transition if first_t != epsilon and hasattr(first_t, 'pred'): # has predicate pi = first_t # pred D0.add_all_confs(closure(D0, atn_config(pa_i, i, call_stack(), pi))) D0.release_busy() work.append(D0) ret.add_state(D0) while len(work) != 0: d_state = work.pop() new_trans = [] # remember transitions newly added new_works_count = 0 # remember num of new works added new_states = set() # remember new states discovered for a in d_state.get_all_terminal_edges(): d_state_new = dfa_state() for conf in d_state.move(a): # move and closure d_state_new.add_all_confs(closure(d_state, conf)) d_state.release_busy() resolve_overflow(d_state) # d_state may be marked overflowed while closuring, so it must be resolved check_if_final_and_replace(d_state, ret) if d_state.stop_transit: break if d_state.stop_transit: break if not ret.contain_state(d_state_new): # resolve_conflicts and add to dfa network resolve_conflicts(d_state_new) if not check_if_final_and_replace(d_state_new, ret): work.append(d_state_new) new_works_count = new_works_count + 1 ret.add_state(d_state_new) new_states.add(d_state_new) d_state.add_transition(a, d_state_new) new_trans.append((a, d_state_new)) else: d_state.add_transition(a, ret.get_same_state(d_state_new)) # add the same state already in the dfa(not the newly created one) new_trans.append((a, ret.get_same_state(d_state_new))) if d_state.stop_transit: # remove newly added states, transitions and works if d_state.stop_transit for n_s in new_states: ret.states.remove(n_s) for t in new_trans: d_state.transitions.remove(t) for i in range(new_works_count): work.pop() pred_trans = set() for c in [c for c in d_state.confs if c.was_resolved]: pred_trans.add((c.pred, ret.final_states[c.alt])) for p, s in pred_trans: d_state.add_transition(p, s) return ret