Personal tools
You are here: Home Projects C++ Cfront releases Release 1.0 Source cfront src dcl.c
Document Actions

dcl.c

by Paul McJones last modified 2007-02-02 09:34

Click here to get the file

Size 45.5 kB - File type text/x-csrc

File contents

/* @(#) dcl.c 1.6 1/27/86 17:48:35 */ 
/*ident	"@(#)cfront:src/dcl.c	1.6" */
/**************************************************************************

	C++ source for cfront, the C++ compiler front-end
	written in the computer science research center of Bell Labs

	Copyright (c) 1984 AT&T, Inc. All Rights Reserved
	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.

	
dcl.c:

	``declare'' all names, that is insert them in the appropriate symbol tables.

	Calculate the size for all objects (incl. stack frames),
	and find store the offsets for all members (incl. auto variables).
	"size.h" holds the constants needed for calculating sizes.

	Note that (due to errors) functions may nest

*****************************************************************************/


#include "cfront.h"
#include "size.h"

class dcl_context ccvec[MAXCONT], * cc = ccvec;
int byte_offset;
int bit_offset;
int max_align;
int stack_size;
int enum_count;
int friend_in_class = 0;

void name.check_oper(Pname cn)
/*
	check declarations of operators, ctors, dtors
*/
{
	switch (n_oper) {
	case CALL:
		if (cn == 0) error("operator() must be aM");
		break;
	case DEREF:
		if (cn == 0) error("operator[] must be aM");
		break;
	case 0:
	case TNAME:	/* may be a constructor */
		if (cn && strcmp(cn->string,string)==0) {
			if (tp->base == FCT) {
				Pfct f = (Pfct)tp;
				if (f->returns!=defa_type && fct_void==0)
					error("%s::%s() with returnT",string,string);
				f->returns = void_type;
				string = "_ctor";
				n_oper = CTOR;
			}
			else
				error('s',"struct%cnM%n",cn,cn);
		}
		else
			n_oper = 0;
		break;
	case DTOR:	/* must be a destructor */
		if (cn == 0) {
			n_oper = 0;
			error("destructor ~%s() not inC",string);
		}
		else if (strcmp(cn->string,string) == 0) {
			Pfct f = (Pfct)tp;
			string = "_dtor";
			if (tp->base != FCT) {
				error("%s::~%s notF",cn->string,cn->string);
				tp = new fct(void_type,0,1);
			}
			else if (f->returns!=defa_type && fct_void==0)
				error("%s::~%s() with returnT",cn->string,cn->string);
			if (f->argtype) {
				if (fct_void==0) error("%s::~%s() withAs",cn->string,cn->string);
				f->nargs = 0;
				f->nargs_known = 1;
				f->argtype = 0;
			}
			f->returns = void_type;
		}
		else {
			error("~%s in %s",string,cn->string);
			n_oper = 0;
		}
		break;
	case TYPE:
		if (cn == 0) {
			error("operator%t() not aM",(Ptype)n_initializer);
			n_oper = 0;
			n_initializer = 0;
		} else {
			Pfct f = (Pfct)tp;
			Ptype tx = (Ptype)n_initializer;
/*error('d',"operator%t()",tx);*/
			n_initializer = 0;
			if (f->base != FCT) error("badT for%n::operator%t()",cn,tx);
			if (f->returns != defa_type) {
				if (f->returns->check(tx,0)) error("bad resultT for%n::operator%t()",cn,tx);
				DEL(f->returns);
			}
			if (f->argtype) {
				error("%n::operator%t() withAs",cn,tx);
				f->argtype = 0;
			}
			f->returns = tx;
			Pname nx = tx->is_cl_obj();
			if (nx && can_coerce(tx,cn->tp)) error("both %n::%n(%n) and %n::operator%t()",cn,cn,nx,tx);
			char buf[128];
			char* bb = tx->signature(buf);
			int l2 = bb-buf-1;
			char* p = new char[l2+3];
			p[0] = '_';
			p[1] = 'O';
			strcpy(p+2,buf);
			string = p;
		}
		break;
	}
}

Pname name.dcl(Ptable tbl, TOK scope)
/*
	enter a copy of this name into symbol table "tbl";
		- create local symbol tables as needed
	
	"scope" gives the scope in which the declaration was found
		- EXTERN, FCT, ARG, PUBLIC, or 0
	Compare "scope" with the specified storage class "n_sto"
		- AUTO, STATIC, REGISTER, EXTERN, OVERLOAD, FRIEND, or 0

	After name.dcl()
	n_stclass ==	0		class or enum member
			REGISTER	auto variables declared register
			AUTO		auto variables not registers
			STATIC		statically allocated object
	n_scope ==	0		private class member
			PUBLIC		public class member
			EXTERN		name valid in this and other files
			STATIC		name valid for this file only
			FCT		name local to a function
			ARG		name of a function argument
			ARGT		name of a type defined in an
					argument list

	typecheck function bodies;
	typecheck initializers;

	note that functions (error recovery) and classes (legal) nest

	The return value is used to chain symbol table entries, but cannot
	be used for printout because it denotes the sum of all type information
	for the name

	names of typenames are marked with n_oper==TNAME

	WARNING: The handling of scope and storage class is cursed!
*/
{
	Pname nn;
	Ptype nnt = 0;
	Pname odcl = Cdcl;

	if (this == 0) error('i',"0->name.dcl()");
	if (tbl == 0) error('i',"%n->name.dcl(tbl=0,%k)",this,scope);
	if (tbl->base != TABLE) error('i',"%n->name.dcl(tbl=%d,%k)",this,tbl->base,scope);
	if (tp == 0) error('i',"name.dcl(%n,%k)T missing",this,scope);
/*fprintf(stderr,"(%d %s)->dcl(tbl=%d,scope=%d) tp = (%d %d)\n",this,string,tbl,scope,tp,tp->base); fflush(stderr);*/
	Cdcl = this;
	switch (base) {
	case TNAME:
		tp->dcl(tbl);
		PERM(tp);
		nn = new name(string);
		nn->base = TNAME;
		nn->tp = tp;
		tbl->insert(nn,0);
		delete nn;
		Cdcl = odcl;
		return this;
	case NAME:
		switch (n_oper) {
		case TNAME:
			if (tp->base != FCT) n_oper = 0;
			break;
		case COMPL:
			if (tp->base != FCT) {
				error("~%s notF",string);
				n_oper = 0;
			}
			break;
		}
		break;
	default:
		error('i',"NX in name.dcl()");
	}

	if (n_qualifier) {	/*	class function: c::f(); */
		if (tp->base != FCT) {
			error("QdN%n inD of nonF",this);
			Cdcl = odcl;
			return 0;
		}

		Pname cn = n_qualifier;
		switch (cn->base) {
		case TNAME:
			break;
		case NAME:
			cn = gtbl->look(cn->string,0);
			if (cn && cn->base==TNAME) break;
		default:
			error("badQr%n for%n",n_qualifier,this);
			Cdcl = odcl;
			return 0;
		}
		cn = Pbase(cn->tp)->b_name;
		if (n_oper) check_oper(cn);

		Pclass cl = (Pclass)cn->tp;
		if (cl == cc->cot) {
			n_qualifier = 0;
			goto xdr;
		}
		else if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			error("C%nU",cn);
			Cdcl = odcl;
			return 0;
		}

		Ptable etbl = cl->memtbl;
		Pname x = etbl->look(string,0);
		if(x==0 || x->n_table!=etbl) {
			error("%n is not aM of%n",this,cn);
			Cdcl = odcl;
			return 0;
		}
	}
xdr:
	if (n_oper && tp->base!=FCT && n_sto!=OVERLOAD)
		error("operator%k not aF",n_oper);


	/*	if a storage class was specified
			check that it is legal in the scope 
		else
			provide default storage class
		some details must be left until the type of the object is known
	*/

	n_stclass = n_sto;
	n_scope = scope;	/* default scope & storage class */

	switch (n_sto) {
	default:
		error('i',"unX %k",n_sto);
	case FRIEND:
	{
		Pclass cl = cc->cot;

		switch (scope) {
		case 0:
		case PUBLIC:
			break;
		default:
			error("friend%n not in classD(%k)",this,scope);
			base = 0;
			Cdcl = odcl;
			return 0;
		}

		switch (n_oper) {
		case 0:
		case NEW:
		case DELETE:
		case CTOR:
		case DTOR:
		case TYPE:
			n_sto = 0;
			break;
		default:
			n_sto = OVERLOAD;
		}

		switch (tp->base) {
	/*	case INT:	 undefined: implicitly define as class
			nn = tname(CLASS);
			nn->tp->dcl(gtbl);
			break;
	*/
		case COBJ:
			nn = Pbase(tp)->b_name;
			break;
		case CLASS:
			nn = this;
			break;
		case FCT:
			cc->stack();
			cc->not = 0;
			cc->tot = 0;
			cc->cot = 0;
			friend_in_class++;
			n_sto = EXTERN;
			nn = dcl(gtbl,EXTERN);
			friend_in_class--;
/*fprintf(stderr,"ff %s %d\n",nn->string,nn->tp->base);*/
			cc->unstack();
			if (nn->tp->base == OVERLOAD) {
				Pgen g = (Pgen)nn->tp;
				nn = g->find( (Pfct)tp );
			}
			break;
		default:
			error("badT%t of friend%n",tp,this);
		}
		PERM(nn);
		cl->friend_list = new name_list(nn,cl->friend_list);
		Cdcl = odcl;
		return nn;
	}
	case OVERLOAD:
		n_sto = 0;
		switch (scope) {
		case 0:
		case PUBLIC:
			error('w',"overload inCD (ignored)");
			switch (tp->base) {
			case INT:
				base = 0;
				Cdcl = odcl;
				return this;
			case FCT:
				return dcl(tbl,scope);
			}
		}
		if (n_oper && tp->base==FCT) break;
		nn = tbl->insert(this,0);

		if (Nold) {
			if (nn->tp->base != OVERLOAD) {
				error("%n redefined as overloaded",this);
				nn->tp = new gen(string);
			}
		}
		else {
			nn->tp = new gen(string);
		}

		switch (tp->base) {
		case INT:
			base = 0;
			Cdcl = odcl;
			return nn;
		case FCT:
			break;
		default:
			error("N%n ofT%k cannot be overloaded",this,tp->base);
			Cdcl = odcl;
			return nn;
		}
		break;
	case REGISTER:
		if (tp->base == FCT) {
			error('w',"%n: register (ignored)",this);
			goto ddd;
		}
	case AUTO:
		switch (scope) {
		case 0:
		case PUBLIC:
		case EXTERN:
			error("%k not inF",n_sto);
			goto ddd;
		}
		break;
	case EXTERN:
		switch (scope) {
		case ARG:
			error("externA");
			goto ddd;
		case 0:
		case PUBLIC:
			/* extern is provided as a default for functions without body */
			if (tp->base != FCT) error("externM%n",this);
			goto ddd;
		}
		n_stclass = STATIC;
		n_scope = EXTERN;	/* avoid FCT scoped externs to allow better checking */
		break;
	case STATIC:
		switch (scope) {
		case ARG:
			error("static used forA%n",this);
			goto ddd;
		case 0:
		case PUBLIC:
			n_stclass = STATIC;
			n_scope = scope;
			break;
		default:
			n_scope = STATIC;
		}
		break;
	case 0:
	ddd:
		switch (scope) {	/* default storage classes */
		case EXTERN:
			n_scope = EXTERN;
			n_stclass = STATIC;
			break;
		case FCT:
			if (tp->base == FCT) {
				n_stclass = STATIC;
				n_scope = EXTERN;
			}
			else
				n_stclass = AUTO;
			break;
		case ARG:
			n_stclass = AUTO;
			break;
		case 0:
		case PUBLIC:
			n_stclass = 0;
			break;
		}
	}

	
	/*
		now insert the name into the appropriate symbol table,
		and compare types with previous declarations of that name

		do type dependent adjustments of the scope
	*/

	switch (tp->base) {
	case ASM:
	{	Pbase b = (Pbase)tp;
		Pname n = tbl->insert(this,0);
		n->assign();
		n->use();
		return this;
	}

	case CLASS:
	{	Pclass cl;
		Pbase bt;
		Pname bn;
	//	Pclass nest;
		Pname nx = ktbl->look(string,0);		// TNAME
//error('d',"%s: nx%n",string,nx);
		if (nx == 0) {
			/*	search for hidden name for
					(1) nested class declaration
					(2) local class declaration
			*/
			int tn = 0;
			for (nx=ktbl->look(string,HIDDEN); nx; nx=nx->n_tbl_list) {
//error('d',"%s: nxi%n key%d base%d",string,nx,nx->n_key,nx->tp->base);
				if (nx->n_key != HIDDEN) continue;
				if (nx->tp->base != COBJ) {
					tn = 1;
					continue;
				}
				bt = (Pbase)nx->tp;
				bn = bt->b_name;
				cl = (Pclass)bn->tp;
				if (cl == 0) continue;
			//	if ((nest=cl->in_class) && nest==cc->cot) 
			//		goto bbb;
			//	else
			//	 if (cc->nof	/* fudge */
			//		&& cc->nof->where.line<nx->where.line)
					goto bbb;
			}
			if (tn)
				error("%n redefined using typedef");
			else
				error('i',"%n is not aCN",this);
		}
		else {
			if (tbl != gtbl) { // careful: local class def
//error('d',"%n: local lex level %d",nx->lex_level);
				if (nx->lex_level == 0) // imperfect
					error('s',"localC%n and globalC%n",this,nx);
			}
			bt = (Pbase)nx->tp;			// COBJ
			bn = bt->b_name;
	//		nest = 0;
		}
bbb:
/*fprintf(stderr,"bbb: bt %d %d\n",bt,bt->base); fflush(stderr);*/
		Pname ln = tbl->look(bn->string,0);
//error('d',"ln %d %d",ln,ln?ln->n_table==tbl:0);
		if (ln && ln->n_table==tbl) error('w',"%n redefined",ln);
		bn->where = nx->where;
		Pname bnn = tbl->insert(bn,CLASS);	// copy for member lookup
		cl = (Pclass)bn->tp;
								/* CLASS */
/*fprintf(stderr,"cl %d %d\n",cl,cl->base); fflush(stderr);*/
		if (cl->defined&(DEFINED|SIMPLIFIED))
			error("C%n defined twice",this);
		else {
			if (bn->n_scope == ARG) bn->n_scope = ARGT;
			cl->dcl(bn,tbl);
	//		if (nest) {
	//			int l1 = strlen(cl->string);
	//			int l2 = strlen(nest->string);
	//			char* s = new char[l1+l2+2];
	//			strcpy(s,nest->string);
	//			s[l2] = '_';
	//			strcpy(s+l2+1,cl->string);
	//			cl->string = s;
	//		/*	cl->memtbl->t_name->string = s;*/
	//		}
		}
		tp = cl;
		Cdcl = odcl;
		return bnn;
	}

	case ENUM:
	{	Pname nx = ktbl->look(string,0);		/* TNAME */
		if (nx == 0) {
			nx = ktbl->look(string,HIDDEN);		/* hidden TNAME */
		}
		Pbase bt = (Pbase)nx->tp;			/* EOBJ */
		Pname bn = bt->b_name;
		Pname bnn = tbl->insert(bn,CLASS);
		Penum en = (Penum)bn->tp;			/* ENUM */
		if (en->defined&(DEFINED|SIMPLIFIED))
			error("enum%n defined twice",this);
		else {
			if (bn->n_scope == ARG) bn->n_scope = ARGT;
			en->dcl(bn,tbl);
		}
		tp = en;
		Cdcl = odcl;
		return bnn;
	}

	case FCT:
	{	Pfct f = (Pfct)tp;
		Pname class_name;
		Ptable etbl;
		int can_overload;
		int in_class_dcl = (int)cc->not;
		int just_made = 0;
//error('d',"fct%n",this);
		if (f->f_inline) n_sto = STATIC;

		if (f->argtype) {
			Pname a;
			int oo = const_save;
			const_save = 1;
			for (a=f->argtype; a; a=a->n_list) {
				Pexpr init;
				if (init = a->n_initializer) {	// default argument
//or('d',"init %k",init->base);
Pname cln;
if (cln = a->tp->is_cl_obj()) {
//error('d',"a%n cln%n init %k",a,cln,init->base);
	if (init->base==VALUE) {
		switch (init->tp2->base) {
		case CLASS:
			if (Pclass(init->tp2)!=Pclass(cln->tp)) goto inin2;
			break;
		default:
			Pname  n2 = init->tp2->is_cl_obj();
			if (n2==0 || Pclass(n2->tp)!=Pclass(cln->tp)) goto inin2;
		}
		init->e2 = a;
		init = init->typ(tbl);
		init->simpl();
		init->permanent = 2;
		a->n_initializer = init;
		error('s',"constructor as defaultA");
	}
	else {
	inin2:
//error('d',"inin2: %k %s",init->base,init->base==NAME?init->string:"");
		if (init->base == ILIST) error('s',"list as AIr");
		Pexpr i = init->typ(tbl);
		init = class_init(a,a->tp,i,tbl);
		if (i!=init && init->base==DEREF) error('s',"constructor needed forAIr");
		init->simpl();
		init->permanent = 2;
		a->n_initializer = init;
	}
}
else if (a->tp->is_ref()) {
//error('d',"%n is ref",a);
	init = init->typ(tbl);
	int tcount = stcount;
	init = ref_init(Pptr(a->tp),init,tbl);
	if (tcount != stcount) error('s',"needs temporaryV to evaluateAIr");
	init->simpl();
	init->permanent = 2;
	a->n_initializer = init;
//error('d',"ok");
}
else {
	int i = 0;
	init = init->typ(tbl);
	if (a->tp->check(init->tp,ARG)==0
	|| (i=can_coerce(a->tp,init->tp))) {
		if (1 < i) error("%d possible conversions for defaultA",i);
		if (Ncoerce) {
			Pname cn = init->tp->is_cl_obj();
			Pclass cl = (Pclass)cn->tp;
			Pref r = new ref(DOT,init,Ncoerce);
			init = new expr(G_CALL,r,0);
			init->fct_name = Ncoerce;
			init->tp = a->tp;
		}
		init->simpl();
		init->permanent = 2;
		a->n_initializer = init;
		Neval = 0;
		int i = init->eval();
		if (Neval == 0) {
			a->n_evaluated = 1;
			a->n_val = i;
		}
	}
	else {
		error("badIrT%t forA%n",init->tp,a);
		DEL(init);
		a->n_initializer = 0;
	}
				}
}
			flatten1:
				switch (a->tp->base) {
				case TYPE:
					a->tp = Pbase(a->tp)->b_name->tp;
					goto flatten1;
				case CHAR:
				case SHORT:
				/*	error('w',"A ofT%k (becomes int)",a->tp->base);	*/
					a->tp = int_type;
					break;
				case FLOAT:
				/*	error('w',"A ofT float (becomes double)");	*/
					a->tp = double_type;
					break;
				}
			}
			const_save = oo;
		}

		tp->dcl(tbl); /* must be done before the type check */

		if (n_qualifier) { /* qualified name: c.f() checked above */
			if (in_class_dcl) {
				error("unXQN%n",this);
				Cdcl = odcl;
				return 0;
			}
			class_name = Pbase(n_qualifier->tp)->b_name;
			etbl = Pclass(class_name->tp)->memtbl;
		}
		else {
			class_name = cc->not;
			/* beware of local function declarations in member functions */
			if (class_name && tbl!=cc->cot->memtbl) {
				class_name = 0;
				in_class_dcl = 0;
			}
			if (n_oper) check_oper(class_name);
			etbl = tbl;
		}

		if (etbl==0 || etbl->base!=TABLE) error('i',"N.dcl: etbl=%d",etbl);

		switch (n_oper) {
		case NEW:
		case DELETE:
			switch (scope) {
			case 0:
			case PUBLIC:
				error("%nMF",this);
			}
		case 0:
			can_overload = in_class_dcl;
			break;
		case CTOR:
			if (f->f_virtual) {
				error("virtual constructor");
				f->f_virtual = 0;
			}
		case DTOR:
			if (fct_void) n_scope = PUBLIC;
			can_overload = in_class_dcl;
			break;
		case TYPE:
			can_overload = 0;
			break;
		case ASSIGN:
//error('d',"assign %n",class_name);
			if (class_name && f->nargs==1) {
				Ptype t = f->argtype->tp;
				Pname an = t->is_cl_obj();  // X::operator=(X) ?
				if (an==0 && t->is_ref()) { // X::operator=(X&) ?
					t = Pptr(t)->typ;
				rx1:
					switch (t->base) {
					case TYPE:
						t = Pbase(t)->b_name->tp;
						goto rx1;
					case COBJ:
						an = Pbase(t)->b_name;
					}
				}
				if (an && an==class_name) Pclass(an->tp)->bit_ass = 0;
//error('d',"%n ==> %d",an,Pclass(class_name)->bit_ass);
			}
			else if (f->nargs == 2) {
				Ptype t = f->argtype->tp;
				Pname an1;
				if (t->is_ref()) { // operator=(X&,?) ?
					t = Pptr(t)->typ;
				rx2:
					switch (t->base) {
					case TYPE:
						t = Pbase(t)->b_name->tp;
						goto rx2;
					case COBJ:
						an1 = Pbase(t)->b_name;
					}
				}
				t = f->argtype->n_list->tp;
				Pname an2 = t->is_cl_obj(); // operator=(X&,X) ?
				if (an2==0 && t->is_ref()) { // operator=(X&,X&) ?
					t = Pptr(t)->typ;
				rx3:
					switch (t->base) {
					case TYPE:
						t = Pbase(t)->b_name->tp;
						goto rx3;
					case COBJ:
						an2 = Pbase(t)->b_name;
					}
				}
				if (an1 && an1==an2) Pclass(an1->tp)->bit_ass = 0;
			}
		default:
			can_overload = 1;	/* all operators are overloaded */
		}

		switch (scope) {
		case FCT:
		case ARG:
		{	Pname nx = gtbl->insert(this,0);
			n_table = 0;
			n_tbl_list = 0;
			if (Nold && tp->check(nx->tp,0)) error('w',"%n has been declared both as%t and as%t",this,nx->tp,tp);
			/* no break */
		}
		default:
			nn = etbl->insert(this,0);
			nn->assign();
			n_table = etbl;
			break;
		}

			
		if (Nold) {
			Pfct nf = (Pfct)nn->tp;
/*error('d',"%n: tp%t nf%t",nn,tp,nf);*/
			if (nf->base==ANY || f->base==ANY)
				;
			else if (nf->base == OVERLOAD) {
				Pgen g = (Pgen) nf;
				nn = g->add(this,0);
				string = nn->string;
				if (Nold == 0) {
					if (f->body) {
						if (n_qualifier) {
							error(0,"badAL for overloaded %n::%s()",n_qualifier,g->string);
							Cdcl = odcl;
							return 0;
						}
					//	else if (f->f_inline==0 && n_oper==0)
					//		error('w',"overloaded %n defined without being previously declared",nn);
					}
					goto thth;
				}
				else {
					if (f->body==0 && friend_in_class==0) error('w',"overloaded%n redeclared",nn);
				}
				
				nf = (Pfct)nn->tp;

				if (f->body && nf->body) {
					error("two definitions of overloaded%n",nn);
					Cdcl = odcl;
					return 0;
				}

				if (f->body) goto bdbd;
				
				goto stst;
			}
			else if (nf->base != FCT) {
				error("%n declared both as%t and asF",this,nf);
				f->body = 0;
			}
			else if (can_overload) {
				if (nf->check(f,OVERLOAD) || vrp_equiv) {
					if (f->body && n_qualifier) {
						error("badAT for%n",nn);
						Cdcl = odcl;
						return 0;
					}
					Pgen g = new gen(string);
					Pname n1 = g->add(nn,in_class_dcl);
					Pname n2 = g->add(this,0);
/*error('d',"n1%n n2%n\n",n1,n2);*/
					nn->tp = (Ptype)g;
					nn->string = g->string;
					nn = n2;
					goto thth;
				}
				
				if (in_class_dcl) {
					error("two declarations of%n",this);
					f->body = 0;
					Cdcl = odcl;
					return 0;
				}
				
				if (nf->body && f->body) {
					error("two definitions of%n",this);
					f->body = 0;
					Cdcl = odcl;
					return 0;
				}
				
				if (f->body) goto bdbd;

				goto stst;
			}
			else if (nf->check(f,0)) {
				switch (n_oper) {
				case CTOR:
				case DTOR:
					f->s_returns = nf->s_returns;
				}
				error("%nT mismatch:%t and%t",this,nf,f);
				f->body = 0;
			}
			else if (nf->body && f->body) {
				error("two definitions of%n",this);
				f->body = 0;
			}
			else if (f->body) {
				Pname a1, a2;
			bdbd: 
				if (f->nargs_known && nf->nargs_known)
				for (a1=f->argtype, a2=nf->argtype; a1; a1=a1->n_list, a2=a2->n_list) {
					int i1  =  a1->n_initializer || a1->n_evaluated;
					int i2  =  a2->n_initializer || a2->n_evaluated;
//error('d',"bdbd: i %d %d eval %d %d val %d %d",i1,i2,a1->n_evaluated,a2->n_evaluated,a1->n_val,a2->n_val);
					if (i1) {
						if (i2
						&& (	a1->n_evaluated==0
							|| a2->n_evaluated==0
							|| a1->n_val!=a2->n_val)
						)
							error("twoIrs for%nA%n",nn,a1);
					}
					else if (i2) {
						a1->n_initializer = a2->n_initializer;
						a1->n_evaluated = a2->n_evaluated;
						a1->n_val = a2->n_val;
					}
				}
				f->f_virtual = nf->f_virtual;
				f->f_this = nf->f_this;
/*fprintf(stderr,"bdbd %s: f %d inl %d nf %d inl %d\n",string,f,f->f_inline,nf,nf->f_inline);*/
				nn->tp = f;
				if (f->f_inline) {
					if (nf->f_inline==0 && nn->n_used)
						error("%n called before defined as inline",nn);
					nf->f_inline = 1;
					nn->n_sto = STATIC;
				}
				else if (nf->f_inline) {
					/*error("%n defined as inline but not declared as inline",this);*/
					f->f_inline = 1;
				}
				goto stst2;
			}
			else {	/* two declarations */
				Pname a1, a2;
				f->f_this = nf->f_this;
			stst:
				if (f->nargs_known && nf->nargs_known)
				for (a1=f->argtype, a2=nf->argtype; a1; a1=a1->n_list, a2=a2->n_list) {
					int i1  =  a1->n_initializer || a1->n_evaluated;
					int i2  =  a2->n_initializer || a2->n_evaluated;
//error('d',"stst %d %d",i1,i2);
					if (i1) {
						if (i2) {
							if (a1->n_evaluated==0
							|| a2->n_evaluated==0
							|| a1->n_val!=a2->n_val)
								error("twoIrs for%nA%n",nn,a1);
						}
						else if (class_name)
							error("defaultA for%n",nn);
					}
					else if (i2) {
						a1->n_initializer = a2->n_initializer;
						a1->n_evaluated = a2->n_evaluated;
						a1->n_val = a2->n_val;
					}
				}
			stst2:
				if (f->f_inline) n_sto = STATIC;
				if (n_sto
				&& nn->n_scope!=n_sto
				&& friend_in_class==0
				&& f->f_inline==0){ // allow re-def to "static"
if (n_sto == STATIC) nn->n_sto = STATIC; else
					error("%n both%k and%k",this,n_sto,nn->n_scope);
				}
				n_scope = nn->n_scope; // first specifier wins
				n_sto = nn->n_sto;
			
			}
		/*	Pfct(nn->tp)->nargs_known = nf->nargs_known;	*/
		}
		else {	/* new function: make f_this for member functions */
			if (tbl==gtbl && n_oper) {	// overload operator
				Pgen g = new gen(string);
				Pname n1 = g->add(nn,1);
//error('d',"overload %n -> %s",this,n1->string);
				nn->tp = Ptype(g);
				nn->string = g->string;
				string = n1->string;
				nn = n1;
			}
		thth:
			just_made = 1;
			if (f->f_inline)
				nn->n_sto = STATIC;
			else if (class_name==0
				&& n_sto==0
				&& f->body==0) // ``explicitly'' extern
					nn->n_sto = EXTERN;
/*fprintf(stderr,"thth %s: f %d nn->tp %d inl %d\n",string,f,nn->tp,f->f_inline);*/
			if (class_name && etbl!=gtbl) {	/* beware of implicit declatation */
				Pname cn = nn->n_table->t_name;
				Pname tt = new name("this");
				tt->n_scope = ARG;
				tt->n_sto = REGISTER;
				tt->tp = Pclass(class_name->tp)->this_type;
				PERM(tt);
				Pfct(nn->tp)->f_this = f->f_this = tt;
				tt->n_list = f->argtype;
			}

			if (f->f_virtual) {
				switch (nn->n_scope) {
				default:
					error("nonC virtual%n",this);
					break;
				case 0:
				case PUBLIC:
					cc->cot->virt_count = 1;
					Pfct(nn->tp)->f_virtual = 1;
					break;
				}
			}
		}

		/*	an operator must take at least one class object or
			reference to class object argument
		*/
		switch (n_oper) {
		case CTOR:
			if (f->nargs == 1) {	/* check for X(X) and X(X&) */
				Ptype t = f->argtype->tp;
			clll:
				switch (t->base) {
				case TYPE:
					t = Pbase(t)->b_name->tp;
					goto clll;
				case RPTR:			/* X(X&) ? */
					t = Pptr(t)->typ;
				cxll:
					switch (t->base) {
					case TYPE:
						t = Pbase(t)->b_name->tp;
						goto cxll;
					case COBJ:
						if (class_name == Pbase(t)->b_name)
							Pclass(class_name->tp)->itor = nn;
					}
					break;
				case COBJ:			/* X(X) ? */
					if (class_name == Pbase(t)->b_name)
						error("impossible constructor: %s(%s)",class_name->string,class_name->string);
				}
			}
			break;
		case TYPE:
/*error('d',"just_made %d %n",just_made,this);*/
			if (just_made) {
				nn->n_list = Pclass(class_name->tp)->conv;
				Pclass(class_name->tp)->conv = nn;
			}
			break;
		case DTOR:
		case NEW:
		case DELETE:
		case CALL:
		case 0:
			break;
		default:
			if (f->nargs_known != 1) {
				error("ATs must be fully specified for%n",nn);
			}
			else if (class_name == 0) {
				Pname a;
				switch (f->nargs) {
				case 1:
				case 2:
					for (a=f->argtype; a; a=a->n_list) {
						Ptype tx = a->tp;
						if (tx->base == RPTR) tx = ((Pptr)tx)->typ;
						if (tx->is_cl_obj()) goto cok;
					}
					error("%n must take at least oneCTA",nn);
					break;
				default:
					error("%n must take 1 or 2As",nn);
				}
			}
			else {
				switch (f->nargs) {
				case 0:
				case 1:
					break;
				default:
					error("%n must take 0 or 1As",nn);
				}
			}
		cok:;
		}

		/*
			the body cannot be checked until the name
			has been checked and entered into its table
		*/
		if (f->body) f->dcl(nn);
		break;
	}

	case FIELD:
	{	Pbase fld = (Pbase)tp;

		switch (n_stclass) {
		case 0:
		case PUBLIC:
			break;
		default:
			error("%k field",n_stclass);
			n_stclass = 0;
		}

		if (cc->not==0 || cc->cot->csu==UNION) {
			error(cc->not?"field in union":"field not inC");
			PERM(tp);
			Cdcl = odcl;
			return this;
		}

		if (string) {
			nn = tbl->insert(this,0);
			n_table = nn->n_table;
			if (Nold) error("twoDs of field%n",this);
		}

		tp->dcl(tbl);

		// adjust alignment
		int a = (F_SENSITIVE) ? Pbase(tp)->b_fieldtype->align() : SZ_WORD;
		if (max_align < a) max_align = a;

		if (fld->b_bits == 0) {		// force word alignment
			int b;
			if (bit_offset)
				fld->b_bits = BI_IN_WORD - bit_offset;
			else if (b = byte_offset%SZ_WORD)
				fld->b_bits = b * BI_IN_BYTE;
			if (max_align < SZ_WORD) max_align = SZ_WORD;
		}
		else if (bit_offset == 0) {	// take care of part of word
			int b = byte_offset%SZ_WORD;
			if (b) {
				byte_offset -= b;
				bit_offset = b*BI_IN_BYTE;
			}
		}
//error('d',"byteoff %d bitoff %d bits %d",byte_offset,bit_offset,fld->b_bits);
		int x = (bit_offset += fld->b_bits);
		if (BI_IN_WORD < x) {
			fld->b_offset = 0;
			byte_offset += SZ_WORD;
			bit_offset = fld->b_bits;
		}
		else {
			fld->b_offset = bit_offset;
			if (BI_IN_WORD == x) {
				bit_offset = 0;
				byte_offset += SZ_WORD;
			}
			else
				bit_offset = x;
		}
		n_offset = byte_offset;
		break;
	}

	case COBJ:
	{	Pclass cl = Pclass(Pbase(tp)->b_name->tp);
/*fprintf(stderr,"COBJ %d %s -> (%d %d)\n",tp,Pbase(tp)->b_name->string,cl,cl->base); fflush(stderr);*/
		if (cl->csu == ANON) {	/* export member names to enclosing scope */
			Pname nn;
			int i;
			int uindex;
			Ptable mtbl = cl->memtbl;
			char* p = cl->string;

			if (tbl == gtbl) error('s',"global anonymous union");
			while (*p++ != 'C');	/* UGH!!! */
			uindex = str_to_int(p);
			for ( nn=mtbl->get_mem(i=1); nn; nn=mtbl->get_mem(++i) ) {
				Ptable tb = nn->n_table;
				nn->n_table = 0;
				Pname n = tbl->insert(nn,0);
				n->n_union = uindex;
				nn->n_table = tb;
			}
		}
		goto cde;
	}

	case VEC:
	case PTR:
	case RPTR:
		tp->dcl(tbl);

	default:
	cde:
		nn = tbl->insert(this,0);

		n_table = nn->n_table;
//error('d',"Nold %d tbl %d nn %d%n tp%t gtbl %d",Nold,tbl,nn,nn,nn->tp,gtbl);
		if (Nold) {
			if (nn->tp->base == ANY) goto zzz;

			if (tp->check(nn->tp,0)) {
				error("twoDs of%n;Ts:%t and%t",this,nn->tp,tp);
				Cdcl = odcl;
				return 0;
			}

			if (n_sto && n_sto!=nn->n_scope) 
				error("%n both%k and not%k",this,n_sto,n_sto);
			else if (nn->n_scope==STATIC && n_scope==EXTERN)
				error("%n both static and extern",this);
			else if (nn->n_sto==STATIC && n_sto==STATIC ) 
				error("static%n declared twice",this);
			else {
			//	n_sto = nn->n_sto;	 first scope specifier wins
				n_scope = nn->n_scope;

				switch (scope) {
				case FCT:
					error("twoDs of%n",this);
					Cdcl = odcl;
					return 0;
				case ARG:
					error("two arguments%n",this);
					Cdcl = odcl;
					return 0;
				case 0:
				case PUBLIC:
					error("twoDs ofM%n",this);
					Cdcl = odcl;
					return 0;
				case EXTERN:
					if (fct_void==0
					&& n_sto==0
					&& nn->n_sto==0) {
						error("two definitions of%n",this);
						Cdcl = odcl;
						return 0;
					}
				}
			}
			n_scope = nn->n_scope;
/* n_val */
			if (n_initializer) {
				if (nn->n_initializer || nn->n_val) error("twoIrs for%n",this);
				nn->n_initializer = n_initializer;
			}
		}
		else {	// check for the ambiguous plain "int a;"
		/*	if (n_initializer==0
			&&  n_sto==0
			&&  scope==EXTERN) {
				error('w',"%n does not have storageC or initializer",this);
			}
		*/
		}
	
	zzz:
		if (base != TNAME) {
			Ptype t = nn->tp;
//fprintf(stderr,"tp %d %d nn->tp %d %d\n",tp,tp->base,nn->tp,nn->tp?nn->tp->base:0); fflush(stderr);
			if (t->base == TYPE) {
				Ptype tt = Pbase(t)->b_name->tp;
				if (tt->base == FCT) nn->tp = t = tt;
			}

			switch (nn->n_stclass) {
			default:
				switch (t->base) {
				case FCT:
				case OVERLOAD:
					break;
				default:
				{	int x = t->align();
					int y = t->tsizeof();

					if (max_align < x) max_align = x;

					while (0 < bit_offset) {
						byte_offset++;
						bit_offset -= BI_IN_BYTE;
					}
					bit_offset = 0;

					if (byte_offset && 1<x) byte_offset = ((byte_offset-1)/x)*x+x;
					nn->n_offset = byte_offset;
					byte_offset += y;
				}
				}
				break;
			case STATIC:
				switch (t->base) {
				case FCT:
				case OVERLOAD:
					break;
				default:
					t->tsizeof();	// check that size is known
				}
				break;
			}
		}

	{	Ptype t = nn->tp;
		int const_old = const_save;
		bit vec_seen = 0;
		Pexpr init = n_initializer;

		if (init) {
			switch (n_scope) {
			case 0:
			case PUBLIC:
				if (n_stclass != STATIC) error("Ir forM%n",this);
				break;
			}
		}

	/*	if (n_scope == EXTERN) break;		*/

	lll:
		switch (t->base) {
		case RPTR:
			if (init) {
				if (nn->n_scope == ARG) break;
				init = init->typ(tbl);
				if (n_sto==STATIC && init->lval(0)==0)
					error("Ir for static reference%n not an lvalue",this);
				else {
//					int tcount = stcount;
					nn->n_initializer = n_initializer = ref_init(Pptr(t),init,tbl);
//					if (tcount != stcount) error('s',"needs temporaryV for evaluation of AIr");
				}
				nn->assign();
			}
			else {
				switch (nn->n_scope) {
				default:
					if (n_sto == EXTERN) break;
					error("unId reference%n",this);
				case ARG:
					break;
				case PUBLIC:
				case 0:
					if (n_sto == STATIC) error("a staticM%n cannot be a reference",this);
					break;
				}
			}
			break;
		case COBJ:
		{	Pname cn = Pbase(t)->b_name;
			Pclass cl = (Pclass)cn->tp;
			Pname ctor = cl->has_ctor();
			Pname dtor = cl->has_dtor();
//error('d',"c/dtor %n %d %d",cn,ctor,dtor);
			if (dtor) {
				Pstmt dls;
				switch ( nn->n_scope ) {
				case EXTERN:
					if (n_sto==EXTERN) break;
				case STATIC:
				{	Ptable otbl = tbl;
						// to collect temporaries generated
						// in static destructors where we
						// can find them again (in std_tbl)
					if (std_tbl == 0) std_tbl = new table(8,gtbl,0);
					tbl = std_tbl;
					if (vec_seen) {	/*  _vec_delete(vec,noe,sz,dtor,0); */
						int esz = cl->tsizeof();
						Pexpr noe = new expr(IVAL, (Pexpr)(nn->tp->tsizeof()/esz),0);
						Pexpr sz = new expr(IVAL,(Pexpr)esz,0);
						Pexpr arg = new expr(ELIST,dtor,zero);
						dtor->lval(ADDROF);
						arg = new expr(ELIST,sz,arg);
						arg = new expr(ELIST,noe,arg);
						arg = new expr(ELIST,nn,arg);
						arg = new call(vec_del_fct,arg);
						arg->base = G_CALL;
						arg->fct_name = vec_del_fct;
						arg->tp = any_type;	// avoid another type check
						dls = new estmt(SM,nn->where,arg,0);
					}
					else {	/* nn->cl.~cl(0); */
						Pref r = new ref(DOT,nn,dtor);
						Pexpr ee = new expr(ELIST,zero,0);
						Pcall dl = new call(r,ee);
						dls = new estmt(SM,nn->where,dl,0);
						dl->base = G_CALL;
						dl->fct_name = dtor;
						dl->tp = any_type;	// avoid another check
					}
					// destructors for statics are executed in reverse order
					if (st_dlist) dls->s_list = st_dlist;
					st_dlist = dls;
					tbl = otbl;
				}
				}
			}
			if (ctor)	{
				Pexpr oo = nn;
				for (int vi=vec_seen; vi; vi--) oo = oo->contents();
				int sti = 0;
//error('d',"ctor init=%d n_scope=%d",init,nn->n_scope);
				switch (nn->n_scope) {
				case EXTERN:
					if (init==0 && n_sto==EXTERN) goto ggg;
				case STATIC:
					sti = 1;
					if (tbl != gtbl) {
// prohibited only to avoid having to handle local variables in the
// constructors argument list
	error('s',"local static%n of class with constructor",this);
					}
				default:
					if (vec_seen && init) {
						error("Ir forCO%n\[\]",this);
						n_initializer = init = 0;
					}
					break;
				case ARG:
//error('d',"init %d",init);
/*
					if (init) {
						// check default arguments
						init = new texpr(VALUE,cl,0);
						init->e2 = oo;
						nn->n_initializer
							= n_initializer
							= init
							= init->typ(tbl);
					}
*/
				case PUBLIC:
				case 0:
					goto ggg;
				}
				const_save = 1;
				nn->assign();
//error('d',"init %d %n tbl %d",init,nn,tbl);
				Ptable otbl = tbl;
				if (sti) {	// to collect temporaries generated
						// in static initializers where we
						// can find them again (in sti_tbl)
					if (sti_tbl == 0) sti_tbl = new table(8,gtbl,0);
					tbl = sti_tbl;
					if (n_sto == EXTERN) nn->n_sto = n_sto = 0;
				}
//error('d',"init %d %d vec_seen %d",init,init?init->base:0,vec_seen);
				if (init) {
					if (init->base==VALUE) {
//error('d',"value %d",init->tp2->base);
						switch (init->tp2->base) {
						case CLASS:
							if (Pclass(init->tp2)!=cl) goto inin;
							break;
						default:
							Pname  n2 = init->tp2->is_cl_obj();
							if (n2==0 || Pclass(n2->tp)!=cl) goto inin;
						}
						init->e2 = oo;
						init = init->typ(tbl);
					}
					else {
					inin:
//error('d',"inin:");
						init = init->typ(tbl);
						init = class_init(nn,nn->tp,init,tbl);
					}
				}
				else {
					init = new texpr(VALUE,cl,0);
					init->e2 = oo;
					init = init->typ(tbl);
				}
				Pname c;
				if (vec_seen) {
					c = cl->has_ictor();
					if (c == 0)
						error("vector ofC%n that do not have a constructor taking noAs",cn);
					else if (Pfct(c->tp)->nargs)
						error('s',"defaultAs for constructor for vector ofC%n",cn);
				}
				
	if (sti) {
		if (vec_seen) {	// _vec_new(vec,noe,sz,ctor);
			int esz = cl->tsizeof();
			Pexpr noe = new expr(IVAL,(Pexpr)(nn->tp->tsizeof()/esz),0);
			Pexpr sz = new expr(IVAL,(Pexpr)esz,0);
			Pexpr arg = new expr(ELIST,c,0);
			c->lval(ADDROF);
			arg = new expr(ELIST,sz,arg);
			arg = new expr(ELIST,noe,arg);
			arg = new expr(ELIST,nn,arg);
			init = new call(vec_new_fct,arg);
			init->base = G_CALL;
			init->fct_name = vec_new_fct;
			init->tp = any_type;
		}
		else {
//error('d',"init%n: %k",nn,init->base);
			switch (init->base) {
			case DEREF:		// *constructor?
				if (init->e1->base == G_CALL) {	
					Pname fn = init->e1->fct_name;
					if (fn==0 || fn->n_oper!=CTOR) goto as;
					init = init->e1;
					break;
				}
				goto as;
			case ASSIGN:
				if (init->e1 == nn) break;	// simple assignment
			as:	
			default:	
				init = new expr(ASSIGN,nn,init);
			}
		}
		Pstmt ist = new estmt(SM,nn->where,init,0);
		// constructors for statics are executed in order
		static Pstmt itail = 0;
		if (st_ilist == 0)
			st_ilist = ist;
		else
			itail->s_list = ist;
		itail = ist;
		init = 0;
	} // if (sti)
				nn->n_initializer = n_initializer = init;
				const_save = const_old;
				tbl = otbl;
			}
			else if (init == 0)		/* no initializer */
				goto str;
			else if (cl->is_simple() && cl->csu!=UNION && cl->csu!=ANON)	/* struct */
				goto str;
			else if (init->base == ILIST) {	// class or union
				error("cannotI%n withIrL",nn);
			}
			else {			// bitwise copy ok?
						// possible to get here?
//error('d',"not simple %n",this);
				init = init->typ(tbl);
				if (nn->tp->check(init->tp,ASSIGN)==0)
					goto str;
				else
					error("cannotI%n:C %s has privateMs but no constructor",nn,cl->string);
			}
			break;
		}
		case VEC:	
			t = Pvec(t)->typ;
			vec_seen++;
			goto lll;
		case TYPE:
			if (init==0 && Pbase(t)->b_const) {
				switch (n_scope) {
				case ARG:
				case 0:
				case PUBLIC:
					break;
				default:
					if (n_sto != EXTERN) error("unId const%n",this);
				}
			}
			t = Pbase(t)->b_name->tp;
			goto lll;
		default:
		str:
//error('d',"str: %n",this);
			if (init == 0) {
				switch (n_scope) {
				case ARG:
				case 0:
				case PUBLIC:
					break;
				default:
					if (n_sto!=EXTERN && t->tconst()) error("unId const%n",this);
				}

				break;
			}

			const_save = 	   const_save
					|| n_scope==ARG
					|| (t->tconst() && vec_const==0);
			nn->n_initializer = n_initializer = init = init->typ(tbl);
			if (const_save) PERM(init);
			nn->assign();
			const_save = const_old;

			switch (init->base) {
			case ILIST:
				new_list(init);
				list_check(nn,nn->tp,0);
				if (next_elem()) error("IrL too long");
				break;
			case STRING:
				if (nn->tp->base == VEC) {
					Pvec v = (Pvec)nn->tp;
					if (v->typ->base == CHAR) {
					/*	error('w',"\"char[] = string\"");*/
						int sz = v->size;
						int isz = Pvec(init->tp)->size;
						if (sz == 0)
							v->size = isz;
						else if (sz < isz)
							error("Ir too long (%d characters) for%n[%d]",isz,nn,sz);
						break;
					}
				}
			default:
			{	Ptype nt = nn->tp;

				if (vec_seen) {
					error("badIr for vector%n",nn);
					break;
				}
			tlx:
				switch (nt->base) {
				case TYPE:
					nt = ((Pbase)nt)->b_name->tp;
					goto tlx;
				case INT:
				case CHAR:
				case SHORT:
					if (init->base==ICON && init->tp==long_type)
						error('w',"longIr constant for%k%n",nn->tp->base,nn);
				case LONG:
					if (Pbase(nt)->b_unsigned
					&& init->base==UMINUS
					&& init->e2->base==ICON)
						error('w',"negativeIr for unsigned%n",nn);
					if (Pbase(nt)->b_const) {
						int i;
						Neval = 0;
						i = init->eval();
						if (Neval == 0) {
							DEL(init);
							nn->n_evaluated = n_evaluated = 1;
							nn->n_val = n_val = i;
							nn->n_initializer = n_initializer = 0;
						}
					}
					goto cvcv;
		case PTR:
		{	Pfct ef = Pfct(Pptr(nt)->typ);
			if (ef->base == FCT) {
				Pfct f;
				Pname n = 0;
				switch (init->base) {
				case NAME:
					f = (Pfct)init->tp;
					n = Pname(init);
					switch (f->base) {
					case FCT:
					case OVERLOAD:
						init = new expr(G_ADDROF,0,init);
						init->tp = f;
					}
					goto ad;
				case DOT:
				case REF:
					f = (Pfct) init->mem->tp;
					switch (f->base) {
					case FCT:
					case OVERLOAD:
						n = Pname(init->mem);
						init = new expr(G_ADDROF,0,init);
						init = init->typ(tbl);
					}
					goto ad;
				case ADDROF:
				case G_ADDROF:
					f = (Pfct)init->e2->tp;
				ad:
					if (f->base == OVERLOAD) {
						Pgen g = (Pgen)f;
						n = g->find(ef);
						if (n == 0) {
							error("cannot deduceT for &overloaded %s()",g->string);
						}
						init->e2 = n;
						n_initializer = init;
						n->lval(ADDROF);
						goto stgg;
					}
					if (n) n->lval(ADDROF);
				}
			}
		}
				} 
	cvcv:
		{	Pname cn;
			int i;
			if ((cn=init->tp->is_cl_obj())
			&& (i=can_coerce(nt,init->tp))
			&& Ncoerce) {
				if (1 < i) error("%d possible conversions forIr",i);
/*error('d',"dcl %t<-%t",nt,init->tp);*/
				Pclass cl = (Pclass)cn->tp;
				Pref r = new ref(DOT,init,Ncoerce);
				Pexpr c = new expr(G_CALL,r,0);
				c->fct_name = Ncoerce;
				c->tp = nt;
				n_initializer = c;
				goto stgg;
			}
		}
				if (nt->check(init->tp,ASSIGN))
					error("badIrT%t for%n (%tX)",init->tp,this,nn->tp);
			else {
			stgg:
				if (init && n_stclass== STATIC) {
					/* check if non-static variables are used */
					/* INCOMPLETE */
					switch (init->base) {
					case NAME:
						if (init->tp->tconst()==0) error("V%n used inIr for%n",init,nn);
						break;
					case DEREF:
					case DOT:
					case REF:
					case CALL:
					case G_CALL:
						error("%k inIr of static%n",init->base,nn);
					}
			}
			}
		}
		} /* switch */
	} /* block */
	} /* default */

	} /* switch */
ggg:
	PERM(nn);
	switch (n_scope) {
	case FCT:
		nn->n_initializer = n_initializer;
		break;
	default:
	{/*	Pexpr ii = nn->n_initializer;*/
		Ptype t = nn->tp;
	/*	if (ii) PERM(ii);*/
	px:
		PERM(t);
		switch (t->base) {
		case PTR:
		case RPTR:	t = Pptr(t)->typ; goto px;
		case VEC:	t = Pvec(t)->typ; goto px;
		case TYPE:	t = Pbase(t)->b_name->tp; goto px;
		case FCT:	t = Pfct(t)->returns; goto px; /* args? */
		} 
	}
	}
	
	Cdcl = odcl;
	return nn;
}


int inline_restr;	/* report use of constructs that the inline expanded
			   cannot handle here
			*/

void fct.dcl(Pname n)
{
	int nmem = TBLSIZE;
	Pname a;
	Pname ll;
	Ptable ftbl;

	Pptr cct = 0;
	int const_old = const_save;

	int bit_old = bit_offset;
	int byte_old = byte_offset;
	int max_old = max_align;
	int stack_old = stack_size;

	if (base != FCT) error('i',"fct.dcl(%d)",base);
	if (body == 0) error('i',"fct.dcl(body=%d)",body);
	if (n==0 || n->base!=NAME) error('i',"fct.dcl(name=%d %d)",n,(n)?n->base:0);

	if (body->memtbl == 0) body->memtbl = new table(nmem+3,n->n_table,0);
	ftbl = body->memtbl;
	body->own_tbl = 1;
	ftbl->real_block = body;

	max_align = AL_FRAME;
	stack_size = byte_offset = SZ_BOTTOM;
	bit_offset = 0;

	cc->stack();
	cc->nof = n;
	cc->ftbl = ftbl;

	switch (n->n_scope) {
	case 0:
	case PUBLIC:
		cc->not = n->n_table->t_name;
		cc->cot = (Pclass)cc->not->tp;
		cc->tot = cc->cot->this_type;
		if (f_this==0 || cc->tot==0) error('i',"fct.dcl(%n): f_this=%d cc->tot=%d",n,f_this,cc->tot);
		f_this->n_table = ftbl;		/* fake for inline printout */
		cc->c_this = f_this;
	
	}

	Pname ax;
	for (a=argtype, ll=0; a; a=ax) {
		ax = a->n_list;
		Pname nn = a->dcl(ftbl,ARG);
		nn->n_assigned_to = nn->n_used = nn->n_addr_taken = 0;
		nn->n_list = 0;
		switch (a->tp->base) {
		case CLASS:
		case ENUM:	/* unlink types declared in arg list */
			a->n_list = dcl_list;
			dcl_list = a;
			break;
		default:
			if (ll)
				ll->n_list = nn;
			else {
				argtype = nn;
				if (f_this) f_this->n_list = argtype;
	 		}
			ll = nn;
			delete a;
		}
	}


	/*
		handle initializers for base class and member classes
		this->f_init == list of names of classes to be initialized
		no name		=> base class
				=> constructor call in f_init->n_initializer
		name "m"	=> member object
				=> constructor call in m->n_initializer
	*/
	if (n->n_oper != CTOR) {
		if (f_init) error(0,"unXAL: not a constructor");
	}
	else {
//error('d',"%n:f_init %d %d",n,f_init,f_init?f_init->base:0);
		if (f_init) {				// explicit initializers
			Pname  bn  = cc->cot->clbase;
			Ptable tbl = cc->cot->memtbl;
			Pexpr binit = 0;
			Pname nx;
			const_save = 1;
			for ( Pname nn=f_init; nn; nn=nx) {
				nx = nn->n_list;
				Pexpr i = nn->n_initializer;

				if (nn->string) { // class member initializer
					Pname m = tbl->look(nn->string, 0);
					if (m && m->n_table == tbl)
						nn->n_initializer = mem_init(m,i,ftbl);
					else {
						error("%n not inC%n",m,n);
						nn->n_initializer = 0;
					}
				}
				else if (bn) {  // base class initializer
					binit = base_init(bn,i,ftbl);
					nn->n_initializer = 0;
				}
				else
					error( "unXAL: noBC" );
			} // for
			const_save = const_old;
			b_init = binit;
		}

		if (b_init == 0) { // try default initialization of base class
			Pname  bn  = cc->cot->clbase;
			if (bn && Pclass(bn->tp)->has_ctor())
				b_init = base_init(bn,0,ftbl);
		}
	}


	PERM(returns);
	if (returns->base != VOID) {
		Pname rv = new name("_result");
		rv->tp  = returns;
		ftbl->insert(rv,0);
		delete rv;
	}	

	const_save = f_inline?1:0;
	inline_restr = 0;
	body->dcl(ftbl);
	if( f_inline && inline_restr && returns->base!=VOID) {
		f_inline = 0;
		error( 'w', "\"inline\" ignored, %n contains%s%s%s%s",n,
			(inline_restr & 8) ? " loop"	: "",
			(inline_restr & 4) ? " switch"	: "",
			(inline_restr & 2) ? " goto"	: "",
			(inline_restr & 1) ? " label"	: "" );
	}
	const_save = const_old;

	if (f_inline) isf_list = new name_list(n,isf_list);

	defined |= DEFINED;

	frame_size = stack_size + SZ_TOP;
	frame_size = ((frame_size-1)/AL_FRAME)*AL_FRAME+AL_FRAME;
	bit_offset = bit_old;
	byte_offset = byte_old;
	max_align = max_old;
	stack_size = stack_old;

	cc->unstack();
}


Pexpr fct.base_init(Pname bn, Pexpr i, Ptable ftbl)
/*
	have base class bn and expr list i
	return "( *(base*)this ) . ctor( i )"
	ctor call generated in expr.typ()
*/
{
	Pclass bcl = (Pclass)bn->tp;
	Pname bnw = bcl->has_ctor();
//error('d',"base_init%n %d i %d %d bcl %d %d",bn,bnw,i,i?i->base:0,bcl,bcl?bcl->base:0);
	if (bnw) {
		Ptype t = bnw->tp;
		Pfct f  = Pfct((t->base==FCT) ? t : Pgen(t)->fct_list->f->tp);
		Ptype ty = f->f_this->tp;		// this
		Pexpr th = new texpr(CAST,ty,f_this);	// (base*)this
		Pexpr v  = new texpr(VALUE,bcl,i);	// ?.base(i)
		v->e2    = new expr(DEREF,th,0);	// (*(base*)this).base(i)
		v = v->typ(ftbl);			// *base(&*(base*)this,i)
//error('d',"v %d %k",v,v->base);
		switch (v->base) {
		case DEREF:
			Pexpr vv = v;
			v = v->e1;			// base(&*(base*)this,i)
			delete vv;
			break;
		case ASSIGN:		// degenerate base(base&): *(base*)this=i
			th = new texpr(CAST,ty,f_this);
			v = new expr(CM,v,th);	// (*(base*)this=i,(base*)this);
			v = v->typ(ftbl);
			break;
		default:
			error('i',"fct.base_init: unX%k",v->base);
		}
		return v;
	} else
		error(0,"unXAL: noBC constructor");
	return 0;
}


Pexpr fct.mem_init(Pname member, Pexpr i, Ptable ftbl)
/*
	return "member_ctor( m, i )"
*/
{
//error('d',"mem_init(%n)",member);
	if (member->n_stclass == STATIC) error('s',"MIr for static%n",member);
	Pname cn = member->tp->is_cl_obj();	// first find the class name
	if (cn) {
		Pclass mcl = Pclass(cn->tp);	// then find the classdef
		Pname ctor = mcl->has_ctor();
//error('d',"cn%n ctor %d",cn,ctor);
		if (ctor) {	// generate: this->member.cn::cn(args)
			Pref tn = new ref(REF,f_this,member);
			Pref ct = new ref(DOT,tn,ctor);
			Pexpr c = new expr(G_CALL,ct,i);
			return c->typ(ftbl);
		} else
			error("init of member %m with no ctor",member);
	} else if (cl_obj_vec)
		error('s', "init of Cmember vector with ctor");
	else if (member->tp->tconst()) {
		TOK t = member->tp->set_const(0);
		switch (t) {
		case ANY:
		case VEC:
		case RPTR:
			error("MIr for%kM%n",member);
			return 0;
		}
		Pref tn = new ref(REF,f_this,member);
		Pexpr init = new expr(ASSIGN,tn,i);
		init = init->typ(ftbl);
		member->tp->set_const(1);
		return init;
	}
	else if (member->tp->is_ref()) {
		Pexpr init = i->typ(ftbl);
		init = ref_init(Pptr(member->tp),init,ftbl);
		member->assign();
		return init;
	}
	else {
		Pref tn = new ref (REF,f_this,member);
		Pexpr init = new expr(ASSIGN,tn,i);
		return init->typ(ftbl);
	}
	return 0;
}
« March 2024 »
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: