docs: def find_nonterminals_rewritable_to_epsilon(grammar):
      # type: (Grammar) -> Dict[Type[Nonterminal], Type[Rule]]
      """
      Get nonterminals rewritable to epsilon.
      :param grammar: Grammar where to search.
      :return: Dictionary, where key is nonterminal rewritable to epsilon and value is rule that is responsible for it.
      The rule doesn't need to rewrite to epsilon directly,
      but the whole right side can be rewritable to epsilon using different rules.
      """
      # start with empty dictionary (contains only epsilon)
      rewritable = dict()  # type: Dict[Type[Nonterminal], Optional[Type[Rule]]]
      rewritable[EPSILON] = None
      # iterate until the dictionary change
      while True:
          working = rewritable.copy()
          for rule in grammar.rules:
              # no need to process rules we already know rewrite to epsilon
              if rule.fromSymbol in working:
                  continue
              # check if the whole right side rewrite to epsilon
              right_side_rewrite = True
              for symbol in rule.right:
                  if symbol not in rewritable:
                      right_side_rewrite = False
              # the whole right side can be reduce to epsilon, add left side to dictionary
              if right_side_rewrite:
                  working[rule.fromSymbol] = rule
          # Working set didn't change, we are done
          if working == rewritable:
              break
          # Otherwise swap the sets and iterate
          rewritable = working
      # delete epsilon from the dictionary
      del rewritable[EPSILON]
      return rewritable