-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscope02.py
More file actions
161 lines (127 loc) · 4.29 KB
/
Copy pathscope02.py
File metadata and controls
161 lines (127 loc) · 4.29 KB
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
from collections import OrderedDict
from spi import (
Lexer,
Parser,
NodeVisitor,
BuiltinTypeSymbol,
VarSymbol,
ProcedureSymbol
)
class ScopedSymbolTable(object):
def __init__(self, scope_name, scope_level):
self._symbols = OrderedDict()
self.scope_name = scope_name
self.scope_level = scope_level
self._init_builtins()
def _init_builtins(self):
self.insert(BuiltinTypeSymbol('INTEGER'))
self.insert(BuiltinTypeSymbol('REAL'))
def __str__(self):
h1 = 'SCOPE (SCOPED SYMBOL TABLE)'
lines = ['\n', h1, '=' * len(h1)]
for header_name, header_value in (
('Scope name', self.scope_name),
('Scope level', self.scope_level),
):
lines.append('%-15s: %s' % (header_name, header_value))
h2 = 'Scope (Scoped symbol table) contents'
lines.extend([h2, '-' * len(h2)])
lines.extend(
('%7s: %r' % (key, value))
for key, value in self._symbols.items()
)
lines.append('\n')
s = '\n'.join(lines)
return s
__repr__ = __str__
def insert(self, symbol):
print('Insert: %s' % symbol.name)
self._symbols[symbol.name] = symbol
def lookup(self, name):
print('Lookup: %s' % name)
symbol = self._symbols.get(name)
# 'symbol' is either an instance of the Symbol class or None
return symbol
class SemanticAnalyzer(NodeVisitor):
def __init__(self):
self.current_scope = None
def visit_Block(self, node):
for declaration in node.declarations:
self.visit(declaration)
self.visit(node.compound_statement)
def visit_Program(self, node):
print('ENTER scope: global')
global_scope = ScopedSymbolTable(
scope_name='global',
scope_level=1,
)
self.current_scope = global_scope
# visit subtree
self.visit(node.block)
print(global_scope)
print('LEAVE scope: global')
def visit_Compound(self, node):
for child in node.children:
self.visit(child)
def visit_NoOp(self, node):
pass
def visit_BinOp(self, node):
self.visit(node.left)
self.visit(node.right)
def visit_ProcedureDecl(self, node):
proc_name = node.proc_name
proc_symbol = ProcedureSymbol(proc_name)
self.current_scope.insert(proc_symbol)
print('ENTER scope: %s' % proc_name)
# Scope for parameters and local variables
procedure_scope = ScopedSymbolTable(
scope_name=proc_name,
scope_level=2,
)
self.current_scope = procedure_scope
# Insert parameters into the procedure scope
for param in node.params:
param_type = self.current_scope.lookup(param.type_node.value)
param_name = param.var_node.value
var_symbol = VarSymbol(param_name, param_type)
self.current_scope.insert(var_symbol)
proc_symbol.params.append(var_symbol)
self.visit(node.block_node)
print(procedure_scope)
print('LEAVE scope: %s' % proc_name)
def visit_VarDecl(self, node):
type_name = node.type_node.value
type_symbol = self.current_scope.lookup(type_name)
# We have all the information we need to create a variable symbol.
# Create the symbol and insert it into the symbol table.
var_name = node.var_node.value
var_symbol = VarSymbol(var_name, type_symbol)
self.current_scope.insert(var_symbol)
def visit_Assign(self, node):
# right-hand side
self.visit(node.right)
# left-hand side
self.visit(node.left)
def visit_Var(self, node):
var_name = node.value
var_symbol = self.current_scope.lookup(var_name)
if var_symbol is None:
raise Exception(
"Error: Symbol(identifier) not found '%s'" % var_name
)
if __name__ == '__main__':
text = """
program Main;
var x, y: real;
procedure Alpha(a : integer);
var y : integer;
begin
end;
begin { Main }
end. { Main }
"""
lexer = Lexer(text)
parser = Parser(lexer)
tree = parser.parse()
semantic_analyzer = SemanticAnalyzer()
semantic_analyzer.visit(tree)