/*ident "@(#)cls4:src/norm.c 1.12" */ /******************************************************************************* C++ source for the C++ Language System, Release 3.0. This product is a new release of the original cfront developed in the computer science research center of AT&T Bell Laboratories. Copyright (c) 1993 UNIX System Laboratories, Inc. Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc. Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System Laboratories, Inc. The copyright notice above does not evidence any actual or intended publication of such source code. norm.c: "normalization" handles problems which could have been handled by the syntax analyser; but has not been done. The idea is to simplify the grammar and the actions accociated with it, and to get a more robust error handling ****************************************************************************/ #include "cfront.h" #include "size.h" #include "template.h" //SYM -- table defs Pktab Gtbl; Pktab Ctbl; Pname sta_name = 0; static Ptype generic_tpdef = 0; void syn_init() { generic_tpdef = new type; generic_tpdef->base = TPDEF; PERM(generic_tpdef); any_type = new basetype(ANY,0); PERM(any_type); any_type->defined = DEFINED; dummy = new expr(DUMMY,0,0); PERM(dummy); dummy->tp = any_type; zero = new expr(ZERO,0,0); PERM(zero); sta_name = new name; PERM(sta_name); //SYM -- init new tables Gtbl = new ktable(GTBLSIZE,0,0); //SYM Ctbl = Gtbl; //SYM } int stcount; char* make_name(TOK c) { char* s = new char[8]; // as it happens: fits in two words if (10000 <= ++stcount) error('i',"too many generatedNs"); sprintf(s,"__%c%d",c,stcount); return s; } Pbase basetype::type_adj(TOK t) { DB(if(Ndebug>=1)error('d',"'%k'->type_adj(%k) --%t b_xname%n",base,t,this,b_xname);); if (b_xname) { if (base) error("badBT:%n%k",b_xname,t); else { base = TYPE; b_name = b_xname; } b_xname = 0; } switch (t) { case TYPEDEF: if(b_typedef) error('w',"two typedefs"); else if(b_inline) { error("badBT:%k and%k",INLINE,TYPEDEF); b_typedef=0; } else b_typedef = 1; break; case INLINE: if(b_inline) error('w',"two inlines"); else if(b_typedef) { error("badBT:%k and%k",TYPEDEF,INLINE); b_inline=0; } else b_inline = 1; break; case VIRTUAL: b_virtual = 1; break; case CONST: if (b_const) error('w',"two const declarators"); b_const = 1; break; case UNSIGNED: b_unsigned = 1; break; case SHORT: b_short = 1; break; case LONG: #ifdef VL if (b_long) base = VLONG; else #endif if (base == DOUBLE) base = LDOUBLE; else b_long = 1; break; case FRIEND: case OVERLOAD: case EXTERN: case STATIC: case AUTO: case REGISTER: if (b_sto) error("badBT:%k%k",b_sto,t); else b_sto = t; break; case DOUBLE: if (b_long) { t = LDOUBLE; b_long = 0; } // no break case VOID: case CHAR: case INT: case FLOAT: if (base) error("badBT:%k%k",base,t); else base = t; break; case SIGNED: case VOLATILE: error('w',"\"%k\" not implemented (ignored)",t); break; default: error('i',"BT::type_adj(%k)",t); } return this; } Pbase basetype::name_adj(Pname n) { DB(if(Ndebug>=1)error('d',"'%k'->name_adj(%n) --%t b_xname%n",base,n,this,b_xname)); if (b_xname) { if (base) error("badBT:%n%n",b_xname,n); else { base = TYPE; b_name = b_xname; } b_xname = 0; } if ( base==0 && n->base == TNAME && ( n->tp->base!=COBJ //SYM || in_arg_list )) { || Ctbl->k_id==ARG )) { base = TYPE; b_name = n; } else b_xname = n; return this; } static TOK type_set( Pbase b ) { TOK t = 0; if ( b->b_vlong ) t = VLONG; else if ( b->b_long ) t = LONG; else if ( b->b_short ) t = SHORT; else if ( b->b_unsigned ) t = UNSIGNED; else if ( b->b_inline ) t = INLINE; else if ( b->b_virtual ) t = VIRTUAL; else if ( b->b_sto == OVERLOAD ) t = OVERLOAD; return t; } int declTag = 1; Pbase basetype::base_adj(Pbase b) { DB(if(Ndebug>=1)error('d',"'%k'->base_adj(%t) --%t b_xname%n",base,b,this,b_xname)); Pname bn = b->b_name; switch (base) { case COBJ: case EOBJ: error("NX after%k%n",base,b_name); return this; } TOK t; if (base) { if (b_name) error("badBT:%k%n%k%n",base,b_name,b->base,bn); else error("badBT:%k%k%n",base,b->base,bn); } else if ( t = type_set(this)) { if (b_name) error("badBT:%k%n%k%n",t,b_name,b->base,bn); else { if ( declTag++ && !(t==INLINE && b->base==EOBJ)) error("badBT:%k%k%n",t,b->base,bn); base=b->base; b_name = bn; // error('d',"base_adj: t: %k", t ); } } else { base = b->base; b_name = bn; b_table = b->b_table; } return this; } Pbase basetype::check(Pname n) /* "n" is the first name to be declared using "this" check the consistency of "this" and use "b_xname" for "n->string" if possible and needed */ { b_inline = 0; b_virtual = 0; //error('d',"basetype::check(%n) base %k b_xname %n",n,base,b_xname); if (b_xname && (n->tp || n->string)) { if (base) error("badBT:%k%n",base,b_xname); else { base = TYPE; b_name = b_xname; } b_xname = 0; } if (b_xname) { if (n->string) error("twoNs inD:%n%n",b_xname,n); else { n->string = b_xname->string; b_xname->hide(); //SYM? } b_xname = 0; } if (ccl==0 && n && n->n_oper==TNAME && !in_typedef && n->n_qualifier==0 && n->string) { // hide type name Pname nx = k_find_name(n->string,Ctbl,0); //SYM if (nx && nx->base==TNAME) nx->hide(); } int defa = 0; switch (base) { case 0: defa = 1; base = INT; break; case EOBJ: case COBJ: if (b_name->base == TNAME) error('i',"TN%n inCO %p",b_name,this); } if (b_long || b_short || b_vlong) { // FIXME: long long TOK vsl; if (b_long) vsl = LONG; if (b_short) vsl = SHORT; if (b_vlong) vsl = VLONG; if ((b_long && b_short) || (b_long && b_vlong) || (b_short && b_vlong)) error("badBT:long short%k%n",base,n); #ifndef VL if (base != INT) error("badBT:%k%k%n",vsl,base,n); else #endif base = vsl; b_short = b_long = b_vlong = 0; } if (b_typedef && b_sto) error("badBT:Tdef%k%n",b_sto,n); b_typedef = b_sto = 0; if (b_linkage) { if (1 <= bl_level) error("local linkage directive"); } if (Pfctvec_type == 0) return this; if (b_const) { if (b_unsigned) { switch (base) { default: error("badBT: unsigned const %k%n",base,n); b_unsigned = 0; case VLONG: case LONG: case SHORT: case INT: case CHAR: return this; } } return this; } else if (b_unsigned) { switch (base) { case VLONG: delete this; return uvlong_type; case LONG: delete this; return ulong_type; case SHORT: delete this; return ushort_type; case INT: delete this; return uint_type; case CHAR: delete this; return uchar_type; default: error("badBT: unsigned%k%n",base,n); b_unsigned = 0; return this; } } else { switch (base) { case VLONG: delete this; return vlong_type; case LONG: delete this; return long_type; case SHORT: delete this; return short_type; case INT: if (this==int_type || this==defa_type) return this; delete this; if (defa) return defa_type; return int_type; case CHAR: delete this; return char_type; case VOID: delete this; return void_type; case TYPE: /* use a single base saved in the keyword */ if (b_name->n_qualifier) { Pbase rv = Pbase(b_name->n_qualifier); delete this; return rv; } else { PERM(this); b_name->n_qualifier = (Pname)this; return this; } default: return this; } } } static int check_redef( Pname on, Pname nn ) { // nn is a new typedef // on was returned from insert_type() // check for conflicts // return 1 for duplicate def, else 0 if (Nold) { //SYM type name was already in symbol table //error('d',"'%n'->tdef() -- redef%t,%t",on,on->tp,nn->tp); //error('d'," -- nn->base%k, on->base%k, nn->n_oper%k, on->n_key%k",nn->base,on->base,nn->n_oper,on->n_key); if ( on->tp->check(nn->tp,0) == 0 ) { // duplicate typedef nn->base = TNAME; return 1; // avoid infinite loop for typedef I I; } if ( nn->tpdef->in_class && nn->tpdef->in_class->csu == ANON ) { if ( nn->tpdef->defined == 0 ) error(&nn->where,"twoDs of %s (one in anonymous union)",nn->string); } else if ( on->tpdef ) error(&nn->where,"%n redefined:Tdef%t andTdef%t",on,on->tp,nn->tp); else error(&nn->where,"%n redefined:%t andTdef%t",on,on->tp,nn->tp); // kluge: avoid printing error twice for nested anon nn->tpdef->defined = 1; Pname nw = new name; Pname x = on; x->n_key = VOID; // anything to get rid of it *nw = *nn; nw->n_tbl_list = 0; nw->n_ktable = 0; nw->n_table = 0; on = insert_type(nw,Ctbl,TYPE); if ( Nold ) error('i',&nn->where,"cannot recover"); on->n_hidden = x; } if ( on->n_key == HIDDEN ) { if ( nn->tpdef->in_class && nn->tpdef->in_class->csu == ANON ) { if ( nn->tpdef->defined == 0 ) error(&nn->where,"twoDs of %s (one in anonymous union)",nn->string); } else error(&nn->where,"%n redefined: identifier andTdef",on); // kluge: avoid printing error twice for nested anon nn->tpdef->defined = 1; } return 0; } Pname basetype::aggr() /* "type SM" seen e.g. struct s {}; class x; enum e; int tname; friend cname; friend class x; int; typedef int i; // where i is tname convert union { ... }; into union name { ... } name ; */ { DB(if(Ndebug>=1)error('d',"'%k'->aggr() --%t b_xname%n ccl%t",base,this,b_xname,ccl)); if (b_xname) { if (base) { Pname n = new name(b_xname->string); //b_xname->hide();//SYM? b_xname = 0; return n->normalize(this,0,0); } else { base = TYPE; b_name = b_xname; b_xname = 0; } } switch (base) { case COBJ: { Pclass cl = Pclass(b_name->tp); char* s = cl->string; /*SYM?*/if (cl->class_base != CL_TEMPLATE && (cl->in_class == 0 || cl->in_class->class_base != CL_TEMPLATE) && b_name->base == TNAME) error('i',"TN%n inCO",b_name); if (b_const) error("const%k%n",cl->csu,b_name); if (cl->c_body == 2) { /* body seen */ if (s[0]=='_' && s[1]=='_' && s[2]=='C') { char* ss = new char[8]; // max size of generated name is 7 chars, see make_name() Pname obj = new name(ss); strcpy(ss,s); if (cl->csu==UNION && cl->class_base!=CL_TEMPLATE) { ss[2] = 'O'; cl->csu = ANON; Pname un = obj->normalize(this,0,0); //SYM -- export anon union names //SYM to current table int i = 1; Pname nn=cl->k_tbl->get_mem(i); for (; nn; NEXT_NAME(cl->k_tbl,nn,i)) { if ( nn->string==0 ) continue; if ( nn->base == NAME ) { insert_name(new name(nn->string),Ctbl); } else if ( nn->tp == 0 ) { error('i',"BT::aggr(): nullT for%n in anon union",nn); } else { Pname nx = new name(nn->string); nx->tp = nn->tp; nx->tpdef = nn->tpdef; nx->where = nn->where; if ( nn->tpdef ) { nx=insert_type(nx,Ctbl,TYPE); check_redef(nx,nn); } else { switch( nx->tp->base ) { case COBJ: { Pclass mcl = (Pclass)Pbase(nn->tp)->b_name->tp; if ( mcl->csu != ANON && !( mcl->string[0]=='_' && mcl->string[1]=='_' && mcl->string[2]=='C') ) { nx=insert_type(nx,Ctbl,mcl->csu); if ( Nold ) { Pname x = nx->tp->is_cl_obj(); Pclass ocl = x?Pclass(x->tp):0; if ( ocl==0 || strcmp(ocl->string,mcl->string) || (ocl->defined&(DEF_SEEN|DEFINED)) && (mcl->defined&(DEF_SEEN|DEFINED)) ) error(&nn->where,"twoDs of %s (one in anonymous union)",nn->string); else if ( mcl->defined&(DEF_SEEN|DEFINED) ) nx->tp = nn->tp; } } } break; case EOBJ: if ( nn->string[0] == '_' && nn->string[1] == '_' && nn->string[2] == 'E' ) break; nx=insert_type(nx,Ctbl,ENUM); if ( Nold ) { Ptype t = nx->tp->skiptypedefs(); Penum oe = t->base==EOBJ ? (Penum)Pbase(t)->b_name->tp : 0; t = nn->tp->skiptypedefs(); Penum ne = t->base==EOBJ ? (Penum)Pbase(t)->b_name->tp : 0; if ( oe==0 || strcmp(oe->string,ne->string) || (oe->defined&(DEF_SEEN|DEFINED)) && (ne->defined&(DEF_SEEN|DEFINED)) ) error(&nn->where,"twoDs of %s (one in anonymous union)",nn->string); else if ( ne->defined&(DEF_SEEN|DEFINED) ) nx->tp = nn->tp; } break; default: error('i',&nn->where,"missing tpdef forTdefN %s",nx->string); } // switch } // else tag //error('d',&nn->where,"exportingTN %n%t",nx,nx->tp); } // else TNAME } // for nn return un; } if (cl->class_base!=CL_TEMPLATE) error('w',"unusable%k ignored",cl->csu); } if ( b_sto == FRIEND ) error("friend%k%n{...} -- may only declare a friendC",cl->csu,b_name); cl->c_body = 1; return b_name; } else { /* really a typedef for cfront only: class x; */ if (b_sto == FRIEND) goto frr; Pname nn = new name(cl->string); nn->tp = b_name->tp; nn->n_key = REF; return nn; } } case EOBJ: { Penum en = Penum(b_name->tp); /*SYM?*/if (b_name->base == TNAME) error('i',"TN%n in enumO",b_name); if (b_const) error("const enum%n",b_name); if (en->e_body == 2) { en->e_body = 1; return b_name; } else { error("forwardD of enum%n", b_name); en->e_type = int_type; } return 0; } case 0: { Pname n = new name(make_name('D')); n->tp = defa_type; error("NX inDL"); return n; } default: if (b_typedef) error('w',"illegalTdef ignored"); if (b_sto == FRIEND && b_name ) { frr: // see also name::normalize(), stc == FRIEND Pname fr = k_find_name(b_name->string,Ctbl,0); //SYM if (fr == 0 || fr->base!=TNAME) error('i',"cannot find friend%n",b_name); Pname n = new name(b_name->string); n->n_sto = FRIEND; // If it is a parameterized type, use the instantiation // type, not the general type. if ((fr->tp->base == COBJ) && (Pclass(Pbase(fr->tp)->b_name->tp)->class_base == CL_TEMPLATE)) { if (base == COBJ) n->tp = this; else if ((base == TYPE) && (Pbase(this)->b_name->base == TNAME) && (Pbase(this)->b_name->tp->base == COBJ)) n->tp = Pbase(this)->b_name->tp; else error('i', "basetype wasn't a COBJ"); } else n->tp = fr->tp; return n; } else { Pname n = new name(make_name('D')); n->tp = defa_type; error("NX inDL"); return n; } } } //SYM -- removed void local_name() //SYM void local_restore() removed //SYM -- local_hide() removed //SYM void nested_restore() removed //SYM nested_hide(Pname) removed //SYM static void nested_hide( Plist l ) removed int defer_check = 0; //SYM removed Pname statStat = 0; void name::hide() /* hide "this": that is, "this" should not be a keyword in this scope */ { if (base != TNAME) return; //error('d',"'%n '->hide() -- %t lex_level %d bl_level %d",this,tp,lex_level,::bl_level); if (n_key == 0) { if (lex_level == bl_level && in_arg_list == 0) { if (tp->base != COBJ) { //error('d',"%n::hide() -- in_typedef base%k %t %t",this,in_typedef->base,tp,in_typedef); if ( in_typedef && in_typedef->base && tp->base != type_set(Pbase(in_typedef)) && in_typedef->check(tp,0) ) { if ( defer_check == 0 ) error("%n redefined: previous: %t now: %t", this, tp, in_typedef); } } else { //error('d',"in_typedef%t %d tp%t %d",in_typedef,in_typedef,tp,tp); //error('d',"in_typedef%k tp%k",in_typedef->base,tp->base); if ( in_typedef && in_typedef->base && in_typedef->check(tp, 0) ) { if ( defer_check == 0 ) error( "%n redefined: previous: %t now: %t", this, tp, in_typedef); } else { Pname nn = Pbase(tp)->b_name; Pclass cl = Pclass( nn->tp ); // check for 'typedef class X X;' // and 'typedef X X;' if ( in_typedef ) while ( in_typedef->base == TYPE ) in_typedef = Pbase(in_typedef)->b_name->tp; if ( in_typedef && in_typedef->base==COBJ && same_class(Pclass(Pbase(in_typedef)->b_name->tp),cl) ) in_typedef = tp; else if ( cl->has_ctor() ) error( "%n redefined: both aCNWK and %s", this, in_typedef?"a type name":"an identifier" ); } } } // error( 'd', "%n::hide", this ); if ( n_table == 0 ) { // error('d',"templp: in progress: %d", templp->in_progress); Pclass cl = 0; if ( tp->base == COBJ ) cl = tp->classtype(); if ( n_template_arg == template_type_formal && templp->in_progress ) error('s',"reuse of formalYZ%n",this); else if ( cl && (cl->class_base == INSTANTIATED || cl->class_base == UNINSTANTIATED )) error("illegal use of instantiatedYC%t", cl); else error('i',"%n->hide() -- no n_table",this); } insert_name( new name(string), Ctbl ); } } //SYM removed Ntncheck, notReally //SYM void set_scope(Pname tn) removed //SYM void restore() removed int classid; // index of generated class names // saved and reset by grammer at start of each class def // so nested tag indices will be relative // -- ensures link compatibility for static member anon unions Pname start_cl(TOK t, Pname c, Pbcl b) { int mk_local = 0; DB( if(Ndebug>=1) error('d',"start_cl(%k,%n,%d) ll %d",t,c,b,c?c->lex_level:0); ); if (c == 0) { int save = stcount; stcount = classid++; c = new name(make_name('C')); stcount = save; c->lex_level -= in_class_decl + 1; if ( in_typedef && c->lex_level ) mk_local = 1; //SYM else c->lex_level = 0; } else if ( ccl && ccl->lex_level == c->lex_level && strcmp(ccl->string,c->string) == 0) { error("%k %s redefines enclosing class",t,c->string); error('i', "can't recover from previous errors"); } Pname n = c->tname(t); /* t ignored */ n->where = curloc; Pbase bt = Pbase(n->tp); /* COBJ */ if (bt->base != COBJ) { error("twoDs of%n:%t andC",n,bt); error('i', "can't recover from previous errors"); } else { if (strcmp(n->string,Pbase(n->tp)->b_name->string)!=0) error("twoDs of %n:Tdef andC",n); if (n->tp->classtype()->csu!=t && (t==UNION || n->tp->classtype()->csu==UNION)) error("twoDs of%n:%k and%k",n,t,n->tp->classtype()->csu); bt->b_name->where = curloc; // line#s in dcl() } //SYM for ( Pclass tc = ccl; tc; tc = tc->in_class ) { //SYM if ( tc->lex_level == c->lex_level // c not local to mem ftn of tc //SYM && strcmp( tc->string, c->string) == 0) { //SYM error( "C %s redefined", c->string ); //SYM error('i', "can't recover from previous errors"); //SYM } // error('d',"ccl: %t bl: %d in_class_decl: %d ccl->lex_level: %d",ccl,bl_level,in_class_decl,ccl?ccl->lex_level:0); // if (templp->in_progress && (c->lex_level == 0)) if (templp->in_progress && (c->lex_level == 0) && (ccl == 0 || (!ccl->in_class && ccl->class_base!=CL_TEMPLATE) || bl_level != ccl->lex_level + in_class_decl + 1 )) // bring the template in scope templp->introduce_class_templ(n); // error('d',"'%n'->start_cl() ll %d",c, c->lex_level); // error('d'," templ %d in_cl %d in_memf %d",templp->in_progress, in_class_decl, in_mem_fct); if ( templp->in_progress && c->lex_level ) { if ( in_class_decl == 0 || in_mem_fct ) if (mk_local==0) error('s',"localC%nWinYF", c); else error('s',"localCWinYF"); } // typedef struct {} x; if ( mk_local ) { local_class = new name_list( n, local_class ); //SYM -- tn stuff removed } Pclass occl = ccl; ccl = Pclass(bt->b_name->tp); /* CLASS */ if (ccl->defined) ccl->defined |= IN_ERROR; ccl->defined |= DEF_SEEN; // error('d', "start_cl: %n ccl->in_class: %t lex_level: %d", n, ccl->in_class, n->lex_level ); ccl->string = n->string; ccl->csu = t; // error('d',"typedef: ccl %t %n", ccl, n); if (occl==0) { // if specialization, ccl->templ_base set within explicit_inst() ccl->templ_base = templp->in_progress ? BOUND_TEMPLATE : ccl->templ_base; } //error('d',"ccl%t %d ll %d %s",ccl,ccl,ccl->lex_level,ccl->k_tbl->whereami()); if (b) { // list of base classes for (Pbcl bx, bb=b, l=0; bb; bb = bx) { bx = bb->next; bb->next = 0; if ( bb->bclass //&& strcmp(ccl->string,bb->bclass->string)==0 && ( ( bb->bclass->nested_sig && ccl->nested_sig && strcmp(ccl->nested_sig, bb->bclass->nested_sig)==0 ) || ( !bb->bclass->nested_sig && !ccl->nested_sig && strcmp(ccl->string, bb->bclass->string)==0 ) ) ) error(&n->where,"%n derived from itself",n); else if (l == 0) l = bb; else { // append and check for duplicates for (Pbcl ll = l;;) { if (bb->bclass && same_class(ll->bclass,bb->bclass)) { error("%s has %s asB twice",ccl->string,bb->bclass->string); break; } if (ll->next) ll = ll->next; else { bb->next = l; l = bb; break; } } } } ccl->baselist = l; //SYM notReally++; set_scope(n); notReally--; } return n; } void end_cl() { if ( templp->parameters_in_progress ) error("definition ofC %tWinY parameterL : %d",ccl,templp->parameters_in_progress); ccl->c_body = 2; // ccl->templ_base may be set within explicit_inst() ccl->templ_base = templp->in_progress ? BOUND_TEMPLATE : ccl->in_class ? ccl->in_class->templ_base : ccl->templ_base; ccl = ccl->in_class; //SYM -- lots of stuff removed } Pbase end_enum(Pname n, nlist* b) { // error( 'd', "end_enum: %n ccl: %t", n , ccl ); bit anon = 0; if (n == 0) { anon = 1; n = new name(make_name('E')); n->lex_level = bl_level - in_class_decl; //SYM } // error('d',"'%n'->end_enum() ll %d",n, n->lex_level); // error('d'," templ %d in_cl %d in_memf %d",templp->in_progress, in_class_decl, in_mem_fct); if ( templp->parameters_in_progress ) error( "definition of enum %sWinY parameterL",anon?"":n->string); if ( templp->in_progress && n->lex_level ) { if ( in_class_decl == 0 || in_mem_fct ) if (anon==0) error('s',"local enum%nWinYF", n); else error('s',"local enumWinYF"); } n = n->tname(ENUM); Pbase bt = (Pbase)n->tp; if (bt->base != EOBJ) { error("twoDs of%n:%t and enum",n,bt); error('i', "can't recover from previous errors"); } bt->b_name->where = curloc; Penum en = (Penum)bt->b_name->tp; en->e_body = 2; en->mem = name_unlist(b); if (en->defined) { // shouldn't be necessary anymore with nested types // if ( in_class_decl ) // error("%n redefined, enum tag not local to class", n); en->defined |= IN_ERROR; } en->defined |= DEF_SEEN; en->templ_base = templp->in_progress ? BOUND_TEMPLATE : en->in_class ? en->in_class->templ_base : en->templ_base; return bt; } Pname name::tdef() /* typedef "this" */ { // error('d',&where,"'%n'->tdef()%t in_typedef %d",this,tp,in_typedef); // error('d',&where," lex_level %d tpdef%d",lex_level,tpdef); // error('d',&where," templ %d in_cl %d in_memf %d",templp->in_progress, in_class_decl, in_mem_fct); //SYM anon_cl removed if (n_qualifier) { error("QdN in typedef",this); n_qualifier = 0; } if (tp == 0) error('i',"Tdef%n tp==0",this); lex_level = bl_level - in_class_decl; if ( ccl && ccl->lex_level == lex_level ) { //error('d',&where,"Tdef%n ccl%t ll %d",this,ccl,lex_level); tpdef = new type; tpdef->base = TPDEF; PERM(tpdef); tpdef->nested_sig = make_nested_name(string,ccl); if ( strcmp(ccl->string,string) == 0 ) { error(&where,"nestedTdef%n redefines immediately enclosingC",this); //SYM lookup mechanism in front end will ignore //SYM members with same name as class } tpdef->in_class = ccl; } else tpdef = generic_tpdef; if ( templp->in_progress && lex_level ) { if ( in_class_decl == 0 || in_mem_fct ) error('s',"localTdef%nWinYF", this); } Pname n; n = insert_type(this,Ctbl,TYPE);//SYM if ( tpdef->in_class ) { // nested typedef // error('d', "*****%s->tdef: %d ccl: %t", string, tpdef, ccl ); //SYM fields copied by insert() if ( tp!=n->tp || tpdef !=n->tpdef ) // error detected below... ; else { n->tpdef->templ_base = templp->in_progress ? BOUND_TEMPLATE : tpdef->in_class->templ_base; } // error('d',"tdef: templ_base: %d", n->tpdef->templ_base); } // else { //SYM removed check for clash w/nested type // } if ( check_redef(n,this) ) return n; n->base = base = TNAME; PERM(n); PERM(tp); if (tp->base == PTR) PERM(Pptr(tp)->typ); if (tp->base == COBJ || tp->base == EOBJ ) { // typedef struct/enum { } s; => struct/enum s {}; Pname b = Pbase(tp)->b_name; if (b->string[0] == '_' && b->string[1] == '_' ) switch ( tp->base ) { case COBJ: { if (b->string[2] == 'C') { Pclass cl = Pclass(b->tp); b->string = n->string; cl->string = n->string; if (!cl->local_sig) cl->c_strlen = strlen(cl->string); } break; } case EOBJ: { if (b->string[2] == 'E') { Penum en = Penum(b->tp); b->string = n->string; en->string = n->string; if (!en->local_sig ) en->e_strlen = strlen(en->string); } } } } DB(if(Ndebug>=1) { error('d',&where,">>'%n'->tdef()%t returning",this,tp); error('d',&where," lex_level %d tpdef%t",lex_level,tpdef); }); return n; } Pname name::tname(TOK csu) /* "csu" "this" seen, return typedef'd name for "this" return (TNAME,x)-tp->(COBJ/EOBJ,y)-b_name->(NAME,z)-tp->(csue) */ { //error('d',"'%n'::tname(%k)",this,csu); char* s = 0; bit nt = 0; switch (base) { case TNAME: return this; case NAME: { Pname tn = insert_type(this,Ctbl,csu);//SYM Pname on = new name; tn->base = TNAME; tn->lex_level = lex_level; //SYM tn->n_list = n_list = 0; n_list = 0; string = tn->string; *on = *this; switch (csu) { case ENUM: tn->tp = new basetype(EOBJ,on); on->tp = new enumdef(0); Penum(on->tp)->string = tn->string; Penum(on->tp)->lex_level = tn->lex_level; Penum(on->tp)->in_class = ccl; Penum(on->tp)->e_strlen = strlen(tn->string); break; case CLASS: case STRUCT: case UNION: on->tp = new classdef(csu); s = Pclass(on->tp)->string = tn->string; Pclass(on->tp)->lex_level = lex_level; //SYM allocate k_tbl here instead of in PUSH_CLAA_SCOPE //SYM to avoid problems with forward refs to template //SYM class defs Pclass(on->tp)->k_tbl = new ktable(0,0,tn); Pclass(on->tp)->k_tbl->k_id = CLASS; Pclass(on->tp)->in_class = ccl; tn->tp = new basetype(COBJ,on); Pbase(tn->tp)->b_table = Pclass(on->tp)->memtbl; Pclass(on->tp)->c_strlen = strlen(tn->string); break; default: error('i',&where,"illegal csu%k for%n in name::tname()",csu,this); } if ( ccl && lex_level == ccl->lex_level ) { on->tp->nested_sig = make_nested_name(string,ccl); if (s) s = on->tp->nested_sig, nt = 1; } else if ( lex_level ) { on->tp->local_sig = make_local_name(on->tp,Ctbl->k_name); if (s) s = on->tp->local_sig; } PERM(tn); PERM(tn->tp); PERM(on); PERM(on->tp); if (s && ansi_opt && !templp->in_progress) fprintf(out_file, "%s %s%s;\n", csu == UNION || csu == ANON ? "union" : "struct", nt ? "__" : "", s); return tn; } default: error('i',"tname(%s %d %k)",string,this,base); return 0; } } int co_hack; 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; bit tpdf; bit inli; bit virt; char * lnkg; DB( if(Ndebug>=1) { error('d',"'%n'::normalize(b%t, bl %d, cast %d)",this,b,bl,Cast); error('d'," tp%k - lex_level %d - bl_level %d",tp?tp->base:0,lex_level,bl_level); }); if (b) { stc = b->b_sto; tpdf = b->b_typedef; inli = b->b_inline; virt = b->b_virtual; lnkg = b->b_linkage; } else { stc = 0; tpdf = 0; inli = 0; virt = 0; lnkg = 0; } if (inli && stc==EXTERN) { error("both extern and inline"); inli = 0; } if ( stc==STATIC && tp && tp->base == FCT && Pfct(tp)->f_const ) error( "%n staticMF cannot be const", this ); if ( stc == FRIEND ) { //error('d',"norm friend%n tp%t b%t",this,tp,b); if ( tp || (b && (b->base || b->b_name || b->b_xname)) ) { // friend dec with type mods -- enter as non type name if ( Ctbl->k_id != CLASS && Ctbl->k_id != TEMPLATE) error("friend%n not inC",this); else if ( n_qualifier == 0 ) { //XXXXX currently enter all unqualified //XXXXX friends in Gtbl //XXXXX Should eventually enter in enclosing //XXXXX scope, however back end currently //XXXXX doesn't support this, due to lack //XXXXX of context info. //XXXXX Commented code below will enter name //XXXXX correctly when back end is brought //XXXXX up to date. //Pktab tb = Ctbl->k_next; //if ( tb->k_id == TEMPLATE ) tb = tb->k_next; //--lex_level; //insert_name(this,tb); lex_level = 0; insert_name(this,Gtbl); } } else { /* 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 examples: typedef void SIG_TYP(int); class x { friend class y; friend z; friend x; // dumb friend int i; // error friend SIG_TYP sigFunc; // subtle friend int f(); friend g(int); }; */ if (n_list) { error("L of friends"); n_list = 0; } //error( 'd', "%n ll: %d", ccl, ccl->lex_level ); lex_level = ccl->lex_level; //SYM k_find_name should have failed for visible tname... Pname nx = k_find_name(string,Ctbl->k_next,0);//SYM if ( nx && nx->base==NAME ) { error(&where,"illegal friendD:F signature required for nonTN%n",nx); nx = nx->n_hidden;//SYM } if ( nx == 0 ) {//SYM //XXXXX currently enter all unqualified //XXXXX friends in Gtbl //XXXXX Should eventually enter in enclosing //XXXXX scope, however back end currently //XXXXX doesn't support this, due to lack //XXXXX of context info. //XXXXX Commented code below will enter name //XXXXX correctly when back end is brought //XXXXX up to date. Pktab otbl = Ctbl; Pclass occl = ccl; if ( Ctbl->k_id != CLASS && Ctbl->k_id != TEMPLATE ) error("friend%n not inC",this); Ctbl = Gtbl; lex_level = 0; ccl = 0; //if ( Ctbl->k_id == CLASS || Ctbl->k_id == TEMPLATE ) { // enter in enclosing scope //Ctbl = Ctbl->k_next; //if (Ctbl->k_id == TEMPLATE) Ctbl = Ctbl->k_next; //lex_level = ccl->lex_level; //ccl = ccl->in_class; //} nx = tname(CLASS); Ctbl = otbl; ccl = occl; } if ( nx->n_key == HIDDEN ) //SYM error('w',"friend%n referring to hiddenTN",this);//SYM //error('d',"friend%n --%k%t tbl %s",nx,nx->base,nx->tp,nx->n_ktable->whereami()); //error('d'," tbase%k",nx->tp->base); n_sto = FRIEND; tp = nx->tp; return this; } } // if friend if (tp // FUDGE: fix the bad grammar && tp->base==FCT && (n_oper==TNAME || Pfct(tp)->returns)) { Pfct f = Pfct(tp); Pfct f2 = Pfct(f->returns); if (f2) { Ptype pt; Ptype t = f2; lxlx: switch (t->base) { case RPTR: case PTR: // x(* p)(args) ? case VEC: // x(* p[10])(args) ? if (pt = Pptr(t)->typ) { if (pt->base == TYPE) { Pptr(t)->typ = 0; b = Pbase(pt); } else { t = pt; goto lxlx; } } goto zse1; case FCT: {// Pexpr e = f2->argtype; Pexpr e = Pfct(f)->argtype; if (e && e->base==ELIST) { // get the real name; fix its type if (e->e2 || e->e1->base!=DEREF) goto zse1; Pexpr ee = e->e1; Ptype t = 0; Ptype tpx; ldld: switch (ee->base) { case DEREF: { Ptype tt = (ee->e2) ? Ptype(new vec(0,ee->e2)) : Ptype (new ptr(PTR,0)); if (t) Pptr(t)->typ = tt; else tpx = tt; t = tt; ee = ee->e1; goto ldld; } case NAME: { Pname rn = Pname(ee); { Pname btn = k_find_name(string,Ctbl,0);//SYM if(btn&&btn->base==NAME)btn=0; b=new basetype(TYPE,btn);//SYM } f->returns = tpx; n_oper = 0; string = rn->string; base = NAME; } } } } } } } zse1: if (b == 0) { error("BTX for %s",string); b = Pbase(defa_type); } 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; if ( !Cast && Pclass(nn->tp)->c_body==2) { /* first occurrence */ //error('d',"%n c_body==2",nn); if ( stc == FRIEND ) { Pclass cl = Pclass(nn->tp); if ( cl->csu == ANON ) error( &nn->where, "friend anonymous union"); else error( &nn->where, "%k%n defined in friendD",cl->csu,nn); } if (tp && tp->base==FCT && co_hack == 0) { error(&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(&this->where,"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 { Penum en = Penum(nn->tp); if ( en->defined == 0 ) error( "forwardD of enum%n", nn ); en->e_type = int_type; nn = this; } break; default: nn = this; } //error('d',&where,"name::normalize: nn%n ll %d nn %d this %d",nn,nn->lex_level,nn,this); Pname nx; Ptype btyp; if(b->base==TYPE && b->b_const) btyp = b->mkconst(); else btyp = b; for (n=this; n; n=nx) { Ptype t = n->tp; nx = n->n_list; n->n_sto = stc; if (n->base == TNAME) error('i',"redefinition ofTN%n",n); if (t == 0) { if (bl == 0) { n->tp = t = btyp; goto skipp; } else { if ( n->base == NAME && n->n_oper ) error(&n->where,"illegalD of%n",n); else error(&n->where,"body of nonF%n",n); t = new fct(0,0,0); } } switch (t->base) { case PTR: case RPTR: n->tp = Pptr(t)->normalize(btyp); break; case VEC: n->tp = Pvec(t)->normalize(btyp); break; case FCT: n->tp = Pfct(t)->normalize(btyp); break; case FIELD: { if (n->string == 0) n->string = make_name('F'); n->tp = t; bit cft = 0; Ptype tb = btyp->skiptypedefs(cft); switch (tb->base) { case CHAR: case SHORT: case LONG: case VLONG: case EOBJ: case INT: // typedef const unsigned cu_int; // struct x { x(); cu_int b1: 2; } Pbase(t)->b_fieldtype = Pbase(tb)->b_unsigned ? uint_type : int_type; Pbase(t)->b_unsigned = Pbase(tb)->b_unsigned; Pbase(t)->b_const = cft; break; case ANY: // error('d',"templp->in_progress %d", templp->in_progress); if (templp->in_progress) // T t : 13; Pbase(t)->b_fieldtype = int_type; break; default: error("non-int field"); n->tp = defa_type; } break; } } skipp: Pfct 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) { // error('d', "%n->normalize: ccl: %t", this, ccl ); if (in_arg_list) { error("Tdef inA list"); continue; } if (n->n_initializer) { error("Ir forTdefN%n",n); n->n_initializer = 0; } n->tdef(); // because do_nl_type() can't call tdef() //SYM removed stuff } continue; } if ( lnkg ) set_linkage(lnkg); f->f_linkage = linkage; if ( lnkg ) set_linkage(0); // wait and call f->sign() after args are checked extern int inline_opt; if (inline_opt) f->f_inline = (bl && strcmp(n->string, "main") ? 1 : 0); else f->f_inline = inli; // f->f_inline = inli; f->f_is_inline = f->f_inline; extern int vcounter; f->f_virtual = virt?(vcounter++,VTOK):0; if (tpdf) { if (f->body = bl) { error("Tdef%n { ... }",n); f->body = bl = 0; } if (n->n_qualifier) { // typedef T x::f(args); // a pointer to member fucntion: // equivalent to typedef T x::(f)(args); f->memof = Pclass(Pbase(n->n_qualifier->tp)->b_name->tp); n->n_qualifier = 0; } n->tdef(); // because do_nl_type() can't call tdef() //SYM removed stuff continue; } if (f->body = bl) continue; /* Check function declarations. Look for class object instantiations 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(); Ptype template_formal_type; bit clob = (cn || cl_obj_vec); if (f->argtype) { /* check argument/initializer list */ Pname nn; for (nn=f->argtype; nn; nn=nn->n_list) { if (nn->base != NAME) { if (!clob) { if ((f->returns->base == TYPE) && (Pbase(f->returns)->b_name->n_template_arg == template_type_formal)) { template_formal_type = f->returns; goto is_obj; } //error(&n->where,"ATX for%n",n); goto zzz; } goto is_obj; } if (nn->tp) goto ok; } if (!clob) { // error("FALX"); goto zzz; } is_obj: /* it was an initializer: expand to constructor */ n->tp = f->returns; if (f->argtype->base != ELIST) f->f_args = f->argtype = (Pname)new expr(ELIST,(Pexpr)f->argtype,0); if ( n->n_initializer ) { error(&n->where,"twoIrs for%n",n); DEL( ((Pexpr)f->argtype) ); f->argtype = 0; } else { n->n_initializer = new texpr(VALUE, cn ? cn->tp : template_formal_type, (Pexpr)f->argtype); } goto ok; zzz: // ctor-style ilitializer for non class object if (f->argtype) { n->tp = f->returns; if (f->argtype->base == ELIST) { if ( f->argtype->e2 == 0 ) { // int i(x) f->argtype = (Pname)f->argtype->e1; } else { // int i( x, y ) error("more than oneA for basicTIr"); for ( Pexpr e = f->argtype; e->e2->e2; e = e->e2 ) e->base = CM; e->base = CM; e->e2 = e->e2->e1; } } if ( n->n_initializer ) { error(&n->where,"twoIrs for%n",n); DEL( ((Pexpr)f->argtype) ); f->argtype = 0; } else { n->n_initializer = (Pexpr)f->argtype; } goto ok; } } else { /* T a(); => function declaration */ /* if (clob) { DEL(n->tp); n->tp = f->returns; } */ } ok: ; } } return nn; } Ptype vec::normalize(Ptype vecof) { Ptype t = typ; typ = vecof; while(vecof->base == TYPE) vecof = Pbase(vecof)->b_name->tp; switch (vecof->base) { case RPTR: error("array ofRs"); break; case FCT: error("array ofFs"); break; case VOID: error("array of void"); break; default: break; } if (t == 0) return this; 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); default: error('i',"bad arrayT(%d)",t->base); return 0; } } Ptype ptr::normalize(Ptype ptrto) { // if (this == 0) error('i',"0->ptr.normalize()"); Ptype t = typ; typ = ptrto; int bc = 0; while (ptrto->base == TYPE) { bc += Pbase(ptrto)->b_const; ptrto = Pbase(ptrto)->b_name->tp; } switch (ptrto->base) { case FCT: if (memof) if (Pfct(ptrto)->memof) { if (!same_class(memof,Pfct(ptrto)->memof)) error("P toMF mismatch: %s and %s",memof->string, Pfct(ptrto)->memof->string); } else Pfct(ptrto)->memof = memof; else memof = Pfct(ptrto)->memof; break; case RPTR: switch (base) { case PTR: error("P toR"); break; case RPTR: error("R toR"); break; } break; case VOID: if(base==RPTR) error("R to void"); break; } if (t == 0) { Pbase b = Pbase(ptrto); if (Pfctvec_type && b_const==0 && b->b_unsigned==0 && b->b_const==0 && bc == 0 && memof==0 && ptname==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; } } return this; } 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); default: error('i',"badPT(%k)",t->base); return 0; } } Ptype fct::normalize(Ptype ret) /* normalize return type */ { //error('d',"%d%t()->norm(%d%t)",returns,returns,ret,ret); register Ptype t = returns; returns = ret; if (argtype && argtype->base==NAME && argtype->n_qualifier) { error("syntax: ANX"); argtype = 0; nargs = 0; nargs_known = 0; } while(ret->base == TYPE) ret = Pbase(ret)->b_name->tp; switch(ret->base) { case VEC: error("F returning array"); break; case FCT: error("F returningF"); //error('d',"t %d%k%t",t,t->base,t); returns = ret = any_type; break; default: break; } if (t == 0) return this; 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); default: error('i',"badFT:%k",t->base); return 0; } } void fct::argdcl(Pname dcl, Pname fn) /* sort out the argument types for old syntax: f(a,b) int a; char b; { ... } beware of f(a) struct s { int a; }; struct s a; */ { Pname n; /*fprintf(stderr,"%d argtype %d %d dcl %d %d\n",this, argtype, argtype?argtype->base:0, dcl, dcl?dcl->base:0); fflush(stderr);*/ switch (base) { case FCT: break; case ANY: return; default: error('i',"fct::argdcl(%d)",base); } if (argtype) { switch (argtype->base) { case NAME: if (dcl) error("badF definition syntax"); for (n=argtype; n; n=n->n_list) { if (n->string == 0) n->string = make_name('A'); } return; case ELIST: // expression list: f(a,b,c) int a; ... { ... } // scan the elist and build a NAME list { Pname tail = 0; n = 0; error(strict_opt?0:'w',&fn->where,"old style definition of%n (anachronism)",fn); for (Pexpr e=Pexpr(argtype); e; e=e->e2) { Pexpr id = e->e1; if (id->base != NAME) { error("NX inAL"); argtype = 0; dcl = 0; break; } Pname nn = new name(id->string); if (n) tail = tail->n_list = nn; else tail = n = nn; } f_args = argtype = n; break; } default: error("ALX(%d)",argtype->base); argtype = 0; dcl = 0; } } else if(nargs_known == ELLIPSIS) { return; } else { nargs_known = 1; nargs = 0; if (dcl) error("ADL forFWoutAs"); return; } // nargs_known = 0; if (dcl) { Pname d; Pname dx; /* for each argument name see if its type is specified in the declaration list otherwise give it the default type */ for (n=argtype; n; n=n->n_list) { char* s = n->string; if (s == 0) { error("AN missing inF definition"); n->string = s = make_name('A'); } else if (n->tp) error("twoTs forA %s",n->string); for (d=dcl; d; d=d->n_list) { if (strcmp(s,d->string) == 0) { if (d->tp && d->tp->base == VOID) { error("voidA%n",d); d->tp = any_type; } n->tp = d->tp; n->n_sto = d->n_sto; d->tp = 0; // now merged into argtype goto xx; } } n->tp = defa_type; xx:; if (n->tp == 0) error("noT for %s",n->string); } /* now scan the declaration list for "unused declarations" and delete it */ for (d=dcl; d; d=dx) { dx = d->n_list; if (d->tp) { /* not merged with argtype list */ /*if (d->base == TNAME) ??? */ switch (d->tp->base) { case CLASS: case ENUM: /* WARNING: this will reverse the order of class and enum declarations */ d->n_list = argtype; f_args = argtype = d; break; default: error("%n inADL not inAL",d); } } } } /* add default argument types if necessary */ for (n=argtype; n; n=n->n_list) { if (n->tp == 0) n->tp = defa_type; nargs++; } } Pname cl_obj_vec; /* set if is_cl_obj() found a array of class objects */ Pname eobj; /* set if is_cl_obj() found an enum */ 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 array 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; if (t == 0) return 0; 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; } } /* //SYM * parsing table lookup */ static int k_has_base( Pclass c1, Pclass c2, TOK& t ) /* true if c2 is an ancestor of c1 * t indicates whether derivation is virtual */ { if ( c1 == 0 || c2 == 0 ) error('i',"k_has_base(%d,%d,...)",c1,c2); for ( Pbcl b = c1->baselist; b; b = b->next ) { TOK v; t = b->base; if ( same_class(b->bclass,c2) ) return 1; if ( k_has_base(b->bclass,c2,v) ) { if ( v==VIRTUAL ) t = VIRTUAL; return 1; } } t = 0; return 0; } static Pname k_find_in_base( char* s, Pclass cl, Pclass &acl, TOK k ) /* find s in class cl or one of its ancestors * (for consistency, may convert to using stuff in find.c...) */ { DB(if(Kdebug>=3)error('d',"k_find_in_base( %s, %t, ...,%k)",s,cl,k);); // look in base classes; check for dominance Pname n = 0; Pname n2 = 0; Pclass ncl = 0, n2cl = 0; // init to avoid warnings for (Pbcl b=cl->baselist; b; b=b->next) { if ( strcmp(s,b->bclass->string) == 0 ) { n = b->bclass->k_tbl->find_cn(s); ncl = b->bclass; } else if ( (n = b->bclass->k_tbl->look(s,0)) != 0 ) ncl = b->bclass; else n = k_find_in_base( s, b->bclass, ncl, k ); if ( n == 0 ) continue; if ( n2 ) { // multiple defs from base classes // Note: error diagnostics for ambiguous // refs are printed by find.c // To print them here would require knowledge of // type/storage class for each name, in addition // to virtual derivation. // This code is only used to select the right name // for parsing purposes and should match the name // selection in find.c. //XXXXX find.c should also be extended to handle member //XXXXX types TOK t; if ( !same_class(ncl,n2cl) ) { // check for dominance //if ( k_has_base(ncl,n2cl,t) ) { // ;// n dominates n2; save n //} else if ( k_has_base(n2cl,ncl,t) ) { // n2 dominates n; discard n n = n2; ncl = n2cl; } } } n2 = n; n2cl = ncl; } if ( n ) { acl = ncl; return n; } acl = n2cl; return n2; } Pname k_find_name(char* s, Pktab tbl, TOK k ) /* parse table lookup */ { recurse: DB(if(Kdebug>=3)error('d',"k_find_name( %s, %s,%k)",s,tbl->whereami(),k);); if ( tbl == 0 ) return 0; Pname n; if ( tbl->k_id == CLASS ) { if ( tbl->k_name == 0 ) error('i',"C table with noN"); if ( strcmp(s,tbl->k_name->string) == 0 ) n = tbl->find_cn(s); else { Pclass cl = tbl->k_name->tp->classtype(); n = cl->k_tbl->look(s,0); } } else n = tbl->look( s, 0 ); if ( n && k == HIDDEN && n->base != TNAME ) n = n->n_hidden; DB(if(Kdebug>=3) { if(n) error('d',"found%n base%k tp%t in %s",n,n->base,n->tp,n->n_ktable->whereami()); else error('d',"%s not found in %s",s,tbl->whereami()); }); if ( n ) return n; // look in enclosing scope // optimization: table::look already looked through containing // blocks and global or first enclosing class scope while ( tbl && tbl->k_id == BLOCK ) tbl = tbl->k_next; if ( tbl == Gtbl ) return 0; if ( tbl->k_id == CLASS ) { if ( tbl->k_name == 0 ) error('i',"C table with noN"); Pclass cl = tbl->k_name->tp->classtype(), acl; n = k_find_in_base(s,cl,acl,k); } else // template/arg ??? n = tbl->look(s,0); if ( n && k == HIDDEN && n->base != TNAME ) n = n->n_hidden; if ( n ) return n; // still failed -- look in next enclosing scope tbl = tbl->k_next; goto recurse; //return tbl ? k_find_name(s,tbl,k) : 0; } Pname k_find_member(char* s, Pclass cl, TOK k ) /* parse table lookup */ { DB(if(Kdebug>=3)error('d',"k_find_member( %s, %s,%k)",s,cl->string,k);); Pktab tbl = cl->k_tbl; Pname n; if ( tbl->k_id != CLASS ) error('i',"C tableX for%t!",cl); if ( strcmp(s,cl->string) == 0 ) n = tbl->find_cn(s); else n = tbl->look(s,0); if ( n && k == HIDDEN && n->base != TNAME ) n = n->n_hidden; DB(if(Kdebug>=3) { if(n) error('d',"found%n base%k tp%t in %s",n,n->base,n->tp,n->n_ktable->whereami()); else error('d',"%s not found in %s",s,tbl->whereami()); }); if ( n ) return n; // look in base classes Pclass acl; n = k_find_in_base(s,cl,acl,k); if ( n && k == HIDDEN && n->base != TNAME ) n = n->n_hidden; DB(if(Kdebug>=3) { if(n) error('d',"found%n base%k tp%t in %s",n,n->base,n->tp,n->n_ktable->whereami()); else error('d',"%s not found in bases of %s",s,tbl->whereami()); }); return n; } //SYM -- table insertion routines... Pname insert_name( Pname nn, Pktab tbl ) /* insert non type name into parsing table */ { DB(if(Kdebug>=2)error('d',"insert_name( nn%n, tbl(%d) %s )",nn,tbl,tbl->whereami());); Pname nx = k_find_name(nn->string,tbl,0); if ( nx && nx->n_ktable == tbl ) { if ( nx->base == TNAME ) { DB(if(Kdebug>=2)error('d'," -- hiding%n tp%t",nx,nx->tp);); if ( nx->tp && nx->tp->base != COBJ && nx->tp->base != EOBJ ) { DB(if(Kdebug>=2)error('d',"hidingTdef%n",nx)); } nx->n_key = HIDDEN; Pname ny = tbl->insert(nn,0); if ( Nold ) error("hiddenTN%n inserted twice",nx); else ny->n_hidden = nx; nx = ny; } else { // non-type name nx already exists in tbl DB(if(Kdebug>=2)error('d'," -- nonTN%n already exists",nx);); ; // error handled later } } else { // nn not in current table Pname ny = tbl->insert(nn,0); if ( nx && nx->base != TNAME ) nx = nx->n_hidden; ny->n_hidden = nx; nx = ny; } return nx; } Pname insert_type( Pname nn, Pktab tbl, TOK tcsue ) /* insert new type name into tbl * if another type name tn already exists, error * if a non type name already exists, enter class/enum as hidden */ { // type names defined in arg lists are entered in surrounding scope // friends are entered in scope enclosing class DB(if(Kdebug>=2)error('d',"insert_type( nn%n, tbl(%d) %s, tcsue%k )",nn,tbl,tbl->whereami(),tcsue);); if ( tbl->k_id == ARG ) { // types defined in arg lists are entered in surrounding scope do tbl = tbl->k_next; while ( tbl->k_id == ARG ); if ( tbl->k_id == TEMPLATE ) tbl = tbl->k_next; } if ( tbl->k_id == CLASS ) { if ( ccl == 0 ) error('i',&nn->where,"insert_type(%n) -- no ccl for class table!",nn); } DB(if(Kdebug>=2)error('d'," -- real tbl %d %s",tbl,tbl->whereami());); Pname nx = k_find_name( nn->string, tbl, 0 ); if ( nx && nx->n_ktable == tbl ) { Nold = 0; if ( nx->base == TNAME ) { Nold = 1; DB(if(Kdebug>=2)error('d',"TN%n redefined in same scope",nx);); } else { // nx is a non-type name in current table -- hide new type if ( tcsue == TYPE ) { ; DB(if(Kdebug>=2)error('d',"%n redefined asTdef",nx);); } Pname ny = tbl->insert(nn,HIDDEN); if ( Nold ) { // previous hidden tname ; DB(if(Kdebug>=2)error('d',"hiddenTN%n redefined in same scope",nx);); } else { ny->n_hidden = nx->n_hidden; nx->n_hidden = ny; DB(if(Kdebug>=2)error('d',"new, hiddenTN%n",nx);); } nx = ny; } } else { // nn not in current table Pname ny = tbl->insert(nn,0); ny->n_hidden = nx; nx = ny; DB(if(Kdebug>=2)error('d',"new, unhiddenTN%n",nx);); } nx->base = TNAME; return nx; } char* ktable::whereami() { if ( this == 0 ) return "NULL TABLE!!!"; else if ( k_id==ARG ) return "arg scope"; else if ( this==Gtbl ) return "global scope"; else if ( k_id==BLOCK ) return "block scope"; else if ( k_id==TEMPLATE ) return "template scope"; else if ( k_name ) return k_name->string; else return "??? scope"; }