def build_grammar(grammar_txt: str): """ Transform a string in this format: S --> A B A --> a A | epsilon B --> b B | epsilon to a Grammar object """ try: nonTerminals, terminals, P = [], [], [] lines = [ l.strip() for l in grammar_txt.splitlines() if l.strip() != '' ] head = None for l in lines: if '->' not in l: l = f'{head} -> {l}' head, bodies = l.split('->') head = head.split()[0] nonTerminals.append(head) for body in bodies.split('|'): if body.strip() != '': P.append({'Head': head, 'Body': list(body.split())}) terminals.extend(P[-1]['Body']) set_terminals, set_nonTerminals = set(terminals).difference( nonTerminals + ['epsilon']), set(nonTerminals) N, T = [], [] for nt in nonTerminals: if nt in set_nonTerminals and set_nonTerminals.discard( nt) == None: N.append(nt) for t in terminals: if t in set_terminals and set_terminals.discard(t) == None: T.append(t) data = json.dumps({ 'Terminals': T, 'NonTerminals': N, 'Productions': P }) G = Grammar.from_json(data) # print(data) G.startSymbol = G.nonTerminals[0] return G except: return None
def parseGrammar(self, text: str): terminals, nonTerminals, productions = [], [], [] try: lines = text.split('\r\n') for line in lines: head, bodies = line.split('->') head, = head.split() if len(head[0]) > 1: raise BadGrammarException() nonTerminals.append(head) for body in bodies.split('|'): productions.append({ 'Head': head, 'Body': list(body.split()) }) terminals.extend(productions[-1]['Body']) except: raise BadGrammarException() nonTerminals = set(nonTerminals) terminals = set( [t for t in terminals if t not in nonTerminals and t != 'epsilon']) data = json.dumps({ 'NonTerminals': [nt for nt in nonTerminals], 'Terminals': [t for t in terminals], 'Productions': productions }) return Grammar.from_json(data)