docs: def _states_to_dfa_bytecode(self, states, \
        tran=None, \
        debug=False, \
        compiled_states=None, \
        gathered_epsilons=None, \
        cached_transitions=None, \
        cached_tcode=None, \
        reltags_cache=None \
        ):
      '''returns the instruction pointer to the bytecode added'''
      pstates = copy.copy(states)
  
      if reltags_cache == None:
        reltags_cache = {}
  
      if cached_tcode == None:
        cached_tcode = {}
  
      if cached_transitions == None:
        cached_transitions = {}
  
      if gathered_epsilons == None:
        gathered_epsilons = {}
  
      self._add_epsilon_states(states, gathered_epsilons)
  
      if tran != None:
        states = self.nextstates(states, tran)
        self._add_epsilon_states(states, gathered_epsilons)
  
      if self._magic != None:
        states = states.union(self._magic(states))
  
      tstates = tuple(states)
  
      # this is used so we only compile each stateset once
      if compiled_states == None:
        compiled_states = {}
  
      if tstates in compiled_states:
        return compiled_states[tstates]
  
      # grab the ip from our codeblock
      ip = self._bytecode.newblock(tstates)
      compiled_states[tstates] = ip
  
      # TODO
      # epsilon transitions are never 'taken' so we need
      # to insert any ltagv/utagv instructions required
      # for all epsilon transitions
      # gathered_epsilons[state] holds a dictionary of dst: src mappings, so we can use that data
  
      if self.do_tags:
        tags = set()
        rtags = set()
    
        for ts in pstates:
          for dst in gathered_epsilons[ts]:
            rtags.update(self.reltags(dst, reltags_cache))
            src = gathered_epsilons[ts][dst]
            if self.is_tagged(NFA.EPSILON, src, dst):
              tags.add((self.tag(NFA.EPSILON, src, dst), dst))
    
        self._write_transition_code(tags, rtags, ip)
  
      # run any defined state hooks
      for s in tstates:
        if s in self._state_hooks:
          ip.append(VM.PyCode(self._state_hooks[s]))
  
      # do a multi-match for any final states
      finals = self._final_states.intersection(states)
      if len(finals) > 0:
        ip.append(VM.MultiMatch(finals))
  
      # do any interupts required
      interupts = self._interupt_states.intersection(states)
      if len(interupts) > 0:
        ip.append(VM.MultiInterupt(interupts))
  
      # consume a character
      ip.append(VM.Consume())
  
      ts = self.transitions(states, cached_transitions)
  
      if debug:
        print 'compiling bytecode for stateset:\n\t%s\n\t0x%x: %s' % (states,ip,(defaults,ts))
  
      def mkbytecode(t):
        return lambda: self._transitions_to_dfa_bytecode(states, t, cached_tcode, debug=debug, compiled_states=compiled_states, gathered_epsilons=gathered_epsilons, cached_transitions=cached_transitions, reltags_cache=reltags_cache)
  
      # for any of the non-default states add a conditional jmp
      for k in ts:
  
        if k in (NFA.ANY, NFA.EPSILON):
          continue
  
        jmppoint = VM.DelayedArg(mkbytecode(k))
        ip.append(VM.Compare(k))
        ip.append(VM.CondJmp(jmppoint))
  
      # jmp to default state if there is one, otherwise leave
      defaults = self.nextstates(states, NFA.ANY)
      if len(defaults) > 0:
        jmppoint = VM.DelayedArg(mkbytecode(NFA.ANY))
        ip.append(VM.Jmp(jmppoint))
      else:
        ip.append(VM.Leave())
  
      # return the instruction pointer
      return ip