· 9 years ago · Nov 29, 2016, 10:36 AM
1#!/usr/bin/python
2import AST
3from SymbolTable import VariableSymbol, FunctionSymbol, SymbolTable
4
5#####################################################
6# Valid types dictionary
7#####################################################
8ttype = {}
9types = ['float', 'int', 'string']
10arithmetic_ops = ['+', '-', '*', '/', '%']
11bit_ops = ['|', '&', '^', '<<', '>>']
12comparison_ops = ['==', '!=', '>', '<', '<=', '>=']
13logical_ops = ['&&', '||']
14all_ops = arithmetic_ops + bit_ops + comparison_ops + logical_ops + ['=']
15
16for op in all_ops:
17 ttype[op] = {}
18 for t in types:
19 ttype[op][t] = {}
20
21for op in arithmetic_ops:
22 ttype[op]['int']['int'] = 'int'
23 ttype[op]['float']['float'] = 'float'
24 ttype[op]['int']['float'] = 'float'
25 ttype[op]['float']['int'] = 'float'
26
27ttype['+']['string']['string'] = 'string'
28ttype['*']['string']['int'] = 'string'
29
30for op in bit_ops:
31 ttype[op]['int']['int'] = 'int'
32
33for op in comparison_ops:
34 ttype[op]['int']['int'] = 'int'
35 ttype[op]['float']['float'] = 'int'
36 ttype[op]['string']['string'] = 'int'
37 ttype[op]['float']['int'] = 'int'
38 ttype[op]['int']['float'] = 'int'
39
40for op in logical_ops:
41 ttype[op]['int']['int'] = 'int'
42
43ttype['=']['int']['int'] = 'int'
44ttype['=']['float']['float'] = 'float'
45ttype['=']['float']['int'] = 'float'
46ttype['=']['string']['string'] = 'string'
47ttype['=']['int']['float'] = 'int' # warning
48
49#####################################################
50#####################################################
51
52class NodeVisitor(object):
53 # args = init type
54 def visit(self, node, *args):
55 method = 'visit_' + node.__class__.__name__
56 visitor = getattr(self, method)
57 return visitor(node, *args)
58
59class TypeChecker(NodeVisitor):
60 def __init__(self):
61 self.symbolTable = SymbolTable(None, 'root')
62
63 def visit_Program(self, node):
64 self.visit(node.sections)
65
66 def visit_Sections(self, node):
67 for section in node.sections:
68 self.visit(section)
69
70 def visit_Section(self, node):
71 self.visit(node.section)
72
73 def visit_Declaration(self, node):
74 self.visit(node.inits, node.type)
75
76 def visit_Inits(self, node, type):
77 for init in node.inits:
78 self.visit(init, type)
79
80 def visit_Init(self, node, type):
81 # symbol was in table
82 if self.symbolTable.get(node.id) is not None:
83 print "Error: Invalid definition of " + node.name + ". Line: " + str(node.line)
84 # symbol was not entered
85 else:
86 expr_type = self.visit(node.expression)
87 # check declared and expression types compatibility
88 if ttype['='][type][expr_type] is None:
89 print "Error: Bad Assign of " + expr_type + " to " + type + ". Line: " + str(node.line)
90 # int = float
91 else:
92 if type == 'int' and expr_type == 'float':
93 print "Warning: Assining float to int variable " + node.id + " may cause precision loss! Line " + str(node.line)
94 self.symbolTable.put(node.id, VariableSymbol(node.id, type))
95
96 def visit_Instructions(self, node):
97 for instruction in node.instructions:
98 self.visit(instruction)
99
100 def visit_PrintInstruction(self, node):
101 self.visit(node.expression_list)
102
103 def visit_LabeledInstruction(self, node):
104 self.visit(node.instruction)
105
106 def visit_Assigment(self, node):
107 # variable was not declared -> error
108 var = self.symbolTable.get(node.id)
109 if var is None:
110 print "Error: Symbol " + node.id + " was not declared before using. Line: "+ str(str(node.line))
111 else:
112 expr_type = self.visit(node.expression)
113 # check declared and expression types compatibility
114 if ttype['='][var.type][expr_type] is None:
115 print "Error: Bad Assign of " + expr_type + " to " + var.type + ". Line: " + str(node.line)
116 else:
117 return ttype['='][var.type][expr_type]
118
119 def visit_Condition(self, node):
120 self.visit(node.expression)
121
122 def visit_ChoiceInstruction(self, node):
123 self.visit(node.condition)
124 self.visit(node.instruction)
125 self.visit(node.alternative)
126
127 def visit_WhileInstruction(self, node):
128 self.visit(node.condition)
129 self.visit(node.instruction)
130
131 def visit_RepeatInstruction(self, node):
132 self.visit(node.instructions)
133 self.visit(node.condition)
134
135 def visit_ReturnInstruction(self, node):
136 self.visit(node.expression)
137
138 def visit_CompoundInstruction(self, node):
139 # create new scope
140 self.symbolTable = self.symbolTable.pushScope("compoundScope")
141
142 self.visit(node.body)
143
144 # return root scope
145 self.symbolTable =self.symbolTable.popScope()
146
147 def visit_Body(self, node):
148 if node.body is not None:
149 for component in node.body:
150 self.visit(component)
151
152 def visit_Component(self, node):
153 self.visit(node.component)
154
155 # TODO
156 def visit_Const(self, node):
157 # recognize const type
158 value = node.value
159 if (value[0] in ('"', "'")) and (value[len(value) - 1] in ('"', "'")):
160 return 'string'
161 try:
162 int(value)
163 return 'int'
164 except ValueError:
165 try:
166 float(value)
167 return 'float'
168 except ValueError:
169 print "Error: Value " + value + " type is not recognized" + str(node.line)
170
171 def visit_Expressions(self, node):
172 for expression in node.expressions:
173 self.visit(expression)
174
175 def visit_FunDef(self, node):
176 id = self.symbolTable.get(node.id)
177 # symbol already exists -> error
178 if id is not None:
179 print "Error: Function " + node.id + " already exists. Line: " + str(node.line)
180 else:
181 # create new scope
182 self.symbolTable = self.symbolTable.pushScope(node.id)
183 # put fun symbol to root scope and new scope
184 funSymbol = FunctionSymbol(node.id, node.type, self.symbolTable.getParentScope())
185 self.symbolTable.put(node.id, funSymbol)
186 self.symbolTable.getParentScope().put(node.id, funSymbol)
187
188 # visit args and check them validity
189 if node.args is not None:
190 self.visit(node.args)
191 # visit compound instr
192 if node.comp is not None:
193 self.visit(node.comp)
194
195 # return root scope
196 self.symbolTable = self.symbolTable.popScope()
197
198 def visit_ArgsList(self, node):
199 for arg in node.args:
200 self.visit(arg)
201
202 def visit_Arg(self, node):
203 id = self.symbolTable.get(node.id)
204 # symbol already exists -> error
205 if id is not None:
206 print "Error: Symbol " + node.id + " already exists. Line: " + str(node.line)
207 else:
208 self.symbolTable.put(node.id, VariableSymbol(node.id, node.type))
209
210 def visit_BinExpr(self, node):
211 left_type = self.visit(node.left)
212 right_type = self.visit(node.right)
213
214 if ttype[node.op][left_type][right_type] is None:
215 print "Error: " # TODO
216 else:
217 return ttype[node.op][left_type][right_type]
218
219 def visit_FunctionCalling(self, node):
220 pass
221 # TODO
222
223 def visit_Id(self, node):
224 # symbol does not exist -> error # TODO check other symbols scopes
225 scope = self.symbolTable
226 while scope is not None:
227 id = scope.get(node.id)
228 if id is None:
229 scope = scope.getParentScope()
230 else:
231 return id.type
232 print "Error: Symbol " + node.id + " was not declared before using."