forked from hghwng/toy-parser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
grammar.py
77 lines (60 loc) · 2.11 KB
/
grammar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/env python
from collections import defaultdict
class Grammar:
def __init__(self):
self.start = None
self.terms = set() # terminals
# prods[nterm] = list of Production objects
self.prods = defaultdict(list)
def add_production(self, nterm, syms):
production = Production(nterm, syms)
self.prods[nterm].append(production)
def is_nonterminal(self, symbol: str) -> bool:
return symbol in self.prods
def is_terminal(self, symbol: str) -> bool:
return symbol in self.terms
def get_alt_nonterminal(self, nonterm: str) -> str:
nonterm += "'"
while nonterm in self.prods:
nonterm += "'"
return nonterm
def get_start_prodctions(self):
return self.prods[self.start]
def duplicate(self):
from copy import deepcopy
return deepcopy(self)
def __str__(self):
result = "Grammar:\n"
result += " Start: " + self.start
result += "\n Terminals: " + " ".join(self.terms)
result += "\n Nonterminals: " + " ".join(self.prods.keys())
result += "\n Productions:"
for prodlist in self.prods.values():
for prod in prodlist:
result += "\n " + str(prod)
return result
class Production:
def __init__(self, nterm: str, syms: list):
self.nterm = nterm
self.syms = Production.remove_eps(syms)
def __eq__(self, other):
return self.nterm == other.nterm and self.syms == other.syms
def __ne__(self, other):
return not self == other
def __hash__(self):
result = hash(self.nterm)
for sym in self.syms:
result ^= hash(sym)
return result
@staticmethod
def remove_eps(syms: list) -> list:
for sym in syms:
if sym != '@':
break
else:
return ['@']
return list(filter(lambda x: x != '@', syms))
def __repr__(self):
return "Production({}, {})".format(self.nterm, self.syms)
def __str__(self):
return "{} → {}".format(self.nterm, " ".join(self.syms))