void memptrdcl(Pname bn, Pname tn, Ptype ft, Pname n) { Pptr p = new ptr(PTR,0); p->memof = Pclass(Pbase(bn->tp)->b_name->tp); Pbase b = new basetype(TYPE,tn); PERM(p); Pfct f = Pfct(ft); Ptype t = n->tp; if (t) { p->typ = t; ltlt: switch (t->base) { case PTR: case RPTR: case VEC: if (Pptr(t)->typ == 0) { Pptr(t)->typ = b; break; } t = Pptr(t)->typ; goto ltlt; default: error('s',"P toMFT too complicated"); } } else p->typ = b; f->returns = p; n->tp = f; }
Ptype fct.normalize(Ptype ret) /* normalize return type */ { register Ptype t = returns; if (this==0 || ret==0) error('i',"%d->fct.normalize(%d)",this,ret); returns = ret; if (t == 0) return this; if (argtype) { if (argtype->base != NAME) { error('i',"syntax: ANX"); argtype = 0; nargs = 0; nargs_known = 0; } /* else { Pname n; for (n=argtype; n; n=n->n_list) { if (n->string) { error("N inATL"); n->string = 0; } } } */ } xx: switch (t->base) { case PTR: case RPTR: return Pptr(t)->normalize(this); case VEC: return Pvec(t)->normalize(this); case FCT: return Pfct(t)->normalize(this); case TYPE: t = Pbase(t)->b_name->tp; goto xx; default: error('i',"badFT:%k",t->base); } }
Ptype vec.normalize(Ptype vecof) /* */ { Ptype t = typ; if (this == 0) error('i',"0->vec.normalize()"); typ = vecof; if (t == 0) return this; xx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto xx; case PTR: case RPTR: return Pptr(t)->normalize(this); case VEC: return Pvec(t)->normalize(this); case FCT: return Pfct(t)->normalize(this); default: error('i',"bad vectorT(%d)",t->base); } }
Ptype ptr.normalize(Ptype ptrto) { Ptype t = typ; if (this == 0) error('i',"0->ptr.normalize()"); typ = ptrto; if (t == 0) { Pbase b = (Pbase) ptrto; if (Pfctvec_type && rdo==0 && b->b_unsigned==0 && b->b_const==0 && base==PTR) { switch (b->base) { case INT: delete this; return Pint_type; case CHAR: delete this; return Pchar_type; case VOID: delete this; return Pvoid_type; case TYPE: break; } } if (base==RPTR && b->base==VOID) error("void& is not a validT"); return this; } xx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto xx; case PTR: case RPTR: return Pptr(t)->normalize(this); case VEC: return Pvec(t)->normalize(this); case FCT: return Pfct(t)->normalize(this); default: error('i',"badPT(%d)",t->base); } }
void stmt.dcl() /* typecheck statement "this" in scope "curr_block->tbl" */ { Pstmt ss; Pname n; Pname nn; Pstmt ostmt = Cstmt; for (ss=this; ss; ss=ss->s_list) { Pstmt old_loop, old_switch; Cstmt = ss; Ptable tbl = curr_block->memtbl; /*error('d',"ss %d%k tbl %d e %d%k s %d%k sl %d%k", ss, ss->base, tbl, ss->e, (ss->e)?ss->e->base:0, ss->s, (ss->s)?ss->s->base:0, ss->s_list, (ss->s_list)?ss->s_list->base:0);*/ switch (ss->base) { case BREAK: if (curr_loop==0 && curr_switch==0) error("%k not in loop or switch",BREAK); ss->reached(); break; case CONTINUE: if (curr_loop == 0) error("%k not in loop",CONTINUE); ss->reached(); break; case DEFAULT: if (curr_switch == 0) { error("default not in switch"); break; } if (curr_switch->has_default) error("two defaults in switch"); curr_switch->has_default = ss; ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case SM: switch (ss->e->base) { case DUMMY: ss->e = 0; break; // check for unused results // don't check operators that are likely // to be overloaded to represent "actions": // ! ~ < <= > >= << >> case EQ: case NE: case PLUS: case MINUS: case REF: case DOT: case MUL: case DIV: case ADDROF: case AND: case OR: case ER: case DEREF: case ANDAND: case OROR: case NAME: if (ss->e->tp) break; // avoid looking at generated code ss->e = ss->e->typ(tbl); if (ss->e->tp->base != VOID) error('w',"result of%kE not used",ss->e->base); break; default: ss->e = ss->e->typ(tbl); } // ss->e = (ss->e != dummy) ? ss->e->typ(tbl) : 0; break; case RETURN: { Pname fn = cc->nof; Ptype rt = Pfct(fn->tp)->returns; Pexpr v = ss->e; if (v != dummy) { if (rt->base == VOID) { error('w',"unX return value"); /*refuse to return the value:*/ ss->e = dummy; } else { v = v->typ(tbl); lx: //error('d',"return %t",rt); switch (rt->base) { case TYPE: rt = Pbase(rt)->b_name->tp; goto lx; case RPTR: ss->e = ref_init(Pptr(rt),v,tbl); if (v->lval(0)==0 && v->tp->tconst()==0) error('w',"reference to non-lvalue returned"); else if (v->base==NAME && Pname(v)->n_scope==FCT) error('w',"reference to local variable returned"); break; case COBJ: { Pname rv = tbl->look("_result",0); ss->e = class_init(rv,rt,v,tbl); //error('d',"ss->e %t %d",ss->e->tp,ss->e->base); break; } case ANY: break; case INT: case CHAR: case LONG: case SHORT: if (Pbase(rt)->b_unsigned && v->base==UMINUS && v->e2->base==ICON) error('w',"negative retured fromF returning unsigned"); default: { Pname cn; int i; if ((cn=v->tp->is_cl_obj()) && (i=can_coerce(rt,v->tp)) && Ncoerce) { if (1 < i) error("%d possible conversions for return value",i); Pclass cl = (Pclass)cn->tp; Pref r = new ref(DOT,v,Ncoerce); Pexpr c = new expr(G_CALL,r,0); c->fct_name = Ncoerce; c->tp = rt; ss->e = c; break; } } ss->e = v; if (rt->check(v->tp,ASSIGN)) error("bad return valueT for%n:%t (%tX)",fn,v->tp,rt); } } } else { if (rt->base != VOID) error('w',"return valueX"); } ss->reached(); break; } case DO: /* in DO the stmt is before the test */ inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; if (ss->s->base == DCL) error('s',"D as onlyS in do-loop"); ss->s->dcl(); /* tbl = curr_block->memtbl;*/ ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,DO,tbl); curr_loop = old_loop; break; case WHILE: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; ss->e = ss->e->typ(tbl); /*ss->e->tp->num_ptr(ss->base);*/ ss->e = check_cond(ss->e,WHILE,tbl); if (ss->s->base == DCL) error('s',"D as onlyS in while-loop"); ss->s->dcl(); curr_loop = old_loop; break; case SWITCH: { int ne = 0; inline_restr |= 4; old_switch = curr_switch; curr_switch = ss; ss->e = ss->e->typ(tbl); /* ss->e->tp->num_ptr(SWITCH);*/ ss->e = check_cond(ss->e,SWITCH,tbl); { Ptype tt = ss->e->tp; sii: switch (tt->base) { case TYPE: tt = ((Pbase)tt)->b_name->tp; goto sii; case EOBJ: ne = Penum(Pbase(tt)->b_name->tp)->no_of_enumerators; case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: case FIELD: break; default: error('s',"%t switchE",ss->e->tp); } } ss->s->dcl(); if (ne) { /* see if the number of cases is "close to" but not equal to the number of enumerators */ int i = 0; Pstmt cs; for (cs=ss->case_list; cs; cs=cs->case_list) i++; if (i && i!=ne) { if (ne < i) { ee: error('w',"switch (%t) with %d cases (%d enumerators)",ss->e->tp,i,ne); } else { switch (ne-i) { case 1: if (3<ne) goto ee; case 2: if (7<ne) goto ee; case 3: if (23<ne) goto ee; case 4: if (60<ne) goto ee; case 5: if (99<ne) goto ee; } } } } curr_switch = old_switch; break; } case CASE: if (curr_switch == 0) { error("case not in switch"); break; } ss->e = ss->e->typ(tbl); ss->e->tp->num_ptr(CASE); { Ptype tt = ss->e->tp; iii: switch (tt->base) { case TYPE: tt = Pbase(tt)->b_name->tp; goto iii; case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: break; default: error('s',"%t caseE",ss->e->tp); } } if (1) { Neval = 0; int i = ss->e->eval(); if (Neval == 0) { Pstmt cs; for (cs=curr_switch->case_list; cs; cs=cs->case_list) { if (cs->case_value == i) error("case %d used twice in switch",i); } ss->case_value = i; ss->case_list = curr_switch->case_list; curr_switch->case_list = ss; } else error("bad case label: %s",Neval); } if (ss->s->s_list) error('i',"case%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case GOTO: inline_restr |= 2; ss->reached(); case LABEL: /* Insert label in function mem table; labels have function scope. */ n = ss->d; nn = cc->ftbl->insert(n,LABEL); /* Set a ptr to the mem table corresponding to the scope in which the label actually occurred. This allows the processing of goto's in the presence of ctors and dtors */ if(ss->base == LABEL) { nn->n_realscope = curr_block->memtbl; inline_restr |= 1; } if (Nold) { if (ss->base == LABEL) { if (nn->n_initializer) error("twoDs of label%n",n); nn->n_initializer = (Pexpr)1; } if (n != nn) ss->d = nn; } else { if (ss->base == LABEL) nn->n_initializer = (Pexpr)1; nn->where = ss->where; } if (ss->base == GOTO) nn->use(); else { if (ss->s->s_list) error('i',"label%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; nn->assign(); } if (ss->s) ss->s->dcl(); break; case IF: { Pexpr ee = ss->e->typ(tbl); if (ee->base == ASSIGN) { Neval = 0; (void)ee->e2->eval(); if (Neval == 0) error('w',"constant assignment in condition"); } ss->e = ee = check_cond(ee,IF,tbl); //error('d',"if (%t)",ee->tp); switch (ee->tp->base) { case INT: case ZTYPE: { int i; Neval = 0; i = ee->eval(); //error('d',"if (int:%k) => (i %s)",ss->e->base,i,Neval?Neval:"0"); if (Neval == 0) { Pstmt sl = ss->s_list; if (i) { DEL(ss->else_stmt); ss->s->dcl(); *ss = *ss->s; } else { DEL(ss->s); if (ss->else_stmt) { ss->else_stmt->dcl(); *ss = *ss->else_stmt; } else { ss->base = SM; ss->e = dummy; ss->s = 0; } } ss->s_list = sl; continue; } } } ss->s->dcl(); if (ss->else_stmt) ss->else_stmt->dcl(); break; } case FOR: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; if (ss->for_init) { Pstmt fi = ss->for_init; switch (fi->base) { case SM: if (fi->e == dummy) { ss->for_init = 0; break; } default: fi->dcl(); break; case DCL: fi->dcl(); //error('d',"dcl=>%k %d",fi->base,fi->base); switch (fi->base) { case BLOCK: { /* { ... for( { a } b ; c) d ; e } => { ... { a for ( ; b ; c) d ; e }} */ Pstmt tmp = new stmt (SM,curloc,0); *tmp = *ss; /* tmp = for */ tmp->for_init = 0; *ss = *fi; /* ss = { } */ if (ss->s) ss->s->s_list = tmp; else ss->s = tmp; curr_block = (Pblock)ss; tbl = curr_block->memtbl; ss = tmp; /* rest of for and s_list */ break; } } } } if (ss->e == dummy) ss->e = 0; else { ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,FOR,tbl); } if (ss->s->base == DCL) error('s',"D as onlyS in for-loop"); ss->s->dcl(); ss->e2 = (ss->e2 == dummy) ? 0 : ss->e2->typ(tbl); curr_loop = old_loop; break; case DCL: /* declaration after statement */ { /* collect all the contiguous DCL nodes from the head of the s_list. find the next statement */ int non_trivial = 0; int count = 0; Pname tail = ss->d; for (Pname nn=tail; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; //error('d',"dcl:%n list %d stc %d in %d",nn,nn->n_list,nn->n_sto,nn->n_initializer); if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial == 2) continue; if (nn->n_sto==STATIC || nn->tp->is_ref()) { non_trivial = 2; continue; } Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; default: non_trivial = 1; } Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; if (Pclass(cln->tp)->has_ctor()) non_trivial = 2; } //error('d',"non_trivial %d",non_trivial); while( ss->s_list && ss->s_list->base==DCL ) { Pstmt sx = ss->s_list; tail = tail->n_list = sx->d; // add to tail for (nn=sx->d; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial == 2) continue; if (nn->n_sto==STATIC || nn->tp->is_ref()) { non_trivial = 2; continue; } Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } non_trivial = 1; Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_ctor()) non_trivial = 2; if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; } ss->s_list = sx->s_list; /* delete sx; */ } Pstmt next_st = ss->s_list; //error('d',"non_trivial %d curr_block->own_tbl %d inline_restr %d",non_trivial,curr_block->own_tbl,inline_restr); if (non_trivial==2 /* must */ || (non_trivial==1 /* might */ && ( curr_block->own_tbl==0 /* just as well */ || inline_restr&3 /* label seen */) ) ) { /* Create a new block, put all the declarations at the head, and the remainder of the slist as the statement list of the block. */ ss->base = BLOCK; /* check that there are no redefinitions since the last "real" (user-written, non-generated) block */ for( nn=ss->d; nn; nn=nn->n_list ) { Pname n; if( curr_block->own_tbl && (n=curr_block->memtbl->look(nn->string,0)) && n->n_table->real_block==curr_block->memtbl->real_block) error("twoDs of%n",n); } /* attach the remainder of the s_list as the statement part of the block. */ ss->s = next_st; ss->s_list = 0; /* create the table in advance, in order to set the real_block ptr to that of the enclosing table */ ss->memtbl = new table(count+4,tbl,0); ss->memtbl->real_block = curr_block->memtbl->real_block; Pblock(ss)->dcl(ss->memtbl); } else { /* to reduce the number of symbol tables, do not make a new block, instead insert names in enclosing block, and make the initializers into expression statements. */ Pstmt sss = ss; for( nn=ss->d; nn; nn=nn->n_list ) { Pname n = nn->dcl(tbl,FCT); //error('d',"%n->dcl(%d) -> %d init %d sss=%d ss=%d",nn,tbl,n,n->n_initializer,sss,ss); if (n == 0) continue; Pexpr in = n->n_initializer; n->n_initializer = 0; if (ss) { sss->base = SM; ss = 0; } else sss = sss->s_list = new estmt(SM,sss->where,0,0); if (in) { switch (in->base) { case G_CALL: /* constructor? */ { Pname fn = in->fct_name; if (fn && fn->n_oper==CTOR) break; } default: in = new expr(ASSIGN,n,in); } sss->e = in->typ(tbl); } else sss->e = dummy; } ss = sss; ss->s_list = next_st; } break; } case BLOCK: Pblock(ss)->dcl(tbl); break; case ASM: /* save string */ break; default: error('i',"badS(%d %d)",ss,ss->base); } } Cstmt = ostmt; }
bit type::check(Ptype t, TOK oper, bit level) /* check if "this" can be combined with "t" by the operator "oper" used for check of assignment types (oper==ASSIGN) declaration compatability (oper==0) decl. compatibility without "const"ness (oper=254) (oper == IGNORE_CONST) parameterized type formals (oper==255) as for (oper==0) but special checking for ANY types argument types (oper==ARG) return types (oper==RETURN) overloaded function name match (oper==OVERLOAD) overloaded function coercion (oper==COERCE) virtual function match (oper==VIRTUAL) NOT for arithmetic operators return 1 if the check failed */ { register Ptype t1 = this, t2 = t; bit cnst1 = 0, cnst2 = 0; TOK b1, b2; bit vv=0, over=0, strict_any_check = 0; TOK rec_oper; // value of oper for recursive calls to type::check // oper, 255, or PT_OVERLOAD TOK rec_oper0; // value of oper for recursive calls to type::check // 0, 255, or PT_OVERLOAD if (t1==0 || t2==0) error('i',"check(%p,%p,%d)",t1,t2,oper); if(t1==t2) return 0; switch(oper) { case VIRTUAL: vv = 1; Vcheckerror = 0; oper = 0; break; case OVERLOAD: over = 1; oper = 0; break; case PT_OVERLOAD: over = 1; // no break case 255: oper = 0; strict_any_check=1; break; } if(level==0) { const_problem = 0; return_error = 0; pt_ptm = 0; pt_over = over; } rec_oper = strict_any_check ? ( over ? PT_OVERLOAD : 255 ) : oper; rec_oper0 = strict_any_check ? ( over ? PT_OVERLOAD : 255 ) : 0; t1 = t1->skiptypedefs(cnst1); /* ** GLOG: the following test on ANY must be done before unrolling ** t2, to accommodate templates (in a way I don't yet understand) */ if (t1->base == ANY || t2->base == ANY) if (over==0 || strict_any_check==0) return strict_any_check ? t1!=t2 : 0; t2 = t2->skiptypedefs(cnst2); if(t1==t2) goto const_check; b1 = t1->base; b2 = t2->base; if (b1 != b2) { switch (b1) { case PTR: switch (b2) { case VEC: if ( level>0 || (oper == 0 || oper == IGNORE_CONST) && over==0 || Pptr(t1)->memof || Pptr(t1)->ptname || Pptr(t1)->typ->check(Pvec(t2)->typ,rec_oper,level+1) ) return 1; goto const_check; case FCT: if ( level>0 || Pptr(t1)->typ->check(t2,rec_oper,level+1) ) return 1; goto const_check; } break; case FCT: if( b2==PTR ) { if ( level>0 || t1->check(Pptr(t2)->typ,rec_oper,level+1) ) return 1; goto const_check; } break; case VEC: if (b2==PTR) { if ( level>0 || (oper==0 || oper == IGNORE_CONST) && over==0 || Pptr(t2)->memof || Pptr(t2)->ptname || Pvec(t1)->typ->check(Pptr(t2)->typ,rec_oper,level+1) ) return 1; goto const_check; } break; } if(level>0) { if((oper != 0 && oper != IGNORE_CONST) && b1==VOID && level==1) { if(b2==FCT) { Pfct f = Pfct(t2); if(f->memof && f->f_static==0) return 1; } goto const_check; } return 1; } switch (oper) { case 0: case IGNORE_CONST: if ( b2 == ZTYPE && b1==INT && Pbase(t1)->b_unsigned==0 || b1 == ZTYPE && b2==INT && Pbase(t2)->b_unsigned==0 ) goto const_check; return 1; case ARG: case ASSIGN: case RETURN: case COERCE: switch (b1) { case ZTYPE: case CHAR: case SHORT: case INT: case LONG: case LLONG: case FLOAT: case DOUBLE: case LDOUBLE: case FIELD: switch (b2) { case LONG: case LLONG: case FLOAT: case DOUBLE: case LDOUBLE: case EOBJ: case ZTYPE: case CHAR: case SHORT: case INT: case FIELD: if(oper==COERCE) Nstd++; goto const_check; } return 1; case PTR: case VEC: if (b2==ZTYPE) { if(oper==COERCE) Nstd++; goto const_check; } case RPTR: case COBJ: case FCT: case EOBJ: default: return 1; } } goto const_check; } switch (b1) { case VEC: if ( Pvec(t1)->size!=Pvec(t2)->size && ( level>0 || (oper==0 || oper==IGNORE_CONST) && strict_any_check==0 && Pvec(t1)->size && Pvec(t2)->size ) ) return 1; if(Pvec(t1)->typ->check(Pvec(t2)->typ,rec_oper,level+1)) return 1; break; case PTR: case RPTR: { Pptr p1 = Pptr(t1); Pptr p2 = Pptr(t2); if ((p1->ptname && p2->ptname) && (!p1->memof || !p2->memof)) return 1; if (!same_class(p1->memof,p2->memof)) { // T::* requires we defer setting up memof // until instantiation of the Template type T // ptname holds the formal parameter T // can't merge with other if because of memof usage if( p1->memof==0 && p1->ptname || p2->memof==0 && p2->ptname ) pt_ptm = 1; else if( p1->memof==0 || p2->memof==0 || (p1->memof->baseof(p2->memof)==0 && same_class(p1->memof,p2->memof,1)==0) ) return 1; if (pt_ptm == 0 && (oper==0 || oper==IGNORE_CONST) && same_class(p1->memof,p2->memof)==0) return 1; if(oper==COERCE) Nstd++; } #if 0 if (!level && (oper == 0 || oper == ASSIGN || oper == COERCE || oper == ARG || oper == RETURN)) { Ptype t11; Ptype t22; Ptype ta; Ptype tb; int i = 0; int j = 0; int k = 0; ta = t1; while ((ta->base == PTR || ta->base == RPTR) && (tb = ta->is_ptr_or_ref())) { ta = Pptr(tb)->typ; i++; k += ta->tconst(); } t11 = ta; ta = t2; while ((ta->base == PTR || ta->base == RPTR) && (tb = ta->is_ptr_or_ref())) { ta = Pptr(tb)->typ; j++; } t22 = ta; if (i >= 2 && j == i && t11->tconst() && !t22->tconst() && k != i) return const_problem = 1; } #endif if(p1->typ->check(p2->typ,rec_oper,level+1)) return 1; break; } case FCT: { Pfct f1 = Pfct(t1); Pfct f2 = Pfct(t2); Pname a1 = f1->argtype; Pname a2 = f2->argtype; TOK k1 = f1->nargs_known; TOK k2 = f2->nargs_known; int n1 = f1->nargs; int n2 = f2->nargs; // if pt_ptm, want to check arguments and return type // but template ptm has no memof until instantiation if (!same_class(f1->memof,f2->memof) && pt_ptm == 0) { if (f1->memof==0 && f2->f_static) goto sss; if (vv == 0) // match even if private base class if ( f1->memof==0 || f2->memof==0 || ( level > 1 || f1->memof->baseof(f2->memof)==0 ) && same_class(f1->memof,f2->memof)==0 ) return 1; if(oper==COERCE) Nstd++; sss:; //SSS } if (k1 != k2) return 1; if (n1!=n2 && k1 && k2) { goto aaa; } else if (a1 && a2) { while (a1 && a2) { if (a1->tp->check(a2->tp,rec_oper0,level+1)) return 1; a1 = a1->n_list; a2 = a2->n_list; } if (a1 || a2) goto aaa; } else if (a1 || a2) { aaa: if (k1 == ELLIPSIS) { switch (oper) { case 0: case IGNORE_CONST: if (a2 && k2==0) break; return 1; case ASSIGN: if (a2 && k2==0) break; return 1; case ARG: if (a1) return 1; break; case COERCE: return 1; } } else if (k2 == ELLIPSIS) { return 1; } else if (k1 || k2) { return 1; } } cnst1 = f2->f_const; cnst2 = f1->f_const; if(f1->returns->check(f2->returns,rec_oper0,level+1)) { if(vv && cnst1==cnst2) { bit fail = 1; Ptype t1 = f1->returns; Ptype t2 = f2->returns; if ((t1->is_ptr() && t2->is_ptr()) || (t1->is_ref() && t2->is_ref())) { t1 = Pptr(t1->is_ptr_or_ref())->typ; t2 = Pptr(t2->is_ptr_or_ref())->typ; if (!t1->is_ptr_or_ref() && !t2->is_ptr_or_ref()) { t1 = t1->skiptypedefs(); t2 = t2->skiptypedefs(); if (t1->base == COBJ && t2->base == COBJ) { Pclass c1 = t1->classtype(); Pclass c2 = t2->classtype(); Nvis = 0; if (c2->has_base(c1,0,1) && !Nvis) fail = 0; } } } if (fail) Vcheckerror = 1; else break; } if (rec_oper0 == PT_OVERLOAD && level == 0) return_error = 1; return 1; } break; } case FIELD: switch (oper) { case 0: case IGNORE_CONST: case ARG: error('i',"check field?"); } return 0; case FLOAT: case DOUBLE: case LDOUBLE: case CHAR: case SHORT: case INT: case LONG: case LLONG: if (Pbase(t1)->b_unsigned != Pbase(t2)->b_unsigned) { if (level>0 || (oper==0 || oper==IGNORE_CONST)) return 1; if (oper==COERCE) Nstd++; } goto const_check; case EOBJ: if (Pbase(t1)->b_name->tp != Pbase(t2)->b_name->tp) return 1; goto const_check; case CLASS: case COBJ: { Pname n1, n2; if (b1 == COBJ) { n1 = Pbase(t1)->b_name; n2 = Pbase(t2)->b_name; if (n1 == n2) goto const_check; } // once again, a more comprehensive check for classes, // since they may be parameterized. // same_class: handles class templates: instantiated // fm_same_class: handles matching uninstantiated templates // used as formal arguments for template functions // hack: see comment on classdef::same_class in template.c extern int is_arg; int access = template_hier || pt_over; if ( same_class(Pclass(b1==COBJ?n1->tp:t1),Pclass(b1==COBJ?n2->tp:t2),access||is_arg) || rec_oper==PT_OVERLOAD && fm_same_class(Pclass(b1==COBJ?n1->tp:t1),Pclass(b1==COBJ?n2->tp:t2)) ) goto const_check; // permit a derived class to match public base class if (template_hier != 0) goto pt_hack; switch (oper) { case ARG: case ASSIGN: case RETURN: case COERCE: { pt_hack: ppbase = PUBLIC; if (level<=1 && ((Pclass(b1==COBJ?n2->tp:t2))->is_base(b1==COBJ?n1->string:Pclass(t1)->string))) { if (ppbase!=PUBLIC) { const_problem = 0; return 1; // private or protected base } if(oper==COERCE) Nstd++; goto const_check; } } // no break case 0: case IGNORE_CONST: const_problem = 0; return 1; } goto const_check; } case ZTYPE: case VOID: goto const_check; default: error('i',"T::check(o=%d %d %d)",oper,b1,b2); } const_check: if(cnst1==cnst2) return 0; switch(oper) { case IGNORE_CONST: return 0;//ignore "const"ness for oper=IGNORE_CONST case 0: const_problem=1; return 1; case ASSIGN: case COERCE: case ARG: case RETURN: if(level>0) { if(cnst2) const_problem=1; return cnst2; } return 0; default: error('i',"oper = %k in type::check()",oper); } return 0; }
void type::dcl(Ptable tbl) /* go through the type (list) and (1) evaluate vector dimensions (2) evaluate field sizes (3) lookup struct tags, etc. (4) handle implicit tag declarations */ { Ptype t = this; // processing_sizeof suppresses errors for refs to names in the arg // to sizeof. Turn errors back on for exprs within type specs // (such as array subscripts) int os = processing_sizeof; processing_sizeof = 0; if (this == 0) error('i',"T::dcl(this==0)"); if (tbl->base != TABLE) error('i',"T::dcl(%d)",tbl->base); xx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto xx; case PTR: case RPTR: { Pptr p = Pptr(t); if(p->memof == 0 && p->ptname) { // T::*, where T is a template formal Ptype tp = p->ptname->tp->skiptypedefs(); switch (tp->base) { case COBJ: { p->memof = tp->classtype(); if (p->typ) { Ptype t = p->typ->skiptypedefs(); if (t && t->base==FCT) { Pfct(t)->memof = p->memof; } } break; } case CLASS: { p->memof = Pclass(tp); Ptype t = p->typ->skiptypedefs(); Pfct f = Pfct(t); // safe??? f->memof = p->memof; break; } default: error("illegalZizedP toM %t::*",tp); break; } } t = p->typ; if (t->base == TYPE) { Ptype tt = Pbase(t)->b_name->tp; if (tt->base == FCT) p->typ = tt; goto done; } goto xx; } case VEC: { Pvec v = Pvec(t); Pexpr e = v->dim; if (e) { Ptype et; v->dim = e = e->typ(tbl); if (e->tp->skiptypedefs()->base == COBJ) { e = check_cond(e,DEREF,tbl); v->dim = e; } et = e->tp; if (et->integral(0) == 'A') { error("UN in array dimension"); } else { long long i; Neval = 0; i = e->eval(); if (Neval == 0) { if (largest_int<i) error("array dimension too large"); v->size = int(i); DEL(v->dim); v->dim = 0; } if (new_type) { if (Neval) ; else if (i == 0) v->dim = zero; else if (i < 0) { error("negative array dimension"); i = 1; } } else { if (Neval) error("%s",Neval); else if (i == 0) { error("array dimension == 0"); v->dim=e; } else if (i < 0) { error("negative array dimension"); i = 1; } } } } t = v->typ; llx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto llx; case FCT: v->typ = t; break; case VEC: if (Pvec(t)->dim==0 && Pvec(t)->size==0) error("null dimension (something like [][] seen)"); } goto xx; } case FCT: { Pfct f = Pfct(t); void dargs(Pname, Pfct, Ptable); if (f->argtype) dargs(0,f,tbl); for (Pname n=f->argtype; n; n = n->n_list) { Ptype t = n->tp; n->tp->dcl(tbl); while(t->base==TYPE) t = Pbase(t)->b_name->tp; if(t->base==VEC) n->tp = new ptr(PTR,Pvec(t)->typ); } Pname cn = f->returns->is_cl_obj(); if (cn && Pclass(cn->tp)->has_itor()) make_res(f); else if (f->f_this == 0) f->f_args = f->argtype; t = f->returns; goto xx; } case FIELD: { Pbase f = Pbase(t); Pexpr e = Pexpr(f->b_name); long long i; Ptype et; e = e->typ(tbl); f->b_name = Pname(e); et = e->tp; if (et->integral(0) == 'A') { error("UN in field size"); i = 1; } else { Neval = 0; i = e->eval(); if (Neval) error("%s",Neval); else if (i < 0) { error("negative field size"); i = 1; } else if (f->b_fieldtype->tsizeof()*BI_IN_BYTE < i) error("field size > sizeof(%t)",f->b_fieldtype); DEL(e); } f->b_bits = int(i); f->b_name = 0; break; } } done: processing_sizeof = os; return; }
TOK type::kind(TOK oper, TOK v, bit perr) /* v == 'I' integral 'N' numeric 'P' numeric or pointer */ { Ptype t = this; if (this == 0) error('i',"type::kind(): this==0"); t = t->skiptypedefs(); switch (t->base) { case ANY: return 'A'; case ZTYPE: return 'Z'; case FIELD: case CHAR: case SHORT: case INT: case LONG: case LLONG: case EOBJ: return 'I'; case FLOAT: case LDOUBLE: case DOUBLE: if (v == 'I') if(perr) error("float operand for %k",oper); return 'F'; case VEC: case PTR: if (v != 'P') if(perr) error("P operand for %k",oper); switch (oper) { case INCR: case DECR: case MINUS: case PLUS: case ASMINUS: case ASPLUS: if ( t->base==PTR && ( Pptr(t)->memof || Pptr(t)->typ->base==FCT ) ) { if(perr) error("%t operand of%k",this,oper); } else { Pptr(t)->typ->tsizeof(); // get increment } break; default: if ( t->base==PTR && ( Pptr(t)->memof || Pptr(t)->typ->base==FCT ) ) if(perr) error("%t operand of%k",this,oper); case LT: case LE: case GT: case GE: case ANDAND: case OROR: case ASSIGN: case NE: case EQ: case IF: case WHILE: case DO: case FOR: case QUEST: case NOT: break; } return 'P'; case RPTR: if(perr) error("R operand for %k",oper); return 'A'; case FCT: if (v != 'P') if(perr) error("F operand for %k",oper); return FCT; case OVERLOAD: if(perr) error("overloaded operand for %k",oper); return 'A'; case CLASS: case ENUM: if(perr) error("%k operand for %k",base,oper); return 'A'; default: if(perr) error("%t operand for %k",this,oper); return 'A'; } }
Pname name.normalize(Pbase b, Pblock bl, bit cast) /* if (bl) : a function definition (check that it really is a type if (cast) : no name string for each name on the name list invert the declarator list(s) and attatch basetype watch out for class object initializers convert struct s { int a; } a; into struct s { int a; }; struct s a; */ { Pname n; Pname nn; TOK stc = b->b_sto; bit tpdf = b->b_typedef; bit inli = b->b_inline; bit virt = b->b_virtual; Pfct f; Pname nx; if (b == 0) error('i',"%d->N.normalize(0)",this); if (this == 0) error('i',"0->N.normalize(%k)",base); if (inli && stc==EXTERN) { error("both extern and inline"); inli = 0; } //fprintf(stderr,"name.norm(%d %s) tp (%d %d)\n",this,string,tp,tp->base); if (stc==FRIEND && tp==0) { /* friend x; must be handled during syntax analysis to cope with class x { friend y; y* p; }; "y" is not local to "x": class x { friend y; ... }; y* p; is legal */ if (b->base) error(0,"T specified for friend"); if (n_list) { error("L of friends"); n_list = 0; } Pname nx = tname(CLASS); modified_tn = modified_tn->l; /* global */ n_sto = FRIEND; tp = nx->tp; return this; } if (tp && n_oper==TNAME && tp->base==FCT) { /* HORRIBLE FUDGE: fix the bad grammar */ Pfct f = (Pfct)tp; Pfct f2 = (Pfct)f->returns; if (f2 && f2->base==FCT) { Pexpr e = f2->argtype; //error('d',"%s: mis-analyzedP toF",string); if (e->base == ELIST) { // get the real name, fix its type if (e->e2 || e->e1->base!=DEREF) goto zse1; Pname rn = (Pname)e->e1->e1; if (rn->base!=NAME) goto zse1; f->returns = new ptr(PTR,0); b = new basetype(TYPE,ktbl->look(string,0)); n_oper = 0; string = rn->string; base = NAME; //error('d',"realN %n b==%t",rn,b); } } } zse1: if (cast) string = ""; b = b->check(this); switch (b->base) { // separate class definitions // from object and function type declarations case COBJ: nn = b->b_name; //fprintf(stderr,"COBJ (%d %s) -> (%d %d body=%d)\n",nn,nn->string,nn->tp,nn->tp->base,Pclass(nn->tp)->c_body); if (Pclass(nn->tp)->c_body==2) { /* first occurrence */ if (tp && tp->base==FCT) { error('s',&this->where,"%k%n defined as returnT for%n (did you forget a ';' after '}' ?)",Pclass(nn->tp)->csu,nn,this); nn = this; break; } nn->n_list = this; Pclass(nn->tp)->c_body = 1; /* other occurences */ } else nn = this; break; case EOBJ: nn = b->b_name; if (Penum(nn->tp)->e_body==2) { if (tp && tp->base==FCT) { error('s',"enum%n defined as returnT for%n (did you forget a ';'?)",nn,this); nn = this; break; } nn->n_list = this; Penum(nn->tp)->e_body = 1; } else nn = this; break; default: nn = this; } for (n=this; n; n=nx) { Ptype t = n->tp; nx = n->n_list; n->n_sto = stc; /* if (t && n_oper==TNAME && t->base==FCT) { // HORRIBLE FUDGE: fix the bad grammar Pfct f = (Pfct)t; Pfct f2 = (Pfct)f->returns; if (f2 && f2->base==FCT) { Pexpr e = f2->argtype; if (e->base == ELIST) { // get the real name, fix its type if (e->e2 || e->e1->base!=DEREF) goto zse; Pname rn = (Pname)e->e1->e1; if (rn->base!=NAME) goto zse; f->returns = new ptr(PTR,0); b = new basetype(TYPE,ktbl->look(n->string,0)); n->n_oper = 0; n->string = rn->string; n->base = NAME; } } } zse: */ if (n->base == TNAME) error('i',"redefinition ofTN%n",n); if (t == 0) { if (bl == 0) n->tp = t = b; else { error("body of nonF%n",n); t = new fct(defa_type,0,0); } } switch (t->base) { case PTR: case RPTR: n->tp = Pptr(t)->normalize(b); break; case VEC: n->tp = Pvec(t)->normalize(b); break; case FCT: n->tp = Pfct(t)->normalize(b); break; case FIELD: if (n->string == 0) n->string = make_name('F'); n->tp = t; Pbase tb = b; flatten: //error('d',"flatten %d %d %d",tb->base,b->b_unsigned,b->b_const); switch (tb->base) { case TYPE: /* chase typedefs */ tb = (Pbase)tb->b_name->tp; goto flatten; case INT: Pbase(t)->b_fieldtype = (b->b_unsigned) ? uint_type : int_type; goto iii; case CHAR: Pbase(t)->b_fieldtype = (b->b_unsigned) ? uchar_type : char_type; goto iii; case SHORT: Pbase(t)->b_fieldtype = (b->b_unsigned) ? ushort_type : short_type; goto iii; iii: Pbase(t)->b_unsigned = b->b_unsigned; Pbase(t)->b_const = b->b_const; break; default: error("non-int field"); n->tp = defa_type; } break; } f = (Pfct) n->tp; if (f->base != FCT) { if (bl) { error("body for nonF%n",n); n->tp = f = new fct(defa_type,0,0); continue; } if (inli) error("inline nonF%n",n); if (virt) error("virtual nonF%n",n); if (tpdf) { if (n->n_initializer) { error("Ir for typedefN%n",n); n->n_initializer = 0; } n->tdef(); } continue; } f->f_inline = inli; f->f_virtual = virt; if (tpdf) { if (f->body = bl) error("typedef%n { ... }",n); n->tdef(); continue; } if (f->body = bl) continue; /* Check function declarations. Look for class object instansiations The real ambiguity: ; class x fo(); is interpreted as an extern function declaration NOT a class object with an empty initializer */ { Pname cn = f->returns->is_cl_obj(); bit clob = (cn || cl_obj_vec); //error('d',"%n: fr%t cn%n",n,f->returns,cn); if (f->argtype) { /* check argument/initializer list */ Pname nn; for (nn=f->argtype; nn; nn=nn->n_list) { if (nn->base != NAME) { if (!clob) { error("ATX for%n",n); goto zzz; } goto is_obj; } /* if (nn->string) { error("AN%n inD of%n",nn,n); nn->string = 0; } */ if (nn->tp) goto ok; } if (!clob) { error("FALX"); goto zzz; } is_obj: //fprintf(stderr,"is_obj: %d %s tp = %d %d\n",this,string,f->returns,f->returns->base); fflush(stderr); /* it was an initializer: expand to constructor */ n->tp = f->returns; if (f->argtype->base != ELIST) f->argtype = (Pname)new expr(ELIST,(Pexpr)f->argtype,0); n->n_initializer = new texpr(VALUE,cn->tp,(Pexpr)f->argtype); goto ok; zzz: if (f->argtype) { DEL(f->argtype); f->argtype = 0; f->nargs = 0; f->nargs_known = !fct_void; } } else { /* T a(); => function declaration */ /* if (clob) { DEL(n->tp); n->tp = f->returns; } */ } ok: ; } } return nn; }