docs: def parse(self, tokens, debug=None):
          """This is the main entry point from outside.
  
          Passing in a debug dictionary changes the default debug
          setting.
          """
  
          self.tokens = tokens
  
          if debug:
              self.debug = debug
  
          sets = [ [(1, 0), (2, 0)] ]
          self.links = {}
  
          if self.ruleschanged:
              self.computeNull()
              self.newrules = {}
              self.new2old = {}
              self.makeNewRules()
              self.ruleschanged = False
              self.edges, self.cores = {}, {}
              self.states = { 0: self.makeState0() }
              self.makeState(0, self._BOF)
  
          for i in range(len(tokens)):
              sets.append([])
  
              if sets[i] == []:
                  break
              self.makeSet(tokens, sets, i)
          else:
              sets.append([])
              self.makeSet(None, sets, len(tokens))
  
          finalitem = (self.finalState(tokens), 0)
          if finalitem not in sets[-2]:
              if len(tokens) > 0:
                  if self.debug.get('errorstack', False):
                      self.errorstack(tokens, i-1, str(self.debug['errorstack']) == 'full')
                  self.error(tokens, i-1)
              else:
                  self.error(None, None)
  
          if self.profile_info is not None:
              self.dump_profile_info()
  
          return self.buildTree(self._START, finalitem,
                      tokens, len(sets)-2)