def METHOD_NAME(self):
    self.rules = rules1 = {}
    self.visit(self.grammar1)
    del self.rules
    self.rules = rules2 = {}
    self.visit(self.grammar2)
    del self.rules
    rules_added = []
    rules_removed = []
    for rulename in rules1:
        if rulename not in rules2:
            rules_removed.append(rulename)
    for rulename in rules2:
        if rulename not in rules1:
            rules_added.append(rulename)
    rules_diff = []
    replacement_functions = {}
    for rulename, (type, actions) in rules1.items():
        if rulename in rules2:
            new_type, new_actions = rules2[rulename]
            if type != new_type or actions != new_actions:
                rules_diff.append(rulename)
                for pattern,old_action in actions.items():
                    new_action = new_actions.get(pattern)
                    if new_action and new_action != old_action and (m1 := self.FUNCCALL_REGEXP.match(old_action)) and (m2 := self.FUNCCALL_REGEXP.match(new_action)):
                        replacement_functions.setdefault(m1.group(1), set()).add(m2.group(1))
    if rules_added:
        print(f"== Rules added [{len(rules_added)}]\n")
        for rulename in rules_added:
            new_type,new_actions = rules2[rulename]
            print(f"\t{rulename}[{new_type}]")
            for pattern,action in new_actions.items():
                print(f"\t\t| {pattern} {{{action}}}")
            print()
    if rules_removed:
        print(f"== Rules removed [{len(rules_removed)}]\n")
        for rulename in rules_removed:
            old_type,old_actions = rules1[rulename]
            print(f"\t{rulename}[{old_type}]")
            for pattern,action in old_actions.items():
                print(f"\t\t| {pattern} {{{action}}}")
            print()
    if rules_diff:
        print(f"== Rule differences [{len(rules_diff)}]\n")
        for rulename in rules_diff:
            old_type,old_actions = rules1[rulename]
            new_type,new_actions = rules2[rulename]
            print(f"\t{rulename}", end="")
            if old_type != new_type:
                print(f"[{self.old(old_type)}{self.new(new_type)}]")
            else:
                print(f"[{old_type}]")
            for pattern,old_action in old_actions.items():
                print(f"\t\t| ", end="")
                if pattern in new_actions:
                    print(pattern, end=" ")
                    new_action = new_actions[pattern]
                    if old_action != new_action:
                        print(f"{{{self.old(old_action)}{self.new(new_action)}}}")
                    else:
                        print(f"{{{old_action}}}")
                else:
                    print(self.old(f"{pattern} {{{old_action}}}"))
            for pattern,new_action in new_actions.items():
                if pattern not in old_actions:
                    print(self.new(f"\t\t| {pattern} {{{new_action}}}"))
            print()
    unchanged_rules = set(rules1.keys()) - set(rules_diff) - set(rules_removed)
    if unchanged_rules:
        print(f"== Unchanged rules [{len(unchanged_rules)}]")
        print("\n\t", "\n\t".join(sorted(unchanged_rules)), "\n", sep="")
    if replacement_functions:
        print(f"== Typical replacement functions\n")
        for old,new in sorted(replacement_functions.items()):
            print(f"\t{old}", "->", self.new(", ".join(new)))
            print()