def __init__(self): self.scope = SymbolTable(None, 'main')
class TypeChecker(NodeVisitor): def __init__(self): self.scope = SymbolTable(None, 'main') def visit_BinExpr(self, node): type1 = self.visit(node.left) type2 = self.visit(node.right) if ttype[node.op][type1][type2] is None: print "Bad expression {} in line {}".format(node.op, node.line) return ttype[node.op][type1][type2] def visit_Const(self, node): if re.match(r"(\+|-){0,1}(\d+\.\d+|\.\d+)", node.val): return self.visit_Float(node) elif re.match(r"(\+|-){0,1}\d+", node.val): return self.visit_Integer(node) elif re.match(r"\A('.*'|\".*\")\Z", node.val): return self.visit_String(node) else: variable = self.scope.get(node.val) if variable is None: print "Variable {} in line {} hasn't been declared".format(node.val, node.line) else: return variable.type def visit_Integer(self, node): return 'int' def visit_Float(self,node): return 'float' def visit_String(self,node): return 'string' def visit_Declaration(self, node): visited_inits = self.visit(node.inits) if visited_inits is not None: for curr in self.visit(node.inits): if self.scope.get_not_parent(curr[0]) is not None: print "Variable {} in line {} has been declared earlier".format(curr[0], node.line) else: if node.type == curr[1] or (node.type == 'float' and curr[1] == 'int'): self.scope.put(curr[0], VariableSymbol(curr[0], node.type)) elif node.type == 'int' and curr[1] == 'float': print "Warning! You lost float precision in line {}".format(node.line) self.scope.put(curr[0], VariableSymbol(curr[0], node.type)) else: print "Type mismatch in line {}".format(node.line) def visit_ReturnInstr(self, node): self.scope.put('return', 'return') if not isinstance(self.scope.get(self.scope.name), FunctionSymbol): print "Return outside function in line {}".format(node.line) if self.scope.parent.get(self.scope.name) is not None: expr = self.visit(node.expr) if self.scope.parent.get(self.scope.name).type == 'int' and expr == 'float': print "Warning! You lost float precision in line {}".format(node.line) elif not (self.scope.parent.get(self.scope.name).type == expr or (self.scope.parent.get(self.scope.name).type == 'float' and expr=='int')): print "Type mismatch in line {}".format(node.line) def visit_PrintInstr(self, node): self.visit(node.expr) def visit_Init(self, node): return (node.id, self.visit(node.expr)) def visit_AssignmentInstr(self, node): type = self.visit(node.expr) if type is None: return None var_from_scope = self.scope.get(node.id) if var_from_scope is None: print "Variable {} in line {} hasn't been declared".format(node.id, node.line) else: if var_from_scope.type == 'int' and type == 'float': print "Warning! You lost float precision in line {}".format(node.line) self.scope.put(node.id, VariableSymbol(node.id, type)) elif not (var_from_scope.type == type or (var_from_scope.type == 'float' and type=='int')): print "Type mismatch in line {}".format(node.line) return (node.id, type) def visit_ChoiceInstr(self, node): self.visit(node.condition) self.visit(node.instruction) self.visit(node.else_instr) def visit_WhileInstr(self, node): self.visit(node.condition) self.scope = self.scope.pushScope("loop") self.visit(node.instruction) self.scope = self.scope.popScope() def visit_RepeatInstr(self, node): self.visit(node.condition) self.scope = self.scope.pushScope("loop") self.visit(node.instruction) self.scope = self.scope.popScope() def visit_ContinueInstr(self, node): if self.scope.name != "loop": print "Continue outside the loop in line {}".format(node.line) def visit_BreakInstr(self, node): if self.scope.name != "loop": print "Break outside the loop in line {}".format(node.line) def visit_CompoundInstr(self, node): self.visit(node.declarations) self.visit(node.instructions_opt) def visit_CastFunction(self, node): function = self.scope.get(node.functionName) if function is None: print "Function {} in line {} has not been declared".format(node.functionName, node.line) return args_cast = self.visit(node.args) args_scope = self.visit(function.arguments) if len(args_cast) != len(args_scope): print "Wrong numbers of arguments in line {}".format(node.line) else: for arg in args_scope: i = args_scope.index(arg) if arg[1] == 'int' and args_cast[i] == 'float': print "Warning! You lost float precision in line {}".format(node.line) elif not (arg[1] == args_cast[i] or (arg[1] == 'float' and args_cast[i] == 'int')): print "Function arguments mismatch in line {}".format(node.line) return function.type def visit_ExprInBrackets(self, node): return self.visit(node.expr) def visit_Function(self, node): if self.scope.get(node.id) is not None: print "Function {} in line {} has been declared earlier".format(node.id, node.line) else: self.scope.put(node.id, FunctionSymbol(node.id, node.type, node.args_list_or_empty)) self.scope = self.scope.pushScope(node.id) self.visit(node.args_list_or_empty) self.visit(node.compound_instr) if node.type != "void" and self.scope.get_not_parent('return') is None: print "No return for function in line {}".format(node.line) self.scope = self.scope.popScope() def visit_Argument(self, node): self.scope.put(node.id, VariableSymbol(node.id, node.type)) return (node.id, node.type) def visit_Block(self, node): self.scope = self.scope.pushScope("block") self.visit(node.declarations) self.visit(node.fundefs_opt) self.visit(node.instructions_opt) self.scope = self.scope.popScope()