bool type_equal(const struct type *t1, const struct type *t2) { if (t1 == t2) return true; if (t1->type != t2->type) { if (t1 == type_generic || t2 == type_generic) return true; return false; } if (t1->type == TYPE_FUNCTION) { if (!type_equal(t1->function_type.return_value, t2->function_type.return_value)) return false; struct list *l1 = t1->function_type.argv; struct list *l2 = t2->function_type.argv; unsigned int s; if ((s = list_size(l1)) != list_size(l2)) return false; for (unsigned int i = 1; i <= s; ++i) { const struct type *s1 = ((struct symbol*)list_get(l1,i))->type; const struct type *s2 = ((struct symbol*)list_get(l2,i))->type; if (!type_equal(s1, s2)) return false; } } if (t1->type == TYPE_ARRAY) { if (!type_equal(t1->array_type.values, t2->array_type.values)) return false; } return true; }
/******************** class compexpr -- A < B, etc. ********************/ compexpr::compexpr(int op, expr *left, expr *right) :binaryexpr(booltype, op, left, right) { Error.CondError( !type_equal( left->gettype(), inttype), "Arguments of <, <=, >, >= must be integral."); Error.CondError( !type_equal( right->gettype(), inttype), "Arguments of <, <=, >, >= must be integral."); if ( constval ) { switch (op) { case '<': value = left->getvalue() < right->getvalue(); break; case LEQ: value = left->getvalue() <= right->getvalue(); break; case '>': value = left->getvalue() > right->getvalue(); break; case GEQ: value = left->getvalue() >= right->getvalue(); break; default: Error.Error("Internal: surprising value for op in compexpr::compexpr."); break; } } }
simplerule::simplerule(ste * enclosures, expr * condition, ste * locals, stmt * body, int priority) :rule(), name(name), enclosures(enclosures), condition(condition), locals(locals), body(body), condname(NULL), rulename(NULL), priority(priority) { if (condition != NULL && body != NULL) { Error.CondError(condition->has_side_effects(), "Rule Condition must not have side effects."); if (args->pmurphik) { Error.CondError(!type_equal(condition->gettype(), realtype), "Condition for probabilistic rule must be a real expression."); if (condition->hasvalue() && ((condition->getrvalue() < 0) || (condition->getrvalue() > 1))) Error.Error("Real condition for rule must be >=0 and <=1."); } else Error.CondError(!type_equal(condition->gettype(), booltype), "Condition for rule must be a boolean expression."); } NextSimpleRule = SimpleRuleList; SimpleRuleList = this; size = CountSize(enclosures); // Rearrange enclosures so that the ones that are NOT // mentioned in the condition go first rearrange_enclosures(); }
/******************** class boolexpr -- a binary expression of two boolean arguments. ********************/ boolexpr::boolexpr(int op, expr *left, expr *right) :binaryexpr(booltype, op, left, right) { Error.CondError( !type_equal( left->gettype(), booltype), "Arguments of &, |, -> must be boolean."); Error.CondError( !type_equal( right->gettype(), booltype), "Arguments of &, |, -> must be boolean."); Error.CondWarning(sideeffects, "Expressions with side effects may behave oddly in some boolean expressions."); if ( constval ) { switch(op) { case IMPLIES: value = !(left->getvalue() ) || (right->getvalue()); break; case '&': value = left->getvalue() && right->getvalue(); break; case '|': value = left->getvalue() || right->getvalue(); break; default: Error.Error("Internal: surprising value for op in boolexpr::boolexpr"); } } }
bool type_equal(Type x, Type y) { //判断类型是否匹配 if(x->kind == BASIC && y->kind == BASIC) { if(x->u.basic == y->u.basic) { return true; } } else if (x->kind == ARRAY && y->kind == ARRAY) { if (type_equal(x->u.array.elem, y->u.array.elem)) return true; } else if (x->kind == STRUCTURE && y->kind == STRUCTURE) { varElement *p = x->u.var; varElement *q = x->u.var; while (p != NULL) { if (q == NULL) return false; else if (strcmp(p->name, q->name)!=0) return false; else if (!type_equal(p->type, q->type)) return false; else p = p->next; q = q->next; } if (q != NULL) return false; return true; } return false; }
/* type_equal -- test two types for equality */ PUBLIC bool type_equal(type t1, frame f1, type t2, frame f2) { unpack(&t1, &f1, FALSE); unpack(&t2, &f2, FALSE); if (t1 == t2 && f1 == f2) return TRUE; else if (t1->t_kind != t2->t_kind) return FALSE; else { switch (t1->t_kind) { case GIVENT: return (t1->t_given == t2->t_given); case TYPEVAR: return (t1->t_typevar == t2->t_typevar); case POWERT: return (type_equal(t1->t_base, f1, t2->t_base, f2)); case CPRODUCT: if (t1->t_nfields != t2->t_nfields) return FALSE; else { int i; for (i = 0; i < t1->t_nfields; i++) if (! type_equal(t1->t_field[i], f1, t2->t_field[i], f2)) return FALSE; return TRUE; } case SPRODUCT: { schema s1 = t1->t_schema, s2 = t2->t_schema; int i; if (s1->z_ncomps != s2->z_ncomps) return FALSE; for (i = 0; i < s1->z_ncomps; i++) if (s1->z_comp[i].z_name != s2->z_comp[i].z_name || ! type_equal(s1->z_comp[i].z_type, f1, s2->z_comp[i].z_type, f2)) return FALSE; return TRUE; } case ABBREV: if (t1->t_def != t2->t_def) return FALSE; else { int i; for (i = 0; i < t1->t_def->d_nparams; i++) if (! type_equal(t1->t_params->f_var[i], f1, t2->t_params->f_var[i], f2)) return FALSE; return TRUE; } default: bad_tag("type_equal", t1->t_kind); return FALSE; } } }
quantdecl::quantdecl(expr * left, expr * right, int by) :decl(), type(inttype), left(left), right(right), by(by), byR(by) { Error.CondError(!type_equal(left->gettype(), inttype) && !type_equal(left->gettype(), realtype), "Bounds of <expr> TO <expr> must be either integers or reals."); Error.CondError(!type_equal(right->gettype(), inttype) && !type_equal(left->gettype(), realtype), "Bounds of <expr> TO <expr> must be either integers or reals."); }
/******************** class condexpr -- a ?: expression. We need to have a subclass for this -- for the extra arg. ********************/ condexpr::condexpr( expr *test, expr *left, expr *right) :expr(left->gettype(), FALSE, test->has_side_effects() || left->has_side_effects() || right->has_side_effects()), test(test), left(left), right(right) { Error.CondError( !type_equal( test->gettype(), booltype), "First argument of ?: must be boolean."); Error.CondError( !type_equal( left->gettype(), right->gettype() ), "Second and third arguments of ?: must have same type."); }
/* theta_type -- compute type of a theta-exp or theta-select */ PRIVATE type theta_type(tree t, env e, type a, tree cxt) { def d = get_schema((tok) t->x_the_name, t->x_loc); schema s; env e1 = new_env(e); type b; int i; if (d == NULL) return err_type; s = d->d_schema; check_rename(s, (tok) t->x_the_decor, t->x_the_rename, t); for (i = 0; i < s->z_ncomps; i++) { sym x = s->z_comp[i].z_name; sym xp = get_rename(x, (tok) t->x_the_decor, t->x_the_rename); type tt = (a == NULL ? ref_type(xp, nil, e, t) : comp_type(a, xp, cxt, t->x_loc)); add_def(VAR, x, tt, e1); } b = mk_sproduct(mk_schema(e1)); if (! aflag && d->d_abbrev && d->d_nparams == 0 && type_equal(b, arid, mk_sproduct(s), arid)) return mk_abbrev(d, arid); else return b; }
simplerule::simplerule(ste *enclosures, expr *condition, ste *locals, stmt *body, bool unfair, int priority) :rule(), name( name ), enclosures(enclosures), condition(condition), locals(locals), body(body), condname(NULL), rulename(NULL), unfair(unfair), priority(priority) { if ( condition != NULL && body != NULL ) { Error.CondError(condition->has_side_effects(), "Rule Condition must not have side effects."); Error.CondError(!type_equal(condition->gettype(), booltype), "Condition for rule must be a boolean expression."); } NextSimpleRule = SimpleRuleList; SimpleRuleList = this; size = CountSize(enclosures); // Rearrange enclosures so that the ones that are NOT // mentioned in the condition go first rearrange_enclosures(); }
/*Controlla i vincoli semantici dell'assegnamento e ne ritorna il codice*/ Code assign_stat(Pnode assign_stat_node){ #ifdef DEBUG_ASSIGN_STAT printf("ASSIGN_STAT - enter\n"); #endif //Imposto le due parti del nodo Pnode id_node = assign_stat_node->child; Pnode expr_node = assign_stat_node->child->brother; //Definisco la variabile che contiene il codice da ritornare Code assign_stat_code ; //Controllo i vincoli semantici //Visibilità del nome if (lookup(valname(id_node))==NULL) semerror(id_node,"Undefined variable"); //Compatibilità degli schemi Pschema schema_expr = (Pschema) newmem(sizeof(Schema)); Code expr_code = expr(expr_node,schema_expr); Psymbol symbol = lookup(valname(id_node)); if (!type_equal((symbol->schema),*(schema_expr))) semerror(assign_stat_node,"Incompatible types"); //Genero il codice assign_stat_code = appcode(expr_code,makecode1(T_STO,symbol->oid)); #ifdef DEBUG_ASSIGN_STAT printf("ASSIGN_STAT - exit\n"); #endif return assign_stat_code; }
/******************** class scalarsettypedecl ********************/ scalarsettypedecl::scalarsettypedecl(expr * l, int lb) :typedecl(), named(FALSE), lexname(NULL), useless(TRUE) { if (Error.CondError(!type_equal(l->gettype(), inttype), "Only scalarsets of integer size allowed.") || Error.CondError(!l->hasvalue(), "Scalarset size must be constants.") ) { left = lb; right = lb; numbits = 1; if (!args->no_compression) { bitsalloc = numbits; } else { bitsalloc = BYTES(numbits); if (left < 0 || right > 254 || numbits > 8) bitsalloc = 32; } mu_type = (left < 0 || right > 254 || numbits > 8 ? "mu__long" : "mu__byte"); idvalues = symtab->declare(new lexid(tsprintf("scalarset_%u_v_error", scalarset_type_int++), 0), new constdecl(lb++, this)); // it is not set as scalarset variable because it is of size 1. // structure = typedecl::ScalarsetVariable; scalarsetlist = NULL; // to be set when declaring ID : typeExpr } else { // setting size, numbits, left and right // const 0 is used for undefined value --> 0. lb, ... . ub int size = l->getvalue(); if (size < 1) Error.Error("Scalarset size must be greater than zero."); numbits = CeilLog2(l->getvalue() + 1); left = lb; right = left + size - 1; if (!args->no_compression) { bitsalloc = numbits; } else { if (numbits > 31) Error.Error("Internal error, range is too large"); bitsalloc = BYTES(numbits); if (left < 0 || right > 254 || numbits > 8) bitsalloc = 32; } mu_type = (left < 0 || right > 254 || numbits > 8 ? "mu__long" : "mu__byte"); // set id strings // name may be changed if it is later explicitly given a type name int value = left; for (int i = 1; i <= size; i++) { symtab->declare(new lexid(tsprintf("scalarset_%u_v%u", scalarset_type_int, i), 0), new constdecl(value++, this)); } idvalues = symtab->getscope(); if (size > 1) // scalarset of size 1 is treated as normal enum structure = typedecl::ScalarsetVariable; scalarsetlist = NULL; // to be set when declaring ID : typeExpr } }
Code assign_stat(Pnode p) { Psymbol symbol; Code exprcode; Schema exprschema; /* assign_stat / / ID ---> expr */ // Semantica: Carico gli schemi di ID e expr symbol = lookup(valname(p->child)); if (symbol == NULL) semerror(p->child, "Undefined identifier in assignment"); exprcode = expr(p->child->brother, &exprschema); // Type checking: if (!type_equal(symbol->schema, &exprschema)) semerror(p->child->brother, "Incompatible types in assignment"); if (exprschema.next != NULL) free_schema(exprschema.next); Value v1; v1.ival = symbol->oid; return concode( exprcode, makecode1(T_STO, v1), endcode()); }
Code tuple_const(Pnode p, Pschema s) { Pschema schema; // Scorro tutti gli elementi della tupla Code result = endcode(); Pnode elem; for (elem = p->child; elem != NULL; elem = elem->brother) { Code elemcode; switch (elem->type) { case N_INTCONST: case N_BOOLCONST: elemcode = makecode1(T_IATTR, elem->value); break; case N_STRCONST: elemcode = makecode1(T_SATTR, elem->value); break; default: noderror(elem); } if (result.head == NULL) result = elemcode; else result = appcode(result, elemcode); } // Type checking schema = tuple_to_schema(p); if (!type_equal(schema, s)) semerror(p, "Incompatible tuples in table constant"); free_schema(schema); return result; }
varElement* doDef(TreeNode *p, int ifStruct) { //printf("doDef\n"); //printf("TreeNode->state:%s\n", p->state); //将doDecList()返回的变量链表赋为doSpecifier()返回的Type,插入变量表 TreeNode *p1 = p->firstChild; TreeNode *p2 = p1->rightBrother; Type type = doSpecifier(p1); //printf("doDef begin doDecList\n"); varElement *elem = doDecList(p2); varElement *elemHead = elem; varElement *elemn = NULL; //判断初始化时类型是否匹配 //printf("type:%d\n", type->u.basic); // printf("elem:%d\n", elem->type->u.basic); if(elem->initType != NULL) { //initType不为空,说明声明的同时初始化,需要判断类型是否匹配 if (ifStruct == 1) { printf("Error type 15 at line %d: struct member initialization is denied\n", p->line); } else if(!type_equal(type, elem->initType)) { printf("Error type 7 at line %d:'=' type mismatch\n", p->line); } } //printf("z\n"); while(elem != NULL) { //printf("z2\n"); Type t = elem->type; if (t->kind != BASIC) { //printf("z3\n"); while (t->kind == ARRAY && t->u.array.elem->kind != BASIC) { //如果是数组要找到最底部的type节点赋为Specifier传回的Type //printf("in loop\n"); t = t->u.array.elem; } //printf("z4\n"); //free(t->u.array.elem); t->u.array.elem = type; //在倒数第二个节点处改变Type //printf("z5\n"); } else { //free(elem->type); elem->type = type; //printf("type in doDef %d\n", type->u.basic); } if (ifStruct != 1) { //普通变量,插入变量表 if (search(elem->name) != NULL) { //查找此层定义不为空,说明变量重复定义 printf("error type 3 at line %d: variable %s redefined.\n", p->line, elem->name); elem = elem->next; } else { elemn = elem->next; insert(elem); elem = elemn; } } else { //结构体变量,保持链表结构 elem = elem->next; } } //printf("out of doDef\n"); return elemHead; }
fairness::fairness(ste *enclosures, expr *test) :simplerule(enclosures, test, NULL, NULL, FALSE, 0) { Error.CondError(!type_equal( test->gettype(), booltype), "Fairness must be a boolean expression."); Error.CondError(test->has_side_effects(), "Fairness must not have side effects."); }
invariant::invariant(ste * enclosures, expr * test) : simplerule(enclosures, test, NULL, NULL, 0) { Error.CondError(!type_equal(test->gettype(), booltype), "Invariant must be a boolean expression."); Error.CondError(test->has_side_effects(), "Invariant must not have side effects."); }
subrangetypedecl::subrangetypedecl(expr * left, expr * right) : typedecl() { if (Error.CondError(!type_equal(left->gettype(), inttype), "Only integer subranges allowed.") || Error.CondError(!type_equal(right->gettype(), inttype), "Only integer subranges allowed.") || Error.CondError(!left->hasvalue(), "Subrange bounds must be constants.") || Error.CondError(!right->hasvalue(), "Subrange bounds must be constants.") || Error.CondError(right->getvalue() < left->getvalue(), "Upper bound of subrange less than lower bound.") ) { this->left = 0; this->right = 1; this->numbits = 1; if (!args->no_compression) { this->bitsalloc = this->numbits; } else { this->bitsalloc = BYTES(this->numbits); } this->parent = inttype; } else { this->left = left->getvalue(); this->right = right->getvalue(); // 0 is used for undefined value --> 0. lb, ... . ub this->numbits = CeilLog2(right->getvalue() - left->getvalue() + 2); if (this->numbits > 31) Error.Error("Internal error, range is too large"); if (!args->no_compression) { this->bitsalloc = this->numbits; } else { this->bitsalloc = BYTES(this->numbits); if (this->left < 0 || this->right > 254 || numbits > 8) this->bitsalloc = 32; } this->parent = left->gettype(); // more general than inttype, though not yet necessary. } mu_type = (left->getvalue() < 0 || right->getvalue() > 254 || numbits > 8 ? "mu__long" : "mu__byte"); }
/******************** class notexpr -- boolean not ********************/ notexpr::notexpr(expr *left) :unaryexpr(booltype, left) { Error.CondError( !type_equal( left->gettype(), booltype), "Arguments of ! must be boolean."); Error.CondWarning(sideeffects, "Expressions with side effects may behave oddly in some boolean expressions."); if ( constval ) value = !left->getvalue(); }
/******************** class quantexpr -- a quantified expression. ********************/ quantexpr::quantexpr(int op, ste *parameter, expr *left) :expr(booltype, FALSE, left->has_side_effects() ), parameter(parameter), op(op), left(left) { Error.CondError( !type_equal( left->gettype(), booltype), "Quantified subexpressions must be boolean."); Error.CondWarning(sideeffects, "Expressions with side effects in quantified expressions may behave oddly."); }
constdecl::constdecl(expr * e) : decl(), type(e->gettype()) { Error.CondError(!e->hasvalue(), "CONST declaration requires constant expression."); if (type_equal(e->gettype(), realtype)) rvalue = e->getrvalue(); // AP: now, a constant may be a real one else value = e->getvalue(); }
designator::designator(designator *left, expr *ar) :expr(NULL, FALSE, left->has_side_effects() || ar->has_side_effects() ), left(left), arrayref(ar), lvalue(left->lvalue), dclass(ArrayRef) { typedecl *t = left->gettype(); if (Error.CondError( t->gettypeclass() != typedecl::Array && t->gettypeclass() != typedecl::MultiSet, "Not an array/multiset type.") ) { type = errortype; } else if (t->gettypeclass() == typedecl::Array) { if (Error.CondError( !type_equal( ((arraytypedecl *)t)->getindextype(), ar->gettype() ), "Wrong index type for array reference.") ) { type = errortype; } else { type = ((arraytypedecl *) t)->getelementtype(); } } else { if (Error.CondError( !ar->isdesignator(), "B") || Error.CondError( ar->gettype()->gettypeclass() != typedecl::MultiSetID, "A") || Error.CondError( !type_equal( (multisettypedecl *) t, ((multisetidtypedecl *)ar->gettype())->getparenttype() ), "Wrong index type for MultiSet reference.") ) { type = errortype; } else { type = ((multisettypedecl *) t)->getelementtype(); } } }
/******************** class multisetcount ********************/ multisetcount::multisetcount(ste * index, designator *set, expr * filter) :expr(inttype, FALSE, FALSE), index(index), set(set), filter(filter) { Error.CondError(set->gettype()->gettypeclass() != typedecl::MultiSet, "2nd Argument of MultiSetCount must be a MultiSet."); Error.CondError( !type_equal( filter->gettype(), booltype), "3rd Argument of MultiSetCount must be boolean."); multisetcount_num = num_multisetcount; num_multisetcount++; ((multisettypedecl *) set->gettype())->addcount(this); }
/******************** bool matchparams(char *name, ste *formals, exprlist *actuals) -- matching type for the parameters ********************/ bool matchparams(char *name, ste * formals, exprlist * actuals) { bool match = TRUE; for (; formals != NULL && actuals != NULL; formals = formals->getnext(), actuals = actuals->next) { param *f = (param *) formals->getvalue(); if (!actuals->undefined) { expr *e = actuals->e; if (!type_equal(f->gettype(), e->gettype())) { if (!(type_equal(f->gettype(), realtype) && type_equal(e->gettype(), inttype))) { Error.Error("Actual parameter to %s has wrong type.", name); match = FALSE; } } if (f->getparamclass() == param::Var) { if (Error.CondError(!e->islvalue(), "Non-variable expression can't be passed to VAR parameter of %s.", name)) match = FALSE; if (Error.CondError(f->gettype() != e->gettype(), "Var parameter to %s has wrong type.", name)) match = FALSE; } } else { if (f->getparamclass() == param::Var) { Error.Error ("UNDEFINED value can't be passed to VAR parameter of %s.", name); match = FALSE; } } } if ((formals != NULL && actuals == NULL) || (actuals != NULL && formals == NULL)) { Error.Error("Wrong number of parameters to function %s.", name); match = FALSE; } return match; }
/*type compare and array compare*/ bool var_type_equal(struct var_descriptor* v1, struct var_descriptor* v2){ assert(v1 != NULL && v2 != NULL); if(!type_equal(v1 -> var_type, v2 -> var_type)) return false; if(!array_equal(v1 -> var_array, v2 -> var_array)) return false; //printf("equal\n"); return true; }
/******************** class arithexpr -- an arithmetic expression. ********************/ arithexpr::arithexpr(int op, expr *left, expr *right) :binaryexpr(inttype, op, left, right) { Error.CondError( !type_equal( left->gettype(), inttype), "Arguments of %c must be integral.", op); Error.CondError( !type_equal( right->gettype(), inttype), "Arguments of %c must be integral.", op); if ( constval ) { switch (op) { case '+': value = left->getvalue() + right->getvalue(); break; case '-': value = left->getvalue() - right->getvalue(); break; default: /* Commented out to allow for mulexprs. */ // Error.Error("Internal: surprising value for op in arithexpr::arithexpr."); break; } } }
realtypedecl::realtypedecl(expr * ac, expr * ex) : typedecl() { Error.CondError(!type_equal(ac->gettype(), inttype), "Only integer accuracy allowed."); Error.CondError(!type_equal(ex->gettype(), inttype), "Only integer exponent allowed."); Error.CondError(!ac->hasvalue(), "Accuracy must be constant."); Error.CondError(!ex->hasvalue(), "Exponent must be constant."); Error.CondError((ac->getvalue() < 1) || (ac->getvalue() > DBL_DIG), "Accuracy must be >= 1 and <= %d.", DBL_DIG); Error.CondError((ex->getvalue() < 1) || (ex->getvalue() > DBL_MAX_10_EXP), //IM: fixed, now we have directly the value "Exponent max value must be between 1 and %d.", DBL_MAX_10_EXP); this->accuracy = ac->getvalue(); this->exponent_value = ex->getvalue(); this->setexponentdigits(); //IM: sets this->exponent this->numbits = (int) ceil(this->getsize() / 2.0) * 8; this->bitsalloc = this->numbits; mu_type = "mu__real"; }
int compareArgs (argElement *arg1, argElement *arg2) { argElement *p1 = arg1; argElement *p2 = arg2; while (p1 != NULL) { //printf("p1 %d\n", p1->type->u.basic); //printf("p2 %d\n", p2->type->u.basic); if (p2 == NULL) return 0; if (!type_equal(p1->type, p2->type)) return 0; p1 = p1->next; p2 = p2->next; } if (p2 != NULL) return 0; return 1; }
/******************** class unexpr -- an unary arithmetic expression. -- +expr or -expr. ********************/ unexpr::unexpr(int op, expr *left) :unaryexpr(inttype, op, left) { Error.CondError( !type_equal( left->gettype(), inttype), "Arguments of %c must be integral.", op); if ( constval ) { switch (op) { case '+': value = left->getvalue(); break; case '-': value = - left->getvalue(); break; default: Error.Error("Internal: surprising value for op in unexpr::unexpr."); break; } } }
void check_stmt_valid(struct func_descriptor* belongs_func, struct tree_node* stmt_node){ assert(stmt_node -> unit_code == Stmt); struct tree_node* first_child = stmt_node -> child; if(first_child -> unit_code == Exp){ check_exp_valid(first_child); } else if(first_child -> unit_code == CompSt){ analyze_compst_node(belongs_func, first_child); } else if(first_child -> unit_code == RETURN){ struct var_descriptor* return_var = check_exp_valid(first_child -> sibling); if(return_var != NULL && type_equal(return_var -> var_type, belongs_func -> return_type)) ; else{ printf("Error type 8 at line %d: Return type mismatch in function \'%s\'\n", first_child -> lineno, belongs_func -> func_name); semantic_error_flag = true; } } else if(first_child -> unit_code == IF){ check_exp_valid(first_child -> sibling -> sibling); //todo exp type in if struct tree_node* stmt_node_in_if = first_child -> sibling -> sibling -> sibling -> sibling; check_stmt_valid(belongs_func, stmt_node_in_if); if(stmt_node_in_if -> sibling != NULL){ check_stmt_valid(belongs_func, stmt_node_in_if -> sibling -> sibling); } } else if(first_child -> unit_code == WHILE){ check_exp_valid(first_child -> sibling -> sibling); //todo exp type in while check_stmt_valid(belongs_func, first_child -> sibling -> sibling -> sibling -> sibling); } }