Pname gen.find(Pfct f) { Plist gl; for (gl=fct_list; gl; gl=gl->l) { Pname nx = gl->f; Pfct fx = (Pfct)nx->tp; Pname a, ax; int vp = 0; //error('d',"find %s",nx->string); if (fx->nargs_known != f->nargs_known) { if (fx->nargs && fx->nargs_known!=ELLIPSIS) continue; } for (ax=fx->argtype, a=f->argtype; a&&ax; ax=ax->n_list, a=a->n_list) { //error('d',"ax %d %d a %d %d",ax->tp,ax->tp->base,a->tp,a->tp->base); Ptype at = ax->tp; if ( at->check(a->tp,0)) goto xx; if ( vrp_equiv ) vp = 1; switch (at->base) { case CHAR: case SHORT: case INT: case LONG: if (Pbase(at)->b_unsigned ^ Pbase(a->tp)->b_unsigned) error('w',"the overloading mechanism cannot tell an unsigned%k from a%k",at->base,at->base); } } if (ax) { if (ax->n_initializer) error("Ir makes overloaded %s() ambiguous",string); continue; } if (a) { if (a->n_initializer) error("Ir makes overloaded %s() ambiguous",string); continue; } if ( fx->returns->check(f->returns,0) ) error("two different return valueTs for overloaded %s: %t and %t", string, fx->returns, f->returns); if (vp) error('w',"ATs differ (only): [] vs *"); return nx; xx:; } return 0; }
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; }
Pname type.is_cl_obj() /* returns this->b_name if this is a class object returns 0 and sets cl_obj_vec to this->b_name if this is a vector of class objects returns 0 and sets eobj to this->b_name if this is an enum object else returns 0 */ { bit v = 0; register Ptype t = this; eobj = 0; cl_obj_vec = 0; xx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto xx; case COBJ: if (v) { cl_obj_vec = Pbase(t)->b_name; return 0; } else return Pbase(t)->b_name; case VEC: t = Pvec(t)->typ; v=1; goto xx; case EOBJ: eobj = Pbase(t)->b_name; default: return 0; } }
Pexpr check_cond(Pexpr e, TOK b, Ptable tbl) { //error('d',"check_cond(%k %k) tbl %d",e->base,b,tbl); Pname cn; if (cn = e->tp->is_cl_obj()) { Pclass cl = (Pclass)cn->tp; int i = 0; Pname found = 0; for (Pname on = cl->conv; on; on=on->n_list) { Pfct f = (Pfct)on->tp; Ptype t = f->returns; xx: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto xx; case CHAR: case SHORT: case INT: case LONG: case EOBJ: case FLOAT: case DOUBLE: case PTR: i++; found = on; } } switch (i) { case 0: error("%nO in%kE",cn,b); return e; case 1: { //error('d',"cond%t<-%t:%n",Pfct(found->tp)->returns,e->tp,found); Pclass cl = (Pclass)cn->tp; Pref r = new ref(DOT,e,found); r->tp = found->tp; Pexpr c = new expr(G_CALL,r,0); c->fct_name = found; // c->tp = Pfct(found->tp)->returns; return c->typ(tbl); } default: error("%d possible conversions for%nO in%kE",i,cn,b); return e; } } e->tp->num_ptr(b); return e; }
Pname name.tname(TOK csu) /* "csu" "this" seen, return typedef'd name for "this" return (TNAME,x) x: (COBJ,y) y: (NAME,z) z: (CLASS,ae); */ { //fprintf(stderr,"tname %s %d ll %d\n",string,this,lex_level); switch (base) { case TNAME: return this; case NAME: { Pname tn = ktbl->insert(this,0); //fprintf(stderr,"tname tn %s %d ll %d (mod %d)\n",tn->string,tn,tn->lex_level,modified_tn); Pname on = new name; tn->base = TNAME; tn->lex_level = lex_level; modified_tn = new name_list(tn,modified_tn); tn->n_list = n_list = 0; string = tn->string; *on = *this; switch (csu) { case ENUM: tn->tp = new basetype(EOBJ,on); on->tp = new enumdef(0); break; default: on->tp = new classdef(csu,0); Pclass(on->tp)->string = tn->string; tn->tp = new basetype(COBJ,on); Pbase(tn->tp)->b_table = Pclass(on->tp)->memtbl; } PERM(tn); PERM(tn->tp); PERM(on); PERM(on->tp); /*fprintf(stderr,"tname %s -> n (%d %d) n->tp (%d %d)\n",string,tn,tn->base,tn->tp,tn->tp->base); fflush(stderr);*/ return tn; } default: error('i',"tname(%s %d %k)",string,this,base); } }
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; }
void classdef.dcl(Pname cname, Ptable tbl) { int nmem; Pname p; Pptr cct; Pbase bt; Pname px; Ptable btbl; int bvirt; Pclass bcl; int i; int fct_seen = 0; int static_seen = 0; int local = tbl!=gtbl; int byte_old = byte_offset; int bit_old = bit_offset; int max_old = max_align; int boff; int in_union; int usz; int make_ctor = 0; int make_dtor = 0; /* this is the place for paranoia */ if (this == 0) error('i',"0->Cdef.dcl(%d)",tbl); if (base != CLASS) error('i',"Cdef.dcl(%d)",base); if (cname == 0) error('i',"unNdC"); if (cname->tp != this) error('i',"badCdef"); if (tbl == 0) error('i',"Cdef.dcl(%n,0)",cname); if (tbl->base != TABLE) error('i',"Cdef.dcl(%n,tbl=%d)",cname,tbl->base); nmem = pubmem->no_of_names() + privmem->no_of_names() + pubdef->no_of_names(); in_union = (csu==UNION || csu==ANON); if (clbase) { if (clbase->base != TNAME) error("BC%nU",clbase); clbase = Pbase(clbase->tp)->b_name; bcl = (Pclass)clbase->tp; if ((bcl->defined&SIMPLIFIED) == 0) error("BC%nU",clbase); tbl = bcl->memtbl; if (tbl->base != TABLE) error('i',"badBC table %d",tbl); btbl = tbl; bvirt = bcl->virt_count; if (bcl->csu == UNION) error('s',"C derived from union"); if (in_union) error("derived union"); else if (pubbase == 0) csu = CLASS; boff = bcl->real_size; max_align = bcl->align(); bit_ass = bcl->bit_ass; } else { btbl = 0; bvirt = 0; boff = 0; if (!in_union) csu = (virt_count) ? CLASS : STRUCT; while (tbl!=gtbl && tbl->t_name) tbl = tbl->next; // nested classes max_align = AL_STRUCT; bit_ass = 1; // can be bitwise copied } memtbl->set_scope(tbl); memtbl->set_name(cname); if (nmem) memtbl->grow((nmem<=2)?3:nmem); cc->stack(); cc->not = cname; cc->cot = this; //error('d',"classdef%n",cname); byte_offset = usz = boff; bit_offset = 0; bt = new basetype(COBJ,cname); bt->b_table = memtbl; this_type = cc->tot = cct = new ptr(PTR,bt,0); PERM(cct); PERM(bt); for (p=privmem; p; p=px) { Pname m; px = p->n_list; //error('d',"privmem%n %d",p,p->tp->base); if (p->tp->base==FCT) { Pfct f = (Pfct)p->tp; Pblock b = f->body; f->body = 0; switch( p->n_sto ) { case AUTO: case STATIC: case REGISTER: case EXTERN: error("M%n cannot be%k",p,p->n_sto); p->n_sto = 0; } m = p->dcl(memtbl,0); if (b) { if (m->tp->defined&(DEFINED|SIMPLIFIED)) error("two definitions of%n",m); else if (p->where.line!=m->where.line) error('s',"previously declared%n cannot be defined inCD",p); else Pfct(m->tp)->body = b; } fct_seen = 1; } else { m = p->dcl(memtbl,0); if (m) { if (m->n_stclass==STATIC) { static_seen = 1; m->n_sto = (tbl == gtbl) ? 0 : STATIC; if (m->n_initializer) error('s',"staticM%n withIr",m); } if (in_union) { if (usz < byte_offset) usz = byte_offset; byte_offset = 0; } } } } if (privmem && csu==STRUCT) csu = CLASS; for (p=pubmem; p; p=px) { Pname m; px = p->n_list; //error('d',"pubmem%n %d",p,p->tp->base); if (p->tp->base == FCT) { Pfct f = (Pfct)p->tp; Pblock b = f->body; f->body = 0; switch(p->n_sto) { case AUTO: case STATIC: case REGISTER: case EXTERN: error("M%n cannot be%k",p,p->n_sto); p->n_sto = 0; } m = p->dcl(memtbl,PUBLIC); if (b) { if (m->tp->defined&(DEFINED|SIMPLIFIED)) error("two definitions of%n",m); else if (p->where.line!=m->where.line) error('s',"previously declared%n cannot be defined inCD",p); else Pfct(m->tp)->body = b; } fct_seen = 1; } else { m = p->dcl(memtbl,PUBLIC); if (m) { if (m->n_stclass==STATIC) { m->n_sto = (tbl == gtbl) ? 0 : STATIC; static_seen = 1; if (m->n_initializer) error('s',"staticM%n withIr",m); } if (in_union) { if (usz < byte_offset) usz = byte_offset; byte_offset = 0; } } } /*delete p;*/ } /* pubmem = 0; */ // if (local && fct_seen) error("FM of local%k %s",csu,string); if (in_union) byte_offset = usz; if (virt_count || bvirt) { /* assign virtual indices */ Pname vp[100]; Pname nn; nn = has_ctor(); if (nn==0 || nn->n_table!=memtbl) make_ctor = 1; { // FUDGE vtbl char* s = new char[20]; sprintf(s,"%s__vtbl",string); Pname n = new name(s); n->tp = Pfctvec_type; Pname nn = gtbl->insert(n,0); nn->use(); } if (virt_count = bvirt) for (i=0; i<bvirt; i++) vp[i] = bcl->virt_init[i]; for ( nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) { switch (nn->tp->base) { case FCT: { Pfct f = (Pfct)nn->tp; if (bvirt) { Pname vn = btbl->look(nn->string,0); if (vn) { /* match up with base class */ if (vn->n_table==gtbl) goto vvv; Pfct vnf; switch (vn->tp->base) { case FCT: vnf = (Pfct)vn->tp; if (vnf->f_virtual) { if (vnf->check(f,0)) error("virtual%nT mismatch:%t and%t",nn,f,vnf); f->f_virtual = vnf->f_virtual; vp[f->f_virtual-1] = nn; } else goto vvv; break; case OVERLOAD: { Pgen g = (Pgen)vn->tp; if (f->f_virtual || Pfct(g->fct_list->f->tp)->f_virtual) error('s',"virtual%n overloaded inBC but not in derivedC",nn); break; } default: goto vvv; } } else goto vvv; } else { vvv: /*error('d',"vvv: %n f_virtual %d virt_count %d",nn,f->f_virtual,virt_count);*/ if (f->f_virtual) { f->f_virtual = ++virt_count; switch (f->f_virtual) { case 1: { Pname vpn = new name("_vptr"); vpn->tp = Pfctvec_type; (void) vpn->dcl(memtbl,PUBLIC); delete vpn; } default: vp[f->f_virtual-1] = nn; } } } break; } case OVERLOAD: { Plist gl; Pgen g = (Pgen)nn->tp; /*error('d',"overload%n bvirt==%d",nn,bvirt);*/ if (bvirt) { Pname vn = btbl->look(nn->string,0); Pgen g2; Pfct f2; if (vn) { /*error('d',"vn%n tp%k",vn,vn->tp->base);*/ if (vn->n_table == gtbl) goto ovvv; switch (vn->tp->base) { default: goto ovvv; case FCT: f2 = (Pfct)vn->tp; if (f2->f_virtual || Pfct(g->fct_list->f->tp)->f_virtual) error('s',"virtual%n overloaded in derivedC but not inBC",nn); break; case OVERLOAD: g2 = (Pgen)vn->tp; for (gl=g->fct_list; gl; gl=gl->l) { Pname fn = gl->f; Pfct f = (Pfct)fn->tp; Pname vn2 = g2->find(f); if (vn2 == 0) { if (f->f_virtual) error('s',"virtual overloaded%n not found inBC",fn); } else { Pfct vn2f = (Pfct)vn2->tp; if (vn2f->f_virtual) { f->f_virtual = vn2f->f_virtual; vp[f->f_virtual-1] = fn; } } } break; } } else goto ovvv; } else { ovvv: for (gl=g->fct_list; gl; gl=gl->l) { Pname fn = gl->f; Pfct f = (Pfct)fn->tp; /*fprintf(stderr,"fn %s f %d %d %d count %d\n",fn->string,f,f->base,f->f_virtual,virt_count+1);*/ if (f->f_virtual) { f->f_virtual = ++virt_count; switch (f->f_virtual) { case 1: { Pname vpn = new name("_vptr"); vpn->tp = Pfctvec_type; (void) vpn->dcl(memtbl,0); delete vpn; } default: vp[f->f_virtual-1] = fn; } } } } break; } } } virt_init = new Pname[virt_count]; for (i=0; i<virt_count; i++) virt_init[i] = vp[i]; } Pname pnx; for (p=pubdef; p; p=pnx) { char* qs = p->n_qualifier->string; char* ms = p->string; Pname cx; Ptable ctbl; Pname mx; pnx = p->n_list; //error('d',"dcl: pubdef %s::%s",qs,ms); if (strcmp(ms,qs)==0) ms = "_ctor"; for (cx = clbase; cx; cx = Pclass(cx->tp)->clbase) { if (strcmp(cx->string,qs) == 0) goto ok; } error("publicQr %s not aBC",qs); continue; ok: ctbl = Pclass(cx->tp)->memtbl; mx = ctbl->lookc(ms,0); //error('d',"ms %d %d %d",mx,Ebase,Epriv); if (Ebase) { // cc->nof ?? if (!Ebase->has_friend(cc->nof)) error("QdMN%n is in privateBC",p); } else if (Epriv) { if (!Epriv->has_friend(cc->nof)) error("QdMN%n is private",p); } if (mx == 0) { error("C%n does not have aM %s",cx,p->string); p->tp = any_type; } else { if (mx->tp->base==OVERLOAD) error('s',"public specification of overloaded%n",mx); p->base = PUBLIC; } p->n_qualifier = mx; (void) memtbl->insert(p,0); //error('d',"bbb"); if (Nold) error("twoDs of CM%n",p); } pubdef = 0; if (bit_offset) byte_offset += (bit_offset/BI_IN_BYTE+1); real_size = byte_offset; //error('d',"%s: rz=%d (bits %d)",string,byte_offset,bit_offset); if (byte_offset < SZ_STRUCT) byte_offset = SZ_STRUCT; int waste = byte_offset%max_align; if (waste) byte_offset += max_align-waste; //error('d',"%s: sz=%d al=%d",string,byte_offset,max_align); obj_size = byte_offset; obj_align = max_align; if ( has_dtor() && has_ctor()==0) error('w',"%s has destructor but no constructor",string); { // now look look at the members Pname m; Pclass oc = in_class; int ct = has_ctor()==0; int dt = has_dtor()==0; int un = csu==UNION; Pname statc = 0; Pname statd = 0; for (m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) { if (m->base == PUBLIC) continue; Ptype t = m->tp; switch (t->base) { default: if (ct && make_ctor==0) { if (t->is_ref()) error("reference%n inC %s without constructor",m,string); if (t->tconst() && vec_const==0) error("constant%n inC %s without constructor",m,string); } break; case FCT: case OVERLOAD: case CLASS: case ENUM: continue; case VEC: break; } Pname cn = t->is_cl_obj(); if (cn == 0) cn = cl_obj_vec; if (cn) { Pclass cl = (Pclass)cn->tp; if (cl->bit_ass == 0) bit_ass = 0; // no bit copy if (ct || dt || un) { Pname ctor = cl->has_ctor(); Pname dtor = cl->has_dtor(); if (ctor) { if (m->n_stclass==STATIC) { error('s',"staticM%n ofC%n with constructor",m,cn); statc = m; } else if (un) error("M%n ofC%n with constructor in union",m,cn); else if (ct) { if (statc) error('s',"staticM%n ofC%t with constructor",statc,statc->tp); make_ctor = 1; ct = 0; } } if (dtor) { if (m->n_stclass==STATIC) { error('s',"staticM%n ofC%n with destructor",m,cn); statd = m; } else if (un) error("M%n ofC%n with destructor in union",m,cn); else if (dt) { if (statd) error('s',"staticM%n ofC%t with constructor",statd,statd->tp); make_dtor = 1; dt = 0; } } } } } } if (make_ctor) { Pname ct = has_ctor(); if (ct==0 || ct->n_table!=memtbl) { // make a constructor for the class: x::x() {} // a base class's constructor is not good enough if (ct && has_ictor()==0) error("%k %s needs a constructor",csu,string); Pname n = new name(string); Pfct f = new fct(defa_type,0,1); n->tp = f; n->n_oper = TNAME; Pname m = n->dcl(memtbl,PUBLIC); Pfct(m->tp)->body = new block(curloc,0,0); } } if (make_dtor && has_dtor()==0) { // make a destructor for the class: x::x() {} Pname n = new name(string); Pfct f = new fct(defa_type,0,1); n->tp = f; n->n_oper = DTOR; Pname m = n->dcl(memtbl,PUBLIC); Pfct(m->tp)->body = new block(curloc,0,0); } defined |= DEFINED; for (p=memtbl->get_mem(i=1); p; p=memtbl->get_mem(++i)) { /* define members defined inline */ //error('d',"member %n",p); switch (p->tp->base) { case FCT: { Pfct f = (Pfct)p->tp; if (f->body) { f->f_inline = 1; p->n_sto = STATIC; f->dcl(p); } break; } case OVERLOAD: { Pgen g = (Pgen)p->tp; Plist gl; for (gl=g->fct_list; gl; gl=gl->l) { Pname n = gl->f; Pfct f = (Pfct)n->tp; if (f->body) { f->f_inline = 1; n->n_sto = STATIC; f->dcl(n); } } } } } Plist fl; /* define friends defined inline */ for (fl=friend_list; fl; fl=fl->l) { Pname p = fl->f; switch (p->tp->base) { case FCT: { Pfct f = (Pfct)p->tp; if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0) { f->f_inline = 1; p->n_sto = STATIC; f->dcl(p); } break; } case OVERLOAD: { Pgen g = (Pgen)p->tp; Plist gl; for (gl=g->fct_list; gl; gl=gl->l) { Pname n = gl->f; Pfct f = (Pfct)n->tp; if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0) { f->f_inline = 1; n->n_sto = STATIC; f->dcl(n); } } } } } byte_offset = byte_old; bit_offset = bit_old; max_align = max_old; cc->unstack(); }
void list_check(Pname nn, Ptype t, Pexpr il) /* see if the list "lll" can be assigned to something of type "t" "nn" is the name of the variable for which the assignment is taking place. "il" is the last list element returned by next_elem() */ { Pexpr e; bit lst = 0; int i; Pclass cl; //error('d',"list_check%n: %t (%d)",nn,t,il); switch ( (int)il ) { case 0: break; case 1: lst = 1; break; default: list_put_back(il); } zzz: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto zzz; case VEC: { Pvec v = (Pvec)t; Ptype vt = v->typ; if (v->size) { /* get at most v->size initializers */ if (v->typ->base == CHAR) { e = next_elem(); if (e->base == STRING) { // v[size] = "..." int isz = Pvec(e->tp)->size; if (v->size < isz) error("Ir too long (%d characters) for%n[%d]",isz,nn,v->size); break; } else list_put_back(e); } for (i=0; i<v->size; i++) { // check next list element type ee: e = next_elem(); if (e == 0) goto xsw; // too few initializers are ok vtz: //error('d',"vtz: %d",vt->base); switch (vt->base) { case TYPE: vt = Pbase(vt)->b_name->tp; goto vtz; case VEC: case COBJ: list_check(nn,vt,e); break; default: if (e == (Pexpr)1) { error("unXIrL"); goto ee; } if (vt->check(e->tp,ASSIGN)) error("badIrT for%n:%t (%tX)",nn,e->tp,vt); } } if ( lst && (e=next_elem()) ) error("end ofIrLX after vector"); xsw:; } else { /* determine v->size */ i = 0; xx: while ( e=next_elem() ) { // get another initializer i++; vtzz: //error('d',"vtzz: %d",vt->base); switch (vt->base) { case TYPE: vt = Pbase(vt)->b_name->tp; goto vtzz; case VEC: case COBJ: list_check(nn,vt,e); break; default: if (e == (Pexpr)1) { error("unXIrL"); goto xx; } if (vt->check(e->tp,ASSIGN)) error("badIrT for%n:%t (%tX)",nn,e->tp,vt); } } v->size = i; } break; } case CLASS: cl = (Pclass)t; goto ccc; case COBJ: /* initialize members */ cl = Pclass(Pbase(t)->b_name->tp); ccc: { Ptable tbl = cl->memtbl; Pname m; if (cl->clbase) list_check(nn,cl->clbase->tp,0); for (m=tbl->get_mem(i=1); m; m=tbl->get_mem(++i)) { Ptype mt = m->tp; switch (mt->base) { case FCT: case OVERLOAD: case CLASS: case ENUM: continue; } if (m->n_stclass == STATIC) continue; /* check assignment to next member */ dd: e = next_elem(); if (e == 0) return; //break; mtz: //error('d',"mtz%n: %d",m,mt->base); switch (mt->base) { case TYPE: mt = Pbase(mt)->b_name->tp; goto mtz; case CLASS: case ENUM: break; case VEC: case COBJ: list_check(nn,m->tp,e); break; default: if (e == (Pexpr)1) { error("unXIrL"); goto dd; } if (mt->check(e->tp,ASSIGN)) error("badIrT for%n:%t (%tX)",m,e->tp,m->tp); } } if (lst && (e=next_elem()) ) error("end ofIrLX afterCO"); break; } default: e = next_elem(); if (e == 0) { error("noIr forO"); break; } if (e == (Pexpr)1) { error("unXIrL"); break; } if (t->check(e->tp,ASSIGN)) error("badIrT for%n:%t (%tX)",nn,e->tp,t); if (lst && (e=next_elem()) ) error("end ofIrLX afterO"); break; } }
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; }
Ptype np_promote(TOK oper, TOK r1, TOK r2, Ptype t1, Ptype t2, TOK p, bit perr) /* an arithmetic operator "oper" is applied to "t1" and "t2", types t1 and t2 has been checked and belongs to catagories "r1" and "r2", respectively: A ANY Z ZERO I CHAR, SHORT, INT, LONG, LLONG, FIELD, or EOBJ F FLOAT DOUBLE LDOUBLE P PTR (to something) or VEC (of something) test for compatability of the operands, if (p) return the promoted result type */ { if (r2 == 'A') return t1; switch (r1) { case 'A': return t2; case 'Z': switch (oper) { case ASMOD: case ASAND: case ASOR: case ASLS: case ASRS: case ASPLUS: case ASMINUS: return any_type; } switch (r2) { case 'Z': return int_type; case 'F': switch (oper) { case MOD: case AND: case ER: case OR: case LS: case RS: return any_type; } // no break case 'I': switch (oper) { case DEREF: return any_type; case LS: // result type is that of promoted left op case RS: return int_type; } return (p) ? Pbase(t2->skiptypedefs())->arit_conv(0) : 0; case 'P': switch (oper) { case MOD: case AND: case ER: case OR: case LS: case RS: case GE: case GT: case LE: case LT: return any_type; case PLUS: case ASPLUS: if(t2!=Pvoid_type) break; case EQ: case NE: case QUEST: break; default: return any_type; } return t2; case FCT: switch (oper) { case QUEST: return any_type; case EQ: case NE: return t2; } if(perr) error("zero%kF",oper); return any_type; default: error('i',"zero(%d)",r2); } case 'I': switch (r2) { case 'Z': t2 = 0; switch (oper) { case DEREF: return any_type; } return (p) ? Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2)) : 0; case 'F': switch (oper) { case MOD: case AND: case ER: case OR: case LS: case RS: case ASMOD: case ASAND: case ASOR: case ASLS: case ASRS: return any_type; } // no break; case 'I': switch (oper) { case DEREF: return any_type; case LS: // result type is that of promoted left op case RS: return (p) ? Pbase(t1->skiptypedefs())->arit_conv(Pbase(0)) : 0; } return (p) ? Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2)) : 0; case 'P': switch (oper) { case DEREF: break; case PLUS: case ASPLUS: if(t2!=Pvoid_type) break; default: if(perr) error("int%kP",oper); return any_type; } return t2; case FCT: if(perr) error("int%kF",oper); return any_type; default: error('i',"int(%d)",r2); return any_type; } case 'F': switch (oper) { case MOD: case ASMOD: case AND: case ER: case OR: case ASAND: case ASOR: case LS: case RS: case ASLS: case ASRS: return any_type; } switch (r2) { case 'Z': t2 = 0; case 'I': case 'F': if(oper==DEREF) return any_type; return (p) ? Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2)) : 0; case 'P': if(perr) error("float%kP",oper); return any_type; case FCT: if(perr) error("float%kF",oper); return any_type; default: error('i',"float(%d)",r2); return any_type; } case 'P': switch(oper) { case LS: case RS: case ASLS: case ASRS: case MOD: case ASMOD: case ER: case OR: case ASOR: case AND: case ASAND: case DIV: case MUL: return any_type; } switch (r2) { case 'Z': switch (oper) { case GE: case GT: case LE: case LT: return any_type; } return t1; case 'I': switch (oper) { case DEREF: case PLUS: case MINUS: case ASPLUS: case ASMINUS: if (t1->check(Pvoid_type,0)==0) { return any_type; } break; default: if(perr) error("P%k int",oper); return any_type; } return t1; case 'F': if(perr) error("P%k float",oper); return any_type; case 'P': if (t1->check(t2,ASSIGN)) { Ptype tt1 = t1->is_ptr()->typ->skiptypedefs(); Ptype tt2 = t2->is_ptr()->typ->skiptypedefs(); switch (oper) { case EQ: case NE: case LE: case GE: case GT: case LT: case MINUS: case QUEST: if (tt1 && tt2 && tt1->base==COBJ && tt2->base==COBJ ) { Pclass c1=tt1->classtype(); Pclass c2=tt2->classtype(); if (c1 && c2 && c1->baseof(c2) || c2->baseof(c1) ) goto zz; } if (t2->check(t1,ASSIGN) == 0) { if (oper == QUEST) return t2; goto zz; } break; case REFMUL: { Pname cn = tt1->is_cl_obj(); if (cn && tt2->base == FCT && same_class(Pclass(cn->tp),Pfct(tt2)->memof) ) return t2; } } if(perr) error("T mismatch:%t %k%t",t1,oper,t2); return any_type; } zz: switch (oper) { case MINUS: return (t2!=Pvoid_type) ? int_type : any_type; case ASMINUS: if(perr) error("P -=P"); return any_type; case PLUS: if(perr) error("P +P"); return any_type; case ASPLUS: if(perr) error("P +=P"); return any_type; case MOD: case ASMOD: case AND: case ER: case OR: case ASAND: case ASOR: case ASLS: case ASRS: case LS: case RS: case DEREF: return any_type; default: return t1; } case FCT: return t1; default: error('i',"P(%d)",r2); } case FCT: if(oper == QUEST) { switch (r2) { case 'Z': return any_type; case 'P': return t2; case 'I': case 'F': if(perr) error("F%k%t",oper,t2); default: return t1; } } if(Pfct(t1)->memof && r2=='P' && t2->memptr()) return t2; if((oper == EQ || oper == NE) && r2=='Z') return t1; if(perr) error("F%k%t",oper,t2); return any_type; default: error('i',"np_promote(%d,%d)",r1,r2); return 0; } }
Pclass type::classtype() { return (base==COBJ)?Pclass(Pbase(this)->b_name->tp) : (error('i',"T::classtype(): %k cobjX",base),Pclass(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; }
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; }