inline void promoteNumeric(Value& v1, Value& v2) { if (!numeric(v1) || !numeric(v2)) return; if (sameType(v1,v2)) return; switch (v1.type) { case Value::T_INEXACT: v2 = double(v2.i); return; case Value::T_EXACT: v1 = double(v1.i); return; default: assert(false); } }
bool operator!=(Value v1, Value v2) { promoteNumeric(v1, v2); if (!sameType(v1,v2)) return false; switch (v1.type) { case Value::T_BOOL: return v1.b != v2.b; case Value::T_STRING: return *v1.s != *v2.s; case Value::T_EXACT: return v1.i != v2.i; case Value::T_INEXACT: return v1.x != v2.x; default: return false; } }
bool Semantic::sameType(Type l, Type r) { return sameType(&l, &r); }
void Semantic::newSym(Symbol::Map &map, Symbol s) { if (s.stype == Symbol::FUNC || s.stype == Symbol::VAR) { if (map.find(s.id) != map.end()) if (s.stype != map[s.id].stype) error("multiple definition of symbol " + s.id); if (aid.find(s.id) != aid.end()) error("symbol name collides with type " + s.id); if (s.stype == Symbol::FUNC) { if (s.decl != NULL) { if (map[s.id].decl != NULL) { if (!sameType(s.decl->type, map[s.id].decl->type)) error("inconsistent declaration of function " + s.id); else { ArgItem * ptr = s.decl->list; ArgItem * old = map[s.id].decl->list; while (ptr != NULL) { if (old == NULL) { error("inconsistent declaration of function " + s.id); break; } if (!sameType(ptr->arg->type, old->arg->type)) { error("inconsistent declaration of function " + s.id); break; } ptr = ptr->next; old = old->next; } if (old != NULL) error("inconsistent declaration of function " + s.id); } } else { if (map[s.id].defn != NULL) { if (!sameType(s.decl->type, map[s.id].defn->type)) error("inconsistent declaration of function " + s.id); else { ArgItem * ptr = s.decl->list; ArgItem * old = map[s.id].defn->args; while (ptr != NULL) { if (old == NULL) { error("inconsistent declaration of function " + s.id); break; } if (!sameType(ptr->arg->type, old->arg->type)) { error("inconsistent declaration of function " + s.id); break; } ptr = ptr->next; old = old->next; } if (old != NULL) error("inconsistent declaration of function " + s.id); } } map[s.id] = s; } } else if (s.defn != NULL) { if (map[s.id].defn != NULL) error("multiple definition of function " + s.id); else { map[s.id] = s; if (map[s.id].decl != NULL) { if (!sameType(s.defn->type, map[s.id].decl->type)) error("inconsistent definition of function " + s.id); else { ArgItem * ptr = s.defn->args; ArgItem * old = map[s.id].decl->list; while (ptr != NULL) { if (old == NULL) { error("inconsistent definition of function " + s.id); break; } if (!sameType(ptr->arg->type, old->arg->type)) { error("inconsistent definition of function " + s.id); break; } ptr = ptr->next; old = old->next; } if (old != NULL) error("inconsistent definition of function " + s.id); } } map[s.id].defn = s.defn; } } } else if (s.stype == Symbol::VAR) map[s.id] = s; } else if (s.stype == Symbol::TYPE) { if (map.find(s.id) != map.end()) error("redeclaration of type " + s.id); for (auto it : vid) if (it.find(s.id) != it.end()) error("type name collides with symbol " + s.id); if (map.find(s.id) == map.end()) map[s.id] = s; } else if (s.stype == Symbol::STRCT) { if (s.defn != NULL && map.find(s.id) != map.end() && map[s.id].defn != NULL) error("redefinition of struct " + s.id); if ((s.decl != NULL && map.find(s.id) == map.end()) || s.defn != NULL) map[s.id] = s; } }
void Semantic::traverse(Exp * cur) { if (cur->v == Exp::ICONST_T || cur->v == Exp::STRLIT_T || cur->v == Exp::CHRLIT_T || cur->v == Exp::BOLLIT_T || cur->v == Exp::NULL_T) { //we're dealing with a constant here, ensure int constant in 0 2^31 if (cur->v == Exp::ICONST_T) if (cur->id.length() == std::string("2147483647").length() && cur->id > "2147483647") error("integer literal constants must be < 2^31"); } else if (cur->v == Exp::ID_T) { //variable getSym(cur->id); } else if (cur->v == Exp::UNOP_T) { //ensure subexp type is char or int Type l = expType(cur->l); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("unop must be applied to expression of type int or char"); traverse(cur->l); } else if (cur->v == Exp::BINOP_T) { //if <=, <, >, >= ensure int or char //if != or == ensure int bool char t[] or t* Type l = expType(cur->l), r = expType(cur->r); if (cur->id == "==" || cur->id == "!="); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("binop must be applied to expression of type int or char or bool"); else if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("binop must be applied to expression of type int or char or bool"); traverse(cur->l); traverse(cur->r); } else if (cur->v == Exp::IFLINE_T) { Type l = expType(cur->l); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("Condition must be of type bool"); traverse(cur->l); traverse(cur->m); traverse(cur->r); } else if (cur->v == Exp::FCALL_T) { if (cur->id == "print" || cur->id == "read_int") return; Symbol func = getSym(cur->id); if (func.decl == NULL && func.defn == NULL) { error("call to undeclared function " + cur->id); return; } ArgItem * ptr = (func.decl != NULL) ? func.decl->list : func.defn->args; ExpItem * old = cur->args; while (ptr != NULL) { if (old == NULL) { error("bad argument passed to function " + cur->id); break; } if (!sameType(*(ptr->arg->type), expType(old->exp))) { error("bad argument passed to function " + cur->id); break; } traverse(old->exp); ptr = ptr->next; old = old->next; } if (old != NULL) error("bad argument passed to function " + cur->id); } else if (cur->v == Exp::DOT_T) { //see if type has that field Type t = expType(cur->l); if (t.v != Type::STRUCT_T) error("accessing field in a non-struct type"); Symbol s = getFromMap(sid, t.str); bool hasField = false; ArgItem * ptr = s.defn->args; while (ptr != NULL) { if (ptr->arg->ID == cur->id) { hasField = true; break; } ptr = ptr->next; } if (!hasField) error("accessing non existing struct field " + cur->id); } else if (cur->v == Exp::ACC_T) { //see if type has that field Type t = expType(cur->l); if (t.v != Type::POINTER_T || t.type->v != Type::STRUCT_T) error("referencing field in a pointer to struct type"); Symbol s = getFromMap(sid, t.type->str); bool hasField = false; ArgItem * ptr = s.defn->args; while (ptr != NULL) { if (ptr->arg->ID == cur->id) { hasField = true; break; } ptr = ptr->next; } if (!hasField) error("referencing non existing struct field " + cur->id); } else if (cur->v == Exp::SUBSC_T) { //see if subst is char or int and other type is vector Type l = expType(cur->l); Type r = expType(cur->r); if (l.v != Type::VECTOR_T) error("accessing index in non-vector type"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("index type must be int or char"); traverse(cur->l); traverse(cur->r); } else if (cur->v == Exp::ALLOC_T) { //return the little thing allocated in memory (heap?) if (cur->t->v != Type::STRUCT_T) error("cannot alloc non-struct type"); } else if (cur->v == Exp::ALLOCARRAY_T) { //return the little thing[] allocated in memory (heap?) Type r = expType(cur->l); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("alloc_array size must be type int"); traverse(cur->l); } }
void Semantic::traverse(Stmt * cur) { if (cur->v == Stmt::LIST_T) { pushScope(); traverse(cur->list); popScope(); } else if (cur->v == Stmt::IF_T || cur->v == Stmt::WHILE_T) { if (cur->v == Stmt::WHILE_T) loops.push(cur); Type t = expType(cur->exp); traverse(cur->exp); if (t.v == Type::INT_T || t.v == Type::CHAR_T) { //warning pushScope(); traverse(cur->left); popScope(); } else if (t.v == Type::BOOL_T) { pushScope(); traverse(cur->left); popScope(); } else error("Condition must be of type bool"); if (cur->v == Stmt::WHILE_T) loops.pop(); } else if (cur->v == Stmt::FOR_T) { loops.push(cur); pushScope(); traverse(cur->left); Type t = expType(cur->exp); traverse(cur->exp); if (t.v == Type::INT_T || t.v == Type::CHAR_T) { //warning pushScope(); traverse(cur->stmt); popScope(); } else if (t.v == Type::BOOL_T) { pushScope(); traverse(cur->stmt); popScope(); } else error("Condition must be of type bool"); if (hasDecl(cur->right)) error("For loop-end statement must not include declarations"); traverse(cur->right); popScope(); loops.pop(); } else if (cur->v == Stmt::RETURN_T) { //check current function return type and compare it with this if (!sameType(expType(cur->exp), *getSym(curF).defn->type)) error("return expression type differs from function " + curF + " signature"); if (cur->exp != NULL) traverse(cur->exp); } else if (cur->v == Stmt::ASSERT_T) { //check argument type to be of bool if (!sameType(expType(cur->exp), Type(Type::BOOL_T))) error("assert expression type must be bool"); traverse(cur->exp); } else if (cur->v == Stmt::ERROR_T) { //call error function with argment string if (!sameType(expType(cur->exp), Type(Type::STRING_T))) error("error argument must be of type string"); traverse(cur->exp); } else if (cur->v == Stmt::ASSIGN_T) { //check if lhs and rhs same type, ensure rhs and lhs is not a struct Type l = lvalType(cur->lval), r = expType(cur->exp); traverse(cur->exp); if (cur->op == "=") { if (!sameType(l, r)) error("lval and expression have different types"); } else if (cur->op == ">>=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from right shift must be of type int or char"); if (!sameType(r, Type(Type::INT_T))) error("shift ammount must be of type int"); } else if (cur->op == "<<=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from left shift must be of type int or char"); if (!sameType(r, Type(Type::INT_T))) error("shift ammount must be of type int"); } else if (cur->op == "+=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from add assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from add assign must be of type int or char"); } else if (cur->op == "-=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from sub assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from sub assign must be of type int or char"); } else if (cur->op == "*=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from mul assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from mul assign must be of type int or char"); } else if (cur->op == "/=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from div assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from div assign must be of type int or char"); } else if (cur->op == "%=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from mod assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from mod assign must be of type int or char"); } else if (cur->op == "&=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from and assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from and assign must be of type int or char or bool"); } else if (cur->op == "^=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from xor assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from xor assign must be of type int or char or bool"); } else if (cur->op == "|=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from or assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from or assign must be of type int or char or bool"); } } else if (cur->v == Stmt::INC_T) { //check if lhs is int or char Type l = lvalType(cur->lval); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from increment must be of type int or char"); } else if (cur->v == Stmt::DEC_T) { //check if lhs is int or char Type l = lvalType(cur->lval); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from decrement must be of type int or char"); } else if (cur->v == Stmt::EXP_T) { traverse(cur->exp); } else if (cur->v == Stmt::DECL_T) { //declaring a variable newSym(vid.back(), Symbol(cur->arg->ID, cur->arg->type)); } else if (cur->v == Stmt::DECLI_T) { //declaring and assigning a variable newSym(vid.back(), Symbol(cur->arg->ID, cur->arg->type)); } else if (cur->v == Stmt::BREAK_T) { //check most recent loop if (loops.empty()) error("break statement does not have a loop"); } else if (cur->v == Stmt::CONT_T) { if (loops.empty()) error("continue statement does not have a loop"); } }