def can_parse(target, rules, verbose=False):
  """Return True if target can be derived given rules using parser.

  Args:
    target: Target string (can contain non-terminals or terminals).
    rules: List of TargetCFGRule instances.
    verbose: Print debug output if True.

  Returns:
    True if target can be derived.
  """

  def node_fn(unused_span_begin, unused_span_end, rule, children):
    """Represent node as applied rules."""
    rules = [rule]
    for child in children:
      rules.extend(child)
    return [rules]

  def postprocess_fn(nodes):
    """Filter invalid nodes."""
    new_nodes = []
    for node in nodes:
      qcfg_to_target = {}
      valid_node = True
      for rule in node:
        if qcfg_rule.is_nt(rule.rhs[len(target_grammar.NON_TERMINAL_PREFIX):]):
          qcfg_to_target.setdefault(rule.rhs, rule.lhs)
          # Filter out node with QCFG NT matches to more than one target NTs.
          if qcfg_to_target[rule.rhs] != rule.lhs:
            valid_node = False
            break
      if valid_node:
        new_nodes.append(node)
    return new_nodes

  tokens = target.split(" ")
  outputs = parse(
      tokens,
      rules,
      verbose=verbose,
      node_fn=node_fn,
      postprocess_fn=postprocess_fn)
  if outputs:
    return True
  return False
Return True if target can be derived given rules using parser.

  Args:
    target: Target string (can contain non-terminals or terminals).
    rules: List of TargetCFGRule instances.
    verbose: Print debug output if True.

  Returns:
    True if target can be derived.
  
language/compgen/csl/qcfg/qcfg_target_parser.py