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