17db96d56Sopenharmony_ci# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. 27db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement. 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ci# Pgen imports 57db96d56Sopenharmony_cifrom . import grammar, token, tokenize 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciclass PgenGrammar(grammar.Grammar): 87db96d56Sopenharmony_ci pass 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciclass ParserGenerator(object): 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci def __init__(self, filename, stream=None): 137db96d56Sopenharmony_ci close_stream = None 147db96d56Sopenharmony_ci if stream is None: 157db96d56Sopenharmony_ci stream = open(filename, encoding="utf-8") 167db96d56Sopenharmony_ci close_stream = stream.close 177db96d56Sopenharmony_ci self.filename = filename 187db96d56Sopenharmony_ci self.stream = stream 197db96d56Sopenharmony_ci self.generator = tokenize.generate_tokens(stream.readline) 207db96d56Sopenharmony_ci self.gettoken() # Initialize lookahead 217db96d56Sopenharmony_ci self.dfas, self.startsymbol = self.parse() 227db96d56Sopenharmony_ci if close_stream is not None: 237db96d56Sopenharmony_ci close_stream() 247db96d56Sopenharmony_ci self.first = {} # map from symbol name to set of tokens 257db96d56Sopenharmony_ci self.addfirstsets() 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ci def make_grammar(self): 287db96d56Sopenharmony_ci c = PgenGrammar() 297db96d56Sopenharmony_ci names = list(self.dfas.keys()) 307db96d56Sopenharmony_ci names.sort() 317db96d56Sopenharmony_ci names.remove(self.startsymbol) 327db96d56Sopenharmony_ci names.insert(0, self.startsymbol) 337db96d56Sopenharmony_ci for name in names: 347db96d56Sopenharmony_ci i = 256 + len(c.symbol2number) 357db96d56Sopenharmony_ci c.symbol2number[name] = i 367db96d56Sopenharmony_ci c.number2symbol[i] = name 377db96d56Sopenharmony_ci for name in names: 387db96d56Sopenharmony_ci dfa = self.dfas[name] 397db96d56Sopenharmony_ci states = [] 407db96d56Sopenharmony_ci for state in dfa: 417db96d56Sopenharmony_ci arcs = [] 427db96d56Sopenharmony_ci for label, next in sorted(state.arcs.items()): 437db96d56Sopenharmony_ci arcs.append((self.make_label(c, label), dfa.index(next))) 447db96d56Sopenharmony_ci if state.isfinal: 457db96d56Sopenharmony_ci arcs.append((0, dfa.index(state))) 467db96d56Sopenharmony_ci states.append(arcs) 477db96d56Sopenharmony_ci c.states.append(states) 487db96d56Sopenharmony_ci c.dfas[c.symbol2number[name]] = (states, self.make_first(c, name)) 497db96d56Sopenharmony_ci c.start = c.symbol2number[self.startsymbol] 507db96d56Sopenharmony_ci return c 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci def make_first(self, c, name): 537db96d56Sopenharmony_ci rawfirst = self.first[name] 547db96d56Sopenharmony_ci first = {} 557db96d56Sopenharmony_ci for label in sorted(rawfirst): 567db96d56Sopenharmony_ci ilabel = self.make_label(c, label) 577db96d56Sopenharmony_ci ##assert ilabel not in first # XXX failed on <> ... != 587db96d56Sopenharmony_ci first[ilabel] = 1 597db96d56Sopenharmony_ci return first 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def make_label(self, c, label): 627db96d56Sopenharmony_ci # XXX Maybe this should be a method on a subclass of converter? 637db96d56Sopenharmony_ci ilabel = len(c.labels) 647db96d56Sopenharmony_ci if label[0].isalpha(): 657db96d56Sopenharmony_ci # Either a symbol name or a named token 667db96d56Sopenharmony_ci if label in c.symbol2number: 677db96d56Sopenharmony_ci # A symbol name (a non-terminal) 687db96d56Sopenharmony_ci if label in c.symbol2label: 697db96d56Sopenharmony_ci return c.symbol2label[label] 707db96d56Sopenharmony_ci else: 717db96d56Sopenharmony_ci c.labels.append((c.symbol2number[label], None)) 727db96d56Sopenharmony_ci c.symbol2label[label] = ilabel 737db96d56Sopenharmony_ci return ilabel 747db96d56Sopenharmony_ci else: 757db96d56Sopenharmony_ci # A named token (NAME, NUMBER, STRING) 767db96d56Sopenharmony_ci itoken = getattr(token, label, None) 777db96d56Sopenharmony_ci assert isinstance(itoken, int), label 787db96d56Sopenharmony_ci assert itoken in token.tok_name, label 797db96d56Sopenharmony_ci if itoken in c.tokens: 807db96d56Sopenharmony_ci return c.tokens[itoken] 817db96d56Sopenharmony_ci else: 827db96d56Sopenharmony_ci c.labels.append((itoken, None)) 837db96d56Sopenharmony_ci c.tokens[itoken] = ilabel 847db96d56Sopenharmony_ci return ilabel 857db96d56Sopenharmony_ci else: 867db96d56Sopenharmony_ci # Either a keyword or an operator 877db96d56Sopenharmony_ci assert label[0] in ('"', "'"), label 887db96d56Sopenharmony_ci value = eval(label) 897db96d56Sopenharmony_ci if value[0].isalpha(): 907db96d56Sopenharmony_ci # A keyword 917db96d56Sopenharmony_ci if value in c.keywords: 927db96d56Sopenharmony_ci return c.keywords[value] 937db96d56Sopenharmony_ci else: 947db96d56Sopenharmony_ci c.labels.append((token.NAME, value)) 957db96d56Sopenharmony_ci c.keywords[value] = ilabel 967db96d56Sopenharmony_ci return ilabel 977db96d56Sopenharmony_ci else: 987db96d56Sopenharmony_ci # An operator (any non-numeric token) 997db96d56Sopenharmony_ci itoken = grammar.opmap[value] # Fails if unknown token 1007db96d56Sopenharmony_ci if itoken in c.tokens: 1017db96d56Sopenharmony_ci return c.tokens[itoken] 1027db96d56Sopenharmony_ci else: 1037db96d56Sopenharmony_ci c.labels.append((itoken, None)) 1047db96d56Sopenharmony_ci c.tokens[itoken] = ilabel 1057db96d56Sopenharmony_ci return ilabel 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci def addfirstsets(self): 1087db96d56Sopenharmony_ci names = list(self.dfas.keys()) 1097db96d56Sopenharmony_ci names.sort() 1107db96d56Sopenharmony_ci for name in names: 1117db96d56Sopenharmony_ci if name not in self.first: 1127db96d56Sopenharmony_ci self.calcfirst(name) 1137db96d56Sopenharmony_ci #print name, self.first[name].keys() 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci def calcfirst(self, name): 1167db96d56Sopenharmony_ci dfa = self.dfas[name] 1177db96d56Sopenharmony_ci self.first[name] = None # dummy to detect left recursion 1187db96d56Sopenharmony_ci state = dfa[0] 1197db96d56Sopenharmony_ci totalset = {} 1207db96d56Sopenharmony_ci overlapcheck = {} 1217db96d56Sopenharmony_ci for label, next in state.arcs.items(): 1227db96d56Sopenharmony_ci if label in self.dfas: 1237db96d56Sopenharmony_ci if label in self.first: 1247db96d56Sopenharmony_ci fset = self.first[label] 1257db96d56Sopenharmony_ci if fset is None: 1267db96d56Sopenharmony_ci raise ValueError("recursion for rule %r" % name) 1277db96d56Sopenharmony_ci else: 1287db96d56Sopenharmony_ci self.calcfirst(label) 1297db96d56Sopenharmony_ci fset = self.first[label] 1307db96d56Sopenharmony_ci totalset.update(fset) 1317db96d56Sopenharmony_ci overlapcheck[label] = fset 1327db96d56Sopenharmony_ci else: 1337db96d56Sopenharmony_ci totalset[label] = 1 1347db96d56Sopenharmony_ci overlapcheck[label] = {label: 1} 1357db96d56Sopenharmony_ci inverse = {} 1367db96d56Sopenharmony_ci for label, itsfirst in overlapcheck.items(): 1377db96d56Sopenharmony_ci for symbol in itsfirst: 1387db96d56Sopenharmony_ci if symbol in inverse: 1397db96d56Sopenharmony_ci raise ValueError("rule %s is ambiguous; %s is in the" 1407db96d56Sopenharmony_ci " first sets of %s as well as %s" % 1417db96d56Sopenharmony_ci (name, symbol, label, inverse[symbol])) 1427db96d56Sopenharmony_ci inverse[symbol] = label 1437db96d56Sopenharmony_ci self.first[name] = totalset 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci def parse(self): 1467db96d56Sopenharmony_ci dfas = {} 1477db96d56Sopenharmony_ci startsymbol = None 1487db96d56Sopenharmony_ci # MSTART: (NEWLINE | RULE)* ENDMARKER 1497db96d56Sopenharmony_ci while self.type != token.ENDMARKER: 1507db96d56Sopenharmony_ci while self.type == token.NEWLINE: 1517db96d56Sopenharmony_ci self.gettoken() 1527db96d56Sopenharmony_ci # RULE: NAME ':' RHS NEWLINE 1537db96d56Sopenharmony_ci name = self.expect(token.NAME) 1547db96d56Sopenharmony_ci self.expect(token.OP, ":") 1557db96d56Sopenharmony_ci a, z = self.parse_rhs() 1567db96d56Sopenharmony_ci self.expect(token.NEWLINE) 1577db96d56Sopenharmony_ci #self.dump_nfa(name, a, z) 1587db96d56Sopenharmony_ci dfa = self.make_dfa(a, z) 1597db96d56Sopenharmony_ci #self.dump_dfa(name, dfa) 1607db96d56Sopenharmony_ci oldlen = len(dfa) 1617db96d56Sopenharmony_ci self.simplify_dfa(dfa) 1627db96d56Sopenharmony_ci newlen = len(dfa) 1637db96d56Sopenharmony_ci dfas[name] = dfa 1647db96d56Sopenharmony_ci #print name, oldlen, newlen 1657db96d56Sopenharmony_ci if startsymbol is None: 1667db96d56Sopenharmony_ci startsymbol = name 1677db96d56Sopenharmony_ci return dfas, startsymbol 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci def make_dfa(self, start, finish): 1707db96d56Sopenharmony_ci # To turn an NFA into a DFA, we define the states of the DFA 1717db96d56Sopenharmony_ci # to correspond to *sets* of states of the NFA. Then do some 1727db96d56Sopenharmony_ci # state reduction. Let's represent sets as dicts with 1 for 1737db96d56Sopenharmony_ci # values. 1747db96d56Sopenharmony_ci assert isinstance(start, NFAState) 1757db96d56Sopenharmony_ci assert isinstance(finish, NFAState) 1767db96d56Sopenharmony_ci def closure(state): 1777db96d56Sopenharmony_ci base = {} 1787db96d56Sopenharmony_ci addclosure(state, base) 1797db96d56Sopenharmony_ci return base 1807db96d56Sopenharmony_ci def addclosure(state, base): 1817db96d56Sopenharmony_ci assert isinstance(state, NFAState) 1827db96d56Sopenharmony_ci if state in base: 1837db96d56Sopenharmony_ci return 1847db96d56Sopenharmony_ci base[state] = 1 1857db96d56Sopenharmony_ci for label, next in state.arcs: 1867db96d56Sopenharmony_ci if label is None: 1877db96d56Sopenharmony_ci addclosure(next, base) 1887db96d56Sopenharmony_ci states = [DFAState(closure(start), finish)] 1897db96d56Sopenharmony_ci for state in states: # NB states grows while we're iterating 1907db96d56Sopenharmony_ci arcs = {} 1917db96d56Sopenharmony_ci for nfastate in state.nfaset: 1927db96d56Sopenharmony_ci for label, next in nfastate.arcs: 1937db96d56Sopenharmony_ci if label is not None: 1947db96d56Sopenharmony_ci addclosure(next, arcs.setdefault(label, {})) 1957db96d56Sopenharmony_ci for label, nfaset in sorted(arcs.items()): 1967db96d56Sopenharmony_ci for st in states: 1977db96d56Sopenharmony_ci if st.nfaset == nfaset: 1987db96d56Sopenharmony_ci break 1997db96d56Sopenharmony_ci else: 2007db96d56Sopenharmony_ci st = DFAState(nfaset, finish) 2017db96d56Sopenharmony_ci states.append(st) 2027db96d56Sopenharmony_ci state.addarc(st, label) 2037db96d56Sopenharmony_ci return states # List of DFAState instances; first one is start 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci def dump_nfa(self, name, start, finish): 2067db96d56Sopenharmony_ci print("Dump of NFA for", name) 2077db96d56Sopenharmony_ci todo = [start] 2087db96d56Sopenharmony_ci for i, state in enumerate(todo): 2097db96d56Sopenharmony_ci print(" State", i, state is finish and "(final)" or "") 2107db96d56Sopenharmony_ci for label, next in state.arcs: 2117db96d56Sopenharmony_ci if next in todo: 2127db96d56Sopenharmony_ci j = todo.index(next) 2137db96d56Sopenharmony_ci else: 2147db96d56Sopenharmony_ci j = len(todo) 2157db96d56Sopenharmony_ci todo.append(next) 2167db96d56Sopenharmony_ci if label is None: 2177db96d56Sopenharmony_ci print(" -> %d" % j) 2187db96d56Sopenharmony_ci else: 2197db96d56Sopenharmony_ci print(" %s -> %d" % (label, j)) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci def dump_dfa(self, name, dfa): 2227db96d56Sopenharmony_ci print("Dump of DFA for", name) 2237db96d56Sopenharmony_ci for i, state in enumerate(dfa): 2247db96d56Sopenharmony_ci print(" State", i, state.isfinal and "(final)" or "") 2257db96d56Sopenharmony_ci for label, next in sorted(state.arcs.items()): 2267db96d56Sopenharmony_ci print(" %s -> %d" % (label, dfa.index(next))) 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci def simplify_dfa(self, dfa): 2297db96d56Sopenharmony_ci # This is not theoretically optimal, but works well enough. 2307db96d56Sopenharmony_ci # Algorithm: repeatedly look for two states that have the same 2317db96d56Sopenharmony_ci # set of arcs (same labels pointing to the same nodes) and 2327db96d56Sopenharmony_ci # unify them, until things stop changing. 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci # dfa is a list of DFAState instances 2357db96d56Sopenharmony_ci changes = True 2367db96d56Sopenharmony_ci while changes: 2377db96d56Sopenharmony_ci changes = False 2387db96d56Sopenharmony_ci for i, state_i in enumerate(dfa): 2397db96d56Sopenharmony_ci for j in range(i+1, len(dfa)): 2407db96d56Sopenharmony_ci state_j = dfa[j] 2417db96d56Sopenharmony_ci if state_i == state_j: 2427db96d56Sopenharmony_ci #print " unify", i, j 2437db96d56Sopenharmony_ci del dfa[j] 2447db96d56Sopenharmony_ci for state in dfa: 2457db96d56Sopenharmony_ci state.unifystate(state_j, state_i) 2467db96d56Sopenharmony_ci changes = True 2477db96d56Sopenharmony_ci break 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci def parse_rhs(self): 2507db96d56Sopenharmony_ci # RHS: ALT ('|' ALT)* 2517db96d56Sopenharmony_ci a, z = self.parse_alt() 2527db96d56Sopenharmony_ci if self.value != "|": 2537db96d56Sopenharmony_ci return a, z 2547db96d56Sopenharmony_ci else: 2557db96d56Sopenharmony_ci aa = NFAState() 2567db96d56Sopenharmony_ci zz = NFAState() 2577db96d56Sopenharmony_ci aa.addarc(a) 2587db96d56Sopenharmony_ci z.addarc(zz) 2597db96d56Sopenharmony_ci while self.value == "|": 2607db96d56Sopenharmony_ci self.gettoken() 2617db96d56Sopenharmony_ci a, z = self.parse_alt() 2627db96d56Sopenharmony_ci aa.addarc(a) 2637db96d56Sopenharmony_ci z.addarc(zz) 2647db96d56Sopenharmony_ci return aa, zz 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci def parse_alt(self): 2677db96d56Sopenharmony_ci # ALT: ITEM+ 2687db96d56Sopenharmony_ci a, b = self.parse_item() 2697db96d56Sopenharmony_ci while (self.value in ("(", "[") or 2707db96d56Sopenharmony_ci self.type in (token.NAME, token.STRING)): 2717db96d56Sopenharmony_ci c, d = self.parse_item() 2727db96d56Sopenharmony_ci b.addarc(c) 2737db96d56Sopenharmony_ci b = d 2747db96d56Sopenharmony_ci return a, b 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci def parse_item(self): 2777db96d56Sopenharmony_ci # ITEM: '[' RHS ']' | ATOM ['+' | '*'] 2787db96d56Sopenharmony_ci if self.value == "[": 2797db96d56Sopenharmony_ci self.gettoken() 2807db96d56Sopenharmony_ci a, z = self.parse_rhs() 2817db96d56Sopenharmony_ci self.expect(token.OP, "]") 2827db96d56Sopenharmony_ci a.addarc(z) 2837db96d56Sopenharmony_ci return a, z 2847db96d56Sopenharmony_ci else: 2857db96d56Sopenharmony_ci a, z = self.parse_atom() 2867db96d56Sopenharmony_ci value = self.value 2877db96d56Sopenharmony_ci if value not in ("+", "*"): 2887db96d56Sopenharmony_ci return a, z 2897db96d56Sopenharmony_ci self.gettoken() 2907db96d56Sopenharmony_ci z.addarc(a) 2917db96d56Sopenharmony_ci if value == "+": 2927db96d56Sopenharmony_ci return a, z 2937db96d56Sopenharmony_ci else: 2947db96d56Sopenharmony_ci return a, a 2957db96d56Sopenharmony_ci 2967db96d56Sopenharmony_ci def parse_atom(self): 2977db96d56Sopenharmony_ci # ATOM: '(' RHS ')' | NAME | STRING 2987db96d56Sopenharmony_ci if self.value == "(": 2997db96d56Sopenharmony_ci self.gettoken() 3007db96d56Sopenharmony_ci a, z = self.parse_rhs() 3017db96d56Sopenharmony_ci self.expect(token.OP, ")") 3027db96d56Sopenharmony_ci return a, z 3037db96d56Sopenharmony_ci elif self.type in (token.NAME, token.STRING): 3047db96d56Sopenharmony_ci a = NFAState() 3057db96d56Sopenharmony_ci z = NFAState() 3067db96d56Sopenharmony_ci a.addarc(z, self.value) 3077db96d56Sopenharmony_ci self.gettoken() 3087db96d56Sopenharmony_ci return a, z 3097db96d56Sopenharmony_ci else: 3107db96d56Sopenharmony_ci self.raise_error("expected (...) or NAME or STRING, got %s/%s", 3117db96d56Sopenharmony_ci self.type, self.value) 3127db96d56Sopenharmony_ci 3137db96d56Sopenharmony_ci def expect(self, type, value=None): 3147db96d56Sopenharmony_ci if self.type != type or (value is not None and self.value != value): 3157db96d56Sopenharmony_ci self.raise_error("expected %s/%s, got %s/%s", 3167db96d56Sopenharmony_ci type, value, self.type, self.value) 3177db96d56Sopenharmony_ci value = self.value 3187db96d56Sopenharmony_ci self.gettoken() 3197db96d56Sopenharmony_ci return value 3207db96d56Sopenharmony_ci 3217db96d56Sopenharmony_ci def gettoken(self): 3227db96d56Sopenharmony_ci tup = next(self.generator) 3237db96d56Sopenharmony_ci while tup[0] in (tokenize.COMMENT, tokenize.NL): 3247db96d56Sopenharmony_ci tup = next(self.generator) 3257db96d56Sopenharmony_ci self.type, self.value, self.begin, self.end, self.line = tup 3267db96d56Sopenharmony_ci #print token.tok_name[self.type], repr(self.value) 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci def raise_error(self, msg, *args): 3297db96d56Sopenharmony_ci if args: 3307db96d56Sopenharmony_ci try: 3317db96d56Sopenharmony_ci msg = msg % args 3327db96d56Sopenharmony_ci except: 3337db96d56Sopenharmony_ci msg = " ".join([msg] + list(map(str, args))) 3347db96d56Sopenharmony_ci raise SyntaxError(msg, (self.filename, self.end[0], 3357db96d56Sopenharmony_ci self.end[1], self.line)) 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ciclass NFAState(object): 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci def __init__(self): 3407db96d56Sopenharmony_ci self.arcs = [] # list of (label, NFAState) pairs 3417db96d56Sopenharmony_ci 3427db96d56Sopenharmony_ci def addarc(self, next, label=None): 3437db96d56Sopenharmony_ci assert label is None or isinstance(label, str) 3447db96d56Sopenharmony_ci assert isinstance(next, NFAState) 3457db96d56Sopenharmony_ci self.arcs.append((label, next)) 3467db96d56Sopenharmony_ci 3477db96d56Sopenharmony_ciclass DFAState(object): 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci def __init__(self, nfaset, final): 3507db96d56Sopenharmony_ci assert isinstance(nfaset, dict) 3517db96d56Sopenharmony_ci assert isinstance(next(iter(nfaset)), NFAState) 3527db96d56Sopenharmony_ci assert isinstance(final, NFAState) 3537db96d56Sopenharmony_ci self.nfaset = nfaset 3547db96d56Sopenharmony_ci self.isfinal = final in nfaset 3557db96d56Sopenharmony_ci self.arcs = {} # map from label to DFAState 3567db96d56Sopenharmony_ci 3577db96d56Sopenharmony_ci def addarc(self, next, label): 3587db96d56Sopenharmony_ci assert isinstance(label, str) 3597db96d56Sopenharmony_ci assert label not in self.arcs 3607db96d56Sopenharmony_ci assert isinstance(next, DFAState) 3617db96d56Sopenharmony_ci self.arcs[label] = next 3627db96d56Sopenharmony_ci 3637db96d56Sopenharmony_ci def unifystate(self, old, new): 3647db96d56Sopenharmony_ci for label, next in self.arcs.items(): 3657db96d56Sopenharmony_ci if next is old: 3667db96d56Sopenharmony_ci self.arcs[label] = new 3677db96d56Sopenharmony_ci 3687db96d56Sopenharmony_ci def __eq__(self, other): 3697db96d56Sopenharmony_ci # Equality test -- ignore the nfaset instance variable 3707db96d56Sopenharmony_ci assert isinstance(other, DFAState) 3717db96d56Sopenharmony_ci if self.isfinal != other.isfinal: 3727db96d56Sopenharmony_ci return False 3737db96d56Sopenharmony_ci # Can't just return self.arcs == other.arcs, because that 3747db96d56Sopenharmony_ci # would invoke this method recursively, with cycles... 3757db96d56Sopenharmony_ci if len(self.arcs) != len(other.arcs): 3767db96d56Sopenharmony_ci return False 3777db96d56Sopenharmony_ci for label, next in self.arcs.items(): 3787db96d56Sopenharmony_ci if next is not other.arcs.get(label): 3797db96d56Sopenharmony_ci return False 3807db96d56Sopenharmony_ci return True 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_ci __hash__ = None # For Py3 compatibility. 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_cidef generate_grammar(filename="Grammar.txt"): 3857db96d56Sopenharmony_ci p = ParserGenerator(filename) 3867db96d56Sopenharmony_ci return p.make_grammar() 387