def fsm_diagram(grammar, start_symbol=START_SYMBOL): def left_align(label): return dot_escape(label.replace('\n', r'\l')).replace(r'\\l', '\\l') dot = Digraph(comment="Grammar as Finite State Machine") symbols = deque([start_symbol]) symbols_seen = set() while len(symbols) > 0: symbol = symbols.popleft() symbols_seen.add(symbol) dot.node(symbol, dot_escape(unicode_escape(symbol))) for expansion in grammar[symbol]: nts = nonterminals(expansion) if len(nts) > 0: target_symbol = nts[-1] if target_symbol not in symbols_seen: symbols.append(target_symbol) label = expansion.replace(target_symbol, '') dot.edge(symbol, target_symbol, left_align(unicode_escape(label))) return display(dot)
def expansion_cost(self, expansion, seen=set()): symbols = nonterminals(expansion) if len(symbols) == 0: return 1 # no symbol if any(s in seen for s in symbols): return float('inf') # the value of a expansion is the sum of all expandable variables # inside + 1 return sum(self.symbol_cost(s, seen) for s in symbols) + 1