/* @(#) dcl2.c 1.5 3/15/85 17:04:20 */ /************************************************************************** C++ source for cfront, the C++ compiler front-end written in the computer science research center of Bell Labs Copyright (c) 1984 AT&T Technologies, Inc. All rigths Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T TECHNOLOGIES, INC. If you ignore this notice the ghost of Ma Bell will haunt you forever. dcl2.c: *************************************************************************/ #include "cfront.h" #include "size.h" Pname classdef.has_ictor() /* does this class have a constructor taking no arguments? */ { Pname c = has_ctor(); Pfct f; Plist l; if (c == 0) return 0; f = (Pfct)c->tp; switch (f->base) { default: error('i',"%s: bad constructor (%k)",string,c->tp->base); case FCT: switch (f->nargs) { case 0: return c; default: if (f->argtype->n_initializer) return c; } return 0; case OVERLOAD: for (l=((Pgen)f)->fct_list; l; l=l->l) { Pname n = l->f; f = (Pfct)n->tp; switch (f->nargs) { case 0: return n; default: if (f->argtype->n_initializer) return n; } } return 0; } } gen.gen(char* s) { char * p = new char[ strlen(s)+1 ]; base = OVERLOAD; strcpy(p,s); string = p; fct_list = 0; } Pname gen.add(Pname n,int sig) /* add "n" to the tail of "fct_list" (overloaded names are searched in declaration order) detect: multiple identical declarations declaration after use multiple definitions */ { Pfct f = (Pfct)n->tp; Pname nx; if (f->base != FCT) error(0,"%n: overloaded non-F",n); if ( fct_list && (nx=find(f)) ) { //error('d',"add old %n",nx); /* Pfct nf = (Pfct)nx->tp; if (nf->body) { if (f->body) error("two definitions for overloaded%n",n); } else { if (f->body) nf->body = f->body; } */ Nold = 1; } else { char* s = string; //error('d',"add new %s",s); if (fct_list || sig || n->n_oper) { char buf[128]; char* bb = n->tp->signature(buf); int l1 = strlen(s); int l2 = bb-buf-1; char* p = new char[l1+l2+1]; strcpy(p,s); strcpy(p+l1,buf); n->string = p; } else n->string = s; nx = new name; *nx = *n; PERM(nx); Nold = 0; if (fct_list) { Plist gl; for (gl=fct_list; gl->l; gl=gl->l) ; gl->l = new name_list(nx,0); } else fct_list = new name_list(nx,0); nx->n_list = 0; } return nx; } 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 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&(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 (bcl->csu == STRUCT) pubbase = 1; if (in_union) error("derived union"); else csu = (pubbase) ? bcl->csu : CLASS; boff = bcl->real_size; max_align = bcl->align(); } 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; } memtbl->set_scope(tbl); memtbl->set_name(cname); if (nmem) memtbl->grow((nmem<=2)?3:nmem); cc->stack(); cc->not = cname; cc->cot = this; 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 += SZ_WORD; real_size = byte_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; if ( (ct || dt || un) && ( (cn=t->is_cl_obj()) || (cn=cl_obj_vec) ) ) { Pclass cl = (Pclass)cn->tp; 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 && has_ctor()==0) { // make a constructor for the class: x::x() {} 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 enumdef.dcl(Pname, Ptable tbl) { #define FIRST_ENUM 0 int nmem = mem->no_of_names(); Pname p; Pname ns = 0; Pname nl; int enum_old = enum_count; no_of_enumerators = nmem; enum_count = FIRST_ENUM; if (this == 0) error('i',"0->enumdef.dcl(%d)",tbl); for(p=mem, mem=0; p; p=p->n_list) { Pname nn; if (p->n_initializer) { Pexpr i = p->n_initializer->typ(tbl); Neval = 0; enum_count = i->eval(); if (Neval) error("%s",Neval); DEL(i); p->n_initializer = 0; } p->n_evaluated = 1; p->n_val = enum_count++; nn = tbl->insert(p,0); /* ??? */ if (Nold) { if (nn->n_stclass == ENUM) { if (p->n_val != nn->n_val) error("twoDs of enum constant %n",nn); else goto lnk; } else error("incompatibleDs of%n",nn); } else { nn->n_stclass = ENUM; /* no store will be allocated */ lnk: if (ns) nl->n_list = nn; else ns = nn; nl = nn; } delete p; } mem = ns; enum_count = enum_old; defined |= DEFINED; } Pstmt curr_loop; Pstmt curr_switch; Pblock curr_block; void stmt.reached() { register Pstmt ss = s_list; if (ss == 0) return; switch (ss->base) { case LABEL: case CASE: case DEFAULT: break; default: error('w',"statement not reached"); /* delete unreacheable code */ for (; ss; ss=ss->s_list) { switch (ss->base) { case LABEL: case CASE: case DEFAULT: /* reachable */ s_list = ss; return; case IF: case DO: case WHILE: case SWITCH: case FOR: case BLOCK: /* may hide a label */ s_list = ss; return; } } s_list = 0; } } bit arg_err_suppress; Pexpr check_cond(Pexpr e, TOK b, Ptable) { 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%k expression",cn,b); return e; case 1: { /*error('d',"cond%t<-%t",((Pfct)found->tp)->returns,e->tp);*/ Pclass cl = (Pclass)cn->tp; Pref r = new ref(DOT,e,found); Pexpr c = new expr(G_CALL,r,0); c->fct_name = found; c->tp = ((Pfct)found->tp)->returns; return c; } default: error("%d possible conversions for%nO in%k expression",i,cn,b); return e; } } e->tp->num_ptr(b); return e; } 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 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 error('w',"result of%kE not used",ss->e->base); 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: 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 case expression",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); switch (ee->tp->base) { case INT: case ZTYPE: { int i; Neval = 0; i = ee->eval(); if (Neval == 0) { /*fprintf(stderr,"if (%d) %d %d\n",i,ss->e,ss->e->base);*/ 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",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++; 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; Pexpr in = nn->n_initializer; //error('d',"in %d",in); if (in && non_trivial == 0) non_trivial = 1; if (nn->n_stclass==STATIC) { non_trivial = 2; continue; } if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } 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; Pexpr in = nn->n_initializer; if (non_trivial == 0) non_trivial = 1; if (nn->n_stclass==STATIC) { non_trivial = 2; continue; } if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } 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",nn,tbl,n,n->n_initializer,sss);*/ 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 block.dcl(Ptable tbl) /* Note: for a block without declarations memtbl denotes the table for the enclosing scope. A function body has its memtbl created by fct.dcl(). */ { int bit_old = bit_offset; int byte_old = byte_offset; int max_old = max_align; Pblock block_old = curr_block; if (base != BLOCK) error('i',"block.dcl(%d)",base); curr_block = this; if (d) { Pname n; own_tbl = 1; if (memtbl == 0) { int nmem = d->no_of_names()+4; memtbl = new table(nmem,tbl,0); memtbl->real_block = this; /* this is a "real" block from the source text, and not one created by DCL's inside a block. */ } else if (memtbl != tbl) error('i',"block.dcl(?)"); Pname nx; for (n=d; n; n=nx) { nx = n->n_list; n->dcl(memtbl,FCT); switch (n->tp->base) { case CLASS: case ANON: case ENUM: break; default: delete n; } } } else memtbl = tbl; if (s) { Pname odcl = Cdcl; Pname m; int i; s->dcl(); if (own_tbl) for (m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i)) { Ptype t = m->tp; if (t == 0) { if (m->n_assigned_to == 0) error('w',"undefined label %s",m->string); if (m->n_used == 0) error('w',"label %s not used", m->string); continue; } ll: switch (t->base) { case TYPE: t=((Pbase)t)->b_name->tp; goto ll; case CLASS: case ENUM: case FCT: case VEC: continue; } if (m->n_addr_taken == 0) { if (m->n_used) { if (m->n_assigned_to) { } else { switch (m->n_scope) { case FCT: Cdcl = m; error('w',"%n used but not set",m); } } } else { if (m->n_assigned_to) { } else { switch (m->n_scope) { case ARG: if (m->string[0]=='_' && m->string[1]=='A') break; /* generated name: cannot be used */ case FCT: Cdcl = m; error('w',"%n not used",m); } } } } } Cdcl = odcl; } d = 0; if (bit_offset) byte_offset += SZ_WORD; if (stack_size < byte_offset) stack_size = byte_offset; bit_offset = bit_old; byte_offset = byte_old; curr_block = block_old; } int name.no_of_names() { register int i = 0; register Pname n; for (n=this; n; n=n->n_list) i++; return i; } static Pexpr lvec[20], *lll; static Pexpr list_back = 0; #define list_put_back(x) list_back = x; void new_list(Pexpr lx) { if (lx->base != ILIST) error('i',"IrLX"); lll = lvec; lll++; *lll = lx->e1; } Pexpr next_elem() { Pexpr e; Pexpr lx; if (lll == lvec) return 0; lx = *lll; if (list_back) { e = list_back; list_back = 0; return e; } if (lx == 0) { /* end of list */ lll--; return 0; } switch (lx->base) { case ELIST: e = lx->e1; *lll = lx->e2; switch (e->base) { case ILIST: lll++; *lll = e->e1; return (Pexpr)1; /* start of new ILIST */ case ELIST: error("nestedEL"); return 0; default: return e; } default: error('i',"IrL"); } } 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; 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: 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 of IrLX after vector"); xsw:; } else { /* determine v->size */ i = 0; xx: while ( e=next_elem() ) { /* get another initializer */ i++; vtzz: 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) break; mtz: 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 %s .%n:%t (%tX)",cl->string,m,e->tp,m->tp); } } if (lst && (e = next_elem()) ) error("end of IrLX afterO"); 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 of IrLX afterO"); break; } }