void Visit(const Waypoint &wp) { if (compare_type(wp, type_index) && (filter_data.distance_index == 0 || compare_name(wp, name)) && compare_direction(wp, direction_index, location, heading)) vector.push_back(wp, location); }
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
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]); } } }
static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) { return compare_type(lhs.token, rhs.token); }