Type TypeCheck_::check_binop( AST_Expression l , AST_Expression r , BinOpType op ) { Type t1 = check_expression(l); Type t2 = check_expression(r); switch (op) { case BINOPLOWER: case BINOPLOWEREQ: case BINOPGREATER: case BINOPGREATEREQ: case BINOPCOMPNE: case BINOPCOMPEQ: if (check_equal(t1,t2) and !check_equal(t1 , T("Boolean")) ) return T("Boolean"); else throw "Type Error (0)"; case BINOPDIV: case BINOPELDIV: case BINOPMULT: case BINOPELMULT: case BINOPADD: case BINOPELADD: case BINOPSUB: case BINOPELSUB: case BINOPEXP: case BINOPELEXP: if (check_equal(t1,t2) and ( check_equal(t1 , T("Real")) or check_equal(t1 , T("Integer")) ) ) return t1; else throw "Type Error (1)" ; case BINOPAND: case BINOPOR: if (check_equal(t1,t2) and check_equal(t1 , T("Boolean")) ) return t1; throw "Type Error (2)"; } throw "Error! (TypeCheck_::check_binop)"; }
void semantic_analysis(struct tree_node * ptr) { if (!ptr) return; int i; if (ptr -> unit_name == NODE_EXTDEF) { if (ptr -> flags == FLAG_EXTDEF_VARIABLES) { struct tree_node * spec = ptr -> children[0]; struct tree_node * declist = ptr -> children[1]; push_anonymous_struct(); // handle type first: if define struct, add struct; if basic, just use it, skip if (spec -> flags == FLAG_SPECIFIER_STRUCT && spec -> children[0] -> flags == FLAG_STRUCTSPECIFIER_DEF) { symtab_add_struct(spec -> children[0]); } // whether or not spec is successfully added, just use them. while (declist -> flags == FLAG_EXTDECLIST_MORE) { symtab_add_variable(spec, declist -> children[0]); declist = declist -> children[2]; } symtab_add_variable(spec, declist -> children[0]); pop_anonymous_struct(); return; // end of EXTDEF_VARIABLES } else if (ptr -> flags == FLAG_EXTDEF_FUNCTION) { if (function_field != NULL) { semerrorpos(ERROR_OTHER, ptr->line); printf("nested function definition \'%s\' inside another function definition\'%s\'\n", ptr -> children[1] -> children[0] -> id_extra -> name, function_field -> name); return; } // register in the symbol table // all the names in parameter list struct tree_node * spec = ptr -> children[0]; struct tree_node * id = ptr -> children[1] -> children[0]; struct func_entry * f = symtab_add_function(ptr -> children[1]); if (!f) { f = search_func_entry(id -> id_extra -> name); semerrorpos(ERROR_FUNCTION_CONFLICT, ptr -> line); printf("function \'%s\' already defined at %d\n", id -> id_extra -> name, f -> defined_at); } function_field = f; // check return type: if spec is a struct definition, add that. if (spec -> flags == FLAG_SPECIFIER_STRUCT) { struct struct_entry * se = NULL; push_anonymous_struct(); se = symtab_add_struct(spec -> children[0]); f -> return_type_flag = TYPE_STRUCT; f -> return_type.struct_type = se; // return type may be NULL, checked by expression analysis pop_anonymous_struct(); } else { assert(spec -> flags == FLAG_SPECIFIER_BASIC); f -> return_type_flag = TYPE_BASIC; f -> return_type.basic_type = spec -> children[0] -> type_name; } // recursive analyze the definitions and statements in the compst struct tree_node * deflist = ptr -> children[2] -> children[1]; while (deflist -> flags == FLAG_DEFLIST_MORE) { semantic_analysis(deflist -> children[0]); deflist = deflist -> children[1]; } struct tree_node * stmtlist = ptr -> children[2] -> children[2]; while (stmtlist -> flags == FLAG_STMTLIST_MORE) { semantic_analysis(stmtlist -> children[0]); stmtlist = stmtlist -> children[1]; } function_field = NULL; // end of EXTDEF_FUNCTION } else if (ptr -> flags == FLAG_EXTDEF_TYPE) { if (ptr -> children[0] -> flags == FLAG_SPECIFIER_BASIC) return; else if (ptr -> children[0] -> flags == FLAG_SPECIFIER_STRUCT) symtab_add_struct(ptr -> children[0] -> children[0]); else assert(0); } else { assert(0); } } else if (ptr -> unit_name == NODE_EXP) { check_expression(ptr); } else if (ptr -> unit_name == NODE_DEF) { struct tree_node * spec = ptr -> children[0]; struct tree_node * declist = ptr -> children[1]; while (declist -> flags == FLAG_DECLIST_MORE) { symtab_add_variable(spec, declist -> children[0] -> children[0]); if (declist -> children[0] -> flags == FLAG_DEC_INITIALIZED) { check_expression(declist -> children[0] -> children[2]); } declist = declist -> children[2]; } symtab_add_variable(spec, declist -> children[0] -> children[0]); if (declist -> children[0] -> flags == FLAG_DEC_INITIALIZED) { check_expression(declist -> children[0] -> children[2]); } } else if (ptr -> unit_name == NODE_STMT) { if (ptr -> flags == FLAG_STMT_EXP) { check_expression(ptr -> children[0]); } else if (ptr -> flags == FLAG_STMT_COMPST) { struct tree_node * deflist = ptr -> children[0] -> children[1]; while (deflist -> flags == FLAG_DEFLIST_MORE) { semantic_analysis(deflist -> children[0]); deflist = deflist -> children[1]; } struct tree_node * stmtlist = ptr -> children[0] -> children[2]; while (stmtlist -> flags == FLAG_STMTLIST_MORE) { semantic_analysis(stmtlist -> children[0]); stmtlist = stmtlist -> children[1]; } } else if (ptr -> flags == FLAG_STMT_IF) { check_expression(ptr -> children[2]); if (ptr -> children[2] -> exp_type_flag != TYPE_BASIC || ptr -> children[2] -> exp_type.basic_type != TYPE_INT) { semerrorpos(ERROR_OTHER, ptr -> line); printf("non-integer in condition expression\n"); } semantic_analysis(ptr -> children[4]); } else if (ptr -> flags == FLAG_STMT_IFELSE) { check_expression(ptr -> children[2]); if (ptr -> children[2] -> exp_type_flag != TYPE_BASIC || ptr -> children[2] -> exp_type.basic_type != TYPE_INT) { semerrorpos(ERROR_OTHER, ptr -> line); printf("non-integer in condition expression\n"); } semantic_analysis(ptr -> children[4]); semantic_analysis(ptr -> children[6]); } else if (ptr -> flags == FLAG_STMT_WHILE) { check_expression(ptr -> children[2]); if (ptr -> children[2] -> exp_type_flag != TYPE_BASIC || ptr -> children[2] -> exp_type.basic_type != TYPE_INT) { semerrorpos(ERROR_OTHER, ptr -> line); printf("non-integer in condition expression\n"); } semantic_analysis(ptr -> children[4]); } else if (ptr -> flags == FLAG_STMT_RETURN) { // done check_expression(ptr -> children[1]); if (function_field == NULL) { semerrorpos(ERROR_OTHER, ptr -> line); printf("no corresponding block to return operation\n"); return; } int c = compare_type(ptr -> children[1] -> exp_type_flag, &(ptr -> children[1] -> exp_type), function_field -> return_type_flag, &(function_field -> return_type)); if (c == COMPARE_GOOD) { // good } else { semerrorpos(ERROR_RETURN_MISMATCH, ptr -> line); printf("return type error: %s\n", compare_str[c]); } // end of return } else { assert(0); } } else { for (i = 0; i < ptr -> num_of_children; ++i) { assert(ptr -> children[i]); semantic_analysis(ptr -> children[i]); } } }
int check_expression(struct tree_node * exp) { assert(exp -> unit_name == NODE_EXP); if (exp -> flags == FLAG_EXP_ID) { // terminal const char * id_name = exp -> children[0] -> id_extra -> name; struct var_entry * ve = search_var_entry(id_name); if (ve == NULL) { semerrorpos(ERROR_VARIABLE_UNDEFINED, exp -> children[0] -> line); printf("identifier \'%s\' not exist\n", id_name); } else { // check the ve's type and its flags exp -> exp_type_flag = ve -> type_flag; exp -> exp_type = ve -> t; exp -> exp_is_lvalue = 1; } } else if (exp -> flags == FLAG_EXP_INT) { // terminal assert(exp -> children[0] -> unit_name == TOKEN_INTEGER); exp -> exp_type_flag = TYPE_BASIC; exp -> exp_type.basic_type = TYPE_INT; exp -> exp_is_lvalue = 0; } else if (exp -> flags == FLAG_EXP_FLOAT) { // terminal assert(exp -> children[0] -> unit_name == TOKEN_FLOAT); exp -> exp_type_flag = TYPE_BASIC; exp -> exp_type.basic_type = TYPE_FLOAT; exp -> exp_is_lvalue = 0; } else if (exp -> flags == FLAG_EXP_ASSIGN) { // NON-terminal // TODO: check left-value, then check type confliction check_expression(exp -> children[0]); check_expression(exp -> children[2]); if (exp -> children[0] -> exp_is_lvalue == 0) { semerrorpos(ERROR_ASSIGN_NONLEFT, exp -> children[0] -> line); printf("expression on the left side is not left-value\n"); } exp -> exp_is_lvalue = exp -> children[2] -> exp_is_lvalue; // whether or not the left side is left-value or not, better to check type first. int c = compare_type( exp -> children[0] -> exp_type_flag, &(exp -> children[0] -> exp_type), exp -> children[2] -> exp_type_flag, &(exp -> children[2] -> exp_type)); if (c != COMPARE_GOOD) { semerrorpos(ERROR_ASSIGN_MISMATCH, exp -> children[1] -> line); printf("type mismatch in assignment: %s\n", compare_str[c]); } else { exp -> exp_type_flag = exp -> children[0] -> exp_type_flag; exp -> exp_type = exp -> children[0] -> exp_type; } // end of assignment } else if (exp -> flags == FLAG_EXP_BINOP) { // NON-terminal check_expression(exp -> children[0]); check_expression(exp -> children[2]); // prune: non-basic types cannot take binary operations whatsoever if (exp -> children[0] -> exp_type_flag == TYPE_ARRAY || exp -> children[0] -> exp_type_flag == TYPE_STRUCT) { semerrorpos(ERROR_OTHER, exp -> children[1] -> line); printf("%s (on the left side) cannot take binary operation\n", type_str[exp -> children[0] -> exp_type_flag]); exp -> exp_type_flag = exp -> children[0] -> exp_type_flag; return -1; } if (exp -> children[2] -> exp_type_flag == TYPE_ARRAY || exp -> children[2] -> exp_type_flag == TYPE_STRUCT) { semerrorpos(ERROR_OTHER, exp -> children[1] -> line); printf("%s (on the right side) cannot take binary operation\n", type_str[exp -> children[2] -> exp_type_flag]); exp -> exp_type_flag = exp -> children[2] -> exp_type_flag; return -1; } // now they are both basic types. exp -> exp_type_flag = TYPE_BASIC; exp -> exp_type.basic_type = exp -> children[0] -> exp_type.basic_type; if (exp -> children[1] -> unit_name == TOKEN_RELOP) exp -> exp_type.basic_type = TYPE_INT; exp -> exp_is_lvalue = 0; int type_left = exp -> children[0] -> exp_type.basic_type; int type_right = exp -> children[2] -> exp_type.basic_type; // assert(type_left == TYPE_INT || type_left == TYPE_FLOAT); // assert(type_right == TYPE_INT || type_right == TYPE_FLOAT); if (type_left == type_right) { // printf("types: %d, %d\n", type_left, type_right); } else { semerrorpos(ERROR_OPERAND_MISMATCH, exp->children[1] -> line); printf("expression type not match: %d and %d\n", type_left, type_right); } // end of binary operators: + - * / && || relop } else if (exp -> flags == FLAG_EXP_PAREN) { // NON-terminal check_expression(exp -> children[1]); exp -> exp_type_flag = exp -> children[1] -> exp_type_flag; exp -> exp_type = exp -> children[1] -> exp_type; exp -> exp_is_lvalue = exp -> children[1] -> exp_is_lvalue; // end of parentheses } else if (exp -> flags == FLAG_EXP_UNOP) { // NON-terminal check_expression(exp -> children[1]); if (exp -> exp_type_flag == TYPE_ARRAY || exp -> exp_type_flag == TYPE_STRUCT) { semerrorpos(ERROR_OTHER, exp -> line); printf("%s cannot take unary operator\n", type_str[exp -> exp_type_flag]); } exp -> exp_is_lvalue = 0; exp -> exp_type_flag = exp -> children[1] -> exp_type_flag; exp -> exp_type = exp -> children[1] -> exp_type; // end of unary operator } else if (exp -> flags == FLAG_EXP_CALL_ARGS) { // NON-self-recursive // DONE: check arguments const char * f_name = exp -> children[0] -> id_extra -> name; struct func_entry * f = search_func_entry(f_name); struct tree_node * arguments = exp -> children[2]; struct list_head * parameters_head = NULL; if (f == NULL) { semerrorpos(ERROR_FUNCTION_UNDEFINED, exp -> children[0] -> line); printf("function \'%s\' not defined\n", f_name); exp -> exp_type_flag = TYPE_ERROR; return -1; } else { // checking parameters_head parameters_head = &(f -> param_list); struct list_head * param_l = NULL; struct var_entry * param_ve = NULL; /*for loop*/list_for_each(param_l, parameters_head) { struct tree_node * a = arguments -> children[0]; param_ve = list_entry(param_l, struct param_entry, list_ptr) -> param_ptr; check_expression(a); int c = compare_type(param_ve -> type_flag, &(param_ve -> t), a -> exp_type_flag, &(a -> exp_type)); if (c != COMPARE_GOOD) { semerrorpos(ERROR_PARAM_MISMATCH, a -> line); printf("argument and parameter type mismatch: %s\n", compare_str[c]); } if (arguments -> flags == FLAG_ARGS_SINGLE) { // param_ve should be the last parameter if (param_l -> next != parameters_head) { semerrorpos(ERROR_PARAM_MISMATCH, a -> line); printf("more params not matched\n"); } break; } else { assert(arguments -> flags == FLAG_ARGS_MORE); // but if parameters has reached its end... if (param_l -> next == parameters_head) { semerrorpos(ERROR_PARAM_MISMATCH, a -> line); printf("more arguments not matched\n"); break; } } arguments = arguments -> children[2]; } } while (arguments -> flags == FLAG_ARGS_MORE) { check_expression(arguments -> children[0]); arguments = arguments -> children[2]; } exp -> exp_type_flag = f -> return_type_flag; exp -> exp_type = f -> return_type; // end of function calling with args } else if (exp -> flags == FLAG_EXP_CALL_NOARGS) { // NON-self-recursive
Type TypeCheck_::check_expression(AST_Expression e) { Type ct,t1,t2,t; switch (e->expressionType()) { case EXPBINOP: { AST_Expression_BinOp b = e->getAsBinOp(); return check_binop(b->left() , b->right() , b->binopType()); } case EXPUMINUS: { AST_Expression_UMinus b = e->getAsUMinus(); t = check_expression(b->exp()); if ( check_equal(t , T("Integer")) or check_equal(t , T("Real")) ) return t; throw "Type Error (3)"; } case EXPOUTPUT : { AST_Expression_Output b = e->getAsOutput(); return check_expression(b->expressionList()->front() ); } case EXPIF: { AST_Expression_If b = e->getAsIf(); ct = check_expression(b->condition() ); t1 = check_expression(b->then() ); t2 = check_expression(b->else_exp()); // Falta el elseIF if ( !check_equal(ct, T("Boolean")) ) throw "Type Error (4)"; if ( !check_equal(t1,t2) ) throw "Type Error (5)"; return t1; } case EXPCALL: { // Añadir las funciones en la listaaaa de variables AST_Expression_Call c = e->getAsCall(); if ( toStr(c->name()) == "sample" ) return T("Boolean"); if ( toStr(c->name()) == "pre" ) return check_expression(c->arguments()->front()); return T("Real"); } case EXPCOMPREF: { AST_Expression_ComponentReference b = e->getAsComponentReference(); VarInfo tt = varEnv->lookup( toStr(b->names()->front()) ); if (tt == NULL) { cerr << "Var:" << b->names()->front() << ":"; throw "Variable no existe (8)"; } if (b->indexes()->front()->size() == 0) return tt->type(); else { Type t = tt->type(); AST_ExpressionListIterator exit; foreach(exit , b->indexes()->front() ) if (t->getType() == TYARRAY) t = t->getAsArray()->arrayOf(); else throw "Type Error (7)"; return t; } break; } case EXPDERIVATIVE: return T("Real"); case EXPBOOLEAN: return T("Boolean"); case EXPSTRING: return T("String"); case EXPREAL: return T("Real"); case EXPINTEGER: return T("Integer"); case EXPBOOLEANNOT: { AST_Expression_BooleanNot b = e->getAsBooleanNot(); t = check_expression(b->exp()); if ( !check_equal(t, T("Boolean")) ) throw "Type Error (6)"; return t; } default: throw "No implrementado aun! (check_expression)"; } }
int main_i(const std::vector<std::string> &argv) { int argc = argv.size(); if (argc == 1 || (argc == 2 && argv[1] == "-h")) { std:: cout << "Picosel ver. 1.5 (C) 2009-2010 AIST" "\n" "Usage 1: picosel OPTION from inputfile select column where EXPRESSION" "\n" "Usage 2: picosel OPTION from inputfile select column order by column" "\n" "Option" "\n" " -o outputfile: specify output file." "\n"; return 0; } if (argc == 3 && argv[1] == "--text") { return convert_binary_file_to_text(argv[2]); } int r = analyze_commandline(argv); if (r != 0) { return r; } std:: ifstream input; input.open(fromFile.c_str(), std:: ios::in | std:: ios::binary); if (! input.is_open()) { std:: cerr << "error: can not open file '" << fromFile << "'" << std:: endl; return 1; } std:: istream *pInput = &input; r = get_column_names(pInput); if (r != 0) { return r; } int selectColIndex = findNamedColumn(selectCol); if (selectColIndex == -1) { std:: cerr << "error: unknown column name '" << selectCol << "'" << std:: endl; return 1; } r = check_expression(); if (r != 0) { return r; } std:: ostream *pOutput = &std:: cout; std:: ofstream output; if (! outputFile.empty()) { output.open(outputFile.c_str(), binaryOutputFactor != 0 ? (std:: ios::out | std:: ios::binary) : std:: ios::out); if (! output.is_open()) { std:: cerr << "error: can not create file '" << outputFile << "'" << std:: endl; return 1; } pOutput = &output; } if (! orderByAsc.empty()) { int orderColIndex = findNamedColumn(orderByAsc); if (orderColIndex == -1) { std:: cerr << "error: unknown column name '" << orderByAsc << "'" << std:: endl; return 1; } r = do_sorting(pInput, pOutput, selectColIndex, orderColIndex, 1/* asc */, outputFile); } else if (! orderByDesc.empty()) { int orderColIndex = findNamedColumn(orderByDesc); if (orderColIndex == -1) { std:: cerr << "error: unknown column name '" << orderByDesc << "'" << std:: endl; return 1; } r = do_sorting(pInput, pOutput, selectColIndex, orderColIndex, -1/* desc */, outputFile); } else { r = do_selecting(pInput, pOutput, selectColIndex); } output.close(); input.close(); return r; }