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

expr.c

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

Click here to get the file

Size 32.6 kB - File type text/x-csrc

File contents

/* @(#) expr.c 1.6 1/27/86 17:48:51 */ 
/*ident	"@(#)cfront:src/expr.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.


expr.c:

	type check expressions

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

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

int const_save;

Pexpr expr.address()
{
	if (base==DEREF && e2==0) return e1;	/* &* */
	if (base == CM) {
		e2 = e2->address();
		return this;
	}
	register Pexpr ee = new expr(G_ADDROF,0,this);
	ee->tp = new ptr(PTR,tp,0);
	if (base == NAME) Pname(this)->take_addr();
	return ee;
}

Pexpr expr.contents()
{
	if (base==ADDROF || base==G_ADDROF) return e2;		/* *& */
	register Pexpr ee = new expr(DEREF,this,0);
	if (tp) ee->tp = Pptr(tp)->typ;		/* tp==0 ??? */
	return ee;
}

Pexpr table.find_name(register Pname n, bit f, Pexpr/* args*/)
/*
	find the true name for "n", implicitly define if undefined
	if "n" was called f==1 and "args" were its argument list
	if n was qualified r->n or o.n  f==2
*/
{
	Pname q = n->n_qualifier;
	register Pname qn = 0;
	register Pname nn;
	Pclass cl;	/* class specified by q */

	if (n->n_table) {
		nn = n;
		n = 0;
		goto xx;
	}

	if (q) {
		Ptable tbl;
//error('d',"qq %n %n",q,n);
		if (q == sta_name)
			tbl = gtbl;
		else {
			Ptype t = Pclass(q->tp);
			if (t == 0) error('i',"Qr%n'sT missing",q);

			if (q->base == TNAME) {
				if (t->base != COBJ) {
					error("badT%k forQr%n",t->base,q);
					goto nq;
				}
				t = Pbase(t)->b_name->tp;
			}
			if (t->base != CLASS) {
				error("badQr%n(%k)",q,t->base);
				goto nq;
			}
			cl = Pclass(t);
			tbl = cl->memtbl;
		}

		qn = tbl->look(n->string,0);
//error('d',"qn == %d",qn);
		if (qn == 0) {
			n->n_qualifier = 0;
			nn = 0;
			goto def;
		}

		if (q == sta_name) {	/* explicitly global */
			qn->use();
			delete n;
			return qn;
		}
		/* else check visibility */
	}

nq:
	if (cc->tot) {
	{	for (Ptable tbl = this;;) {	// loop necessary to get past
						// local re-definitions
			nn = tbl->lookc(n->string,0);
//error('d',"cc->tot:%n nn=%n sto%k sco%k tbl=%d",n,nn,nn->n_stclass,nn->n_scope,tbl);
			if (nn == 0) goto qq;	/* try for friend */

			switch (nn->n_scope) {
			case 0:
			case PUBLIC:
				if (nn->n_stclass == ENUM) break;

				if (nn->tp->base == OVERLOAD) break;

				if (Ebase
				&& cc->cot->clbase
				&& Ebase!=cc->cot->clbase->tp
				&& !Ebase->has_friend(cc->nof))
					error("%n is from a privateBC",n);

				if (Epriv
				&& Epriv!=cc->cot
				&& !Epriv->has_friend(cc->nof))
					error("%n is private",n);
			}

			if (qn==0 || qn==nn) break;

			if ((tbl=tbl->next) == 0) {	/* qn/cl test necessary? */
				if (/* (qn->n_stclass==STATIC
					|| qn->tp->base==FCT
					|| qn->tp->base==OVERLOAD)
				&&  */ (	qn->n_scope==PUBLIC
					|| cl->has_friend(cc->nof)) ) {
					/*qn->use();
					delete n;
					return qn;
					*/
					nn = qn;
					break;
				}
				else {
					error("QdN%n not in scope",n);
					goto def;
				}
			}
		}
	}
	xx:
//error('d',"xx: nn=%n qn=%n n=%n f=%d",nn,qn,n,f);
		if (nn == 0) goto def;
		nn->use();
		if (f == 2) {
			if (qn && nn->n_stclass==0)
				switch (nn->n_scope) {
				case 0:
				case PUBLIC:	/* suppress virtual */
					switch (qn->tp->base) {
					case FCT:
					case OVERLOAD:
						*n = *qn;
						n->n_qualifier = q;
						return n;
					}
				}
			if (nn->n_table == gtbl) error("MF%n not found",n);
			if (n) delete n;
			return nn;
		}

		switch (nn->n_scope) {
		case 0:
		case PUBLIC:
//error('d',"st %d th %d",nn->n_stclass,cc->c_this);
			if (nn->n_stclass == 0) {
				if (qn)	{	/* suppress virtual */
					switch (qn->tp->base) {
					case FCT:
					case OVERLOAD:
						*n = *qn;
						n->n_qualifier = q;
						/*return n; */
						nn = n;
						n = 0;
					}
				}

				if (cc->c_this == 0) {
					switch (nn->n_oper) {
					case CTOR:
					case DTOR:
						break;
					default:
						/* in static member initializer */
						error("%n cannot be used here",nn);
						return nn;
					}
				}

				Pref r = new ref(REF,cc->c_this,nn);
				cc->c_this->use();
				r->tp = nn->tp;
				if (n) delete n;
				return r;
			}
		default:
			if (n) delete n;
			return nn;
		}
	}
qq:
//error('d',"qq: n%n qn%d",n,qn);
	if (qn) {
		// check for p->base::mem :
			// nasty where derived::mem is public
			// and base::mem is private
		// NOT DONE

	/* static member? */
		if (qn->n_scope==0  && !cl->has_friend(cc->nof) ) {
			error("%n is private",qn);
			if (n) delete n;
			return qn;
		}

		switch (qn->n_stclass) {
		case STATIC:
			break;
		default:
			switch (qn->tp->base) {
			case FCT:
			case OVERLOAD:	/* suppress virtual */
				if (f == 1) error("O missing for%n",qn);
				*n = *qn;
				n->n_qualifier = q;
				return n;
			default:
				if (f != 2) error("O missing for%n",qn);
			}
		}

		if (n) delete n;
		return qn;
	}

	if ( nn = lookc(n->string,0) ) {
		switch (nn->n_scope) {
		case 0:
		case PUBLIC:
			if (nn->n_stclass == ENUM) break;

			if (nn->tp->base == OVERLOAD) break;
			if (Ebase && !Ebase->has_friend(cc->nof) )
				error("%n is from privateBC",n);

			if (Epriv && !Epriv->has_friend(cc->nof) )
				error("%n is private",n);
		}
	}

	if (nn) {
//error('d',"found %n",nn);
		if (f==2 && nn->n_table==gtbl) error("MF%n not found",n);
		nn->use();
		if (n) delete n;
		return nn;
	}

def:	/* implicit declaration */
//error('d',"implicit f %d",f);
	n->n_qualifier = 0;
	if (f == 1) {	/* function */
		if (n->tp) error('i',"find_name(fct_type?)");
		n->tp = new fct(defa_type,0,0);
		n->n_sto = EXTERN;
	/*	if (fct_void) {
			n->tp = new fct(defa_type,0,0);
		}
		else {
			Pexpr e;
			Pname at = 0;
			Pname att;
			
			for (e=args; e; e=e->e2) {
				Pname ar = new name;
				if (e->base != ELIST) error('i',"badA %k",e->base);
				e->e1 = e->e1->typ(this);
				ar->tp = e->e1->base==STRING ? Pchar_type : e->e1->tp;
				switch (ar->tp->base) {
				case ZTYPE:
					ar->tp = defa_type;
					break;
				case FIELD:
					ar->tp = int_type;
					break;
				case ANY:
				default:
					PERM(ar->tp);
				}
				if (at)
					att->n_list = ar;
				else
					at = ar;
				att = ar;
			}
			n->tp = new fct(defa_type,at,1);

		}
	*/
	}
	else {
		n->tp = any_type;
		if (this != any_tbl)
			if (cc->not
			&&  (cc->cot->defined&(DEFINED|SIMPLIFIED)) == 0)
				error("C%n isU",cc->not);
			else
				error("%n isU",n);
	}

	nn = n->dcl(gtbl,EXTERN);
	nn->n_list = 0;
	nn->use();
	nn->use();	/* twice to cope with "undef = 1;" */
	if (n) delete n;

	if (f==1)
		if (fct_void) {
			if  (no_of_undcl++ == 0) undcl = nn;
		}
		else
			error('w',"undeclaredF%n called",nn);

	return nn;
}

Pexpr expr.typ(Ptable tbl)
/*
	find the type of "this" and place it in tp;
	return the typechecked version of the expression:
	"tbl" provides the scope for the names in "this"
*/
{
if (this == 0) error('i',"0->expr.typ");
	Pname n;
	Ptype t = 0;
	Ptype t1, t2;
	TOK b = base;
	TOK r1, r2;

#define nppromote(b)	t=np_promote(b,r1,r2,t1,t2,1)
#define npcheck(b)	(void)np_promote(b,r1,r2,t1,t2,0)
	if (tbl->base != TABLE) error('i',"expr.typ(%d)",tbl->base);
//if (b == NAME) error('d',"name %d %d %s",this,string,string?string:"?");
	if (tp) {
/*error('d',"expr.typ %d (checked) tbl=%d",this,tbl);*/
		if (b == NAME) Pname(this)->use();
		return this;
	}
//error('d',"expr.typ %d%k e1 %d%k e2 %d%k tbl %d\n",this,base,e1,e1?e1->base:0,e2,e2?e2->base:0,tbl);
	switch (b) {		/* is it a basic type */
	case DUMMY:
		error("emptyE");
		tp = any_type;
		return this;
	case ZERO:
		tp = zero_type;
		return this;
	case IVAL:
		tp = int_type;
		return this;
	case FVAL:
		tp = float_type;
		return this;
	case ICON:
		/*	is it long?
			explicit long?
			decimal larger than largest signed int
			octal or hexadecimal larger than largest unsigned int
		 */
	{	int ll = strlen(string);
		switch (string[ll-1]) {
		case 'l':
		case 'L':
		lng:
			tp = long_type;
			goto save;
		}

		if  (string[0] == '0') {	/* assume 8 bits in byte */
			switch (string[1]) {
			case 'x':
			case 'X':
				if (SZ_INT+SZ_INT < ll-2) goto lng;
				goto nrm;
			default:
				if (BI_IN_BYTE*SZ_INT < (ll-1)*3) goto lng;
				goto nrm;
			}
		}
		else {
			if (ll</*sizeof(LARGEST_INT)-1*/10) {
		nrm:
				tp = int_type;
				goto save;
			}
			if (ll>10) goto lng;
			char* p = string;
			char* q = LARGEST_INT;
			do if (*p++>*q++) goto lng; while (*p);
		}

		goto nrm;
	}
	case CCON:
		tp = char_type;
		goto save;
	case FCON:
		tp = double_type;
		goto save;
	case STRING:			// type of "as\tdf" is char[6]
					// c_strlen counts the terminating '\0'
	{	int ll = c_strlen(string);
		Pvec v = new vec(char_type,0);
		v->size = ll;
		tp = v;
		goto save;
	}
	save:
/*error('d',"%s const_save %d",string,const_save);*/
		if (const_save) {
			int ll = c_strlen(string);
			char* p = new char[ll];
			strcpy(p,string);
			string = p;
		}
		return this;

	case THIS:
		delete this;
		if (cc->tot) {
			cc->c_this->use();
			return cc->c_this;
		}
		error("this used in nonC context");
		n = new name("this");
		n->tp = any_type;
		return tbl->insert(n,0); 

	case NAME:
/*error('d',"name %s",string);*/
	{	Pexpr ee = tbl->find_name((Pname)this,0,0);
		if (ee->tp->base == RPTR) return ee->contents();
		return ee;
	}
	case SIZEOF:
		t = tp2;
		if (t) {
			t->dcl(tbl);
			if (e1 && e1!=dummy) {
				e1 = e1->typ(tbl);
				DEL(e1);
				e1 = dummy;
			}
		}
		else {
			e1 = e1->typ(tbl);
			tp2 = e1->tp;
		}
		tp = int_type;
		return this;

	case CAST:
	{	
		Ptype tt = t = tp2;
		tt->dcl(tbl);
	zaq:				/* is the cast legal? */
//error('d',"tt %d %d",tt,tt?tt->base:0);
		switch (tt->base) {
		case TYPE:
			tt = Pbase(tt)->b_name->tp;	goto zaq;
		case RPTR:	// necessary?
		case PTR:
			if (Pptr(tt)->rdo) error("*const in cast");
			tt = Pptr(tt)->typ;
			goto zaq;
		case VEC:
			tt = Pvec(tt)->typ;
			goto zaq;
		case FCT:
			tt = Pfct(tt)->returns;
			goto zaq;
		default:	
			if (Pbase(tt)->b_const) error("const in cast");
		}

		/* now check cast against value, INCOMPLETE */

//error('d',"cast e1 %d %k",e1,e1->base);
		tt = t;

		if (e1 == dummy) {
			error("expression missing for cast");
			tp = any_type;
			return this;
		}
		e1 = e1->typ(tbl);
		Ptype etp = e1->tp;
		while (etp->base == TYPE) etp = Pbase(etp)->b_name->tp;
		
		if (etp->base == COBJ) {
			int i = can_coerce(tt,etp);
//error('d',"cast%t->%t -- %d%n",tt,etp,i,Ncoerce);
			if (i==1 && Ncoerce) {
				Pname cn = Pbase(etp)->b_name;
				Pclass cl = Pclass(cn->tp);
				Pref r = new ref(DOT,e1,Ncoerce);
				Pexpr rr = r->typ(tbl);
				Pexpr c = new expr(G_CALL,rr,0);
				c->fct_name = Ncoerce;
				c->tp = tt;
				*this = *Pexpr(c);
				delete c;	
				return this;
			}
		}

		switch (etp->base) {
		case VOID:
			if (tt->base == VOID) {
				tp = t;
				return this;
			}
			error("cast of void value");
		case ANY:
			tp = any_type;
			return this;
		}

	legloop:
		switch (tt->base) {
		case TYPE:	
			tt = Pbase(tt)->b_name->tp; goto legloop;
		case VOID:
			switch (etp->base) {
			case COBJ:
				switch (e1->base) {
				case VALUE:
				case CALL:
				case G_CALL:
				{	Pname cln = etp->is_cl_obj();
					Pclass cl = (Pclass)cln->tp;
					if (cl->has_dtor()) error('s',"cannot castCO to void");
				}
				}
				break;
			} 
			break;
		case PTR:
			switch (etp->base) {
			case COBJ:
				error("cannot castCO toP");
				break;
			}
			break;

		case RPTR:		// (x&)e: pretend e is an x
			if ((e1->base==CALL || e1->base==G_CALL || e1->lval(0))
			&& Pptr(tt)->typ->tsizeof()<=etp->tsizeof()) {
//error('d',"%t(%t)",t,etp);
				e1 = e1->address();	// *(x*)&e
				tp = t;
				return contents();
			}
			else	
				error(0,"cannot cast%t to%t",etp,t);
			break;

		case COBJ:
//error('d',"%n ctor %d",cn,ctor);
			base = VALUE;	// (x)e => x(e): construct an x from e
			e1 = new expr(ELIST,e1,0);
			return typ(tbl);

		case CHAR:
		case INT:
		case SHORT:
		case LONG:
		case FLOAT:
		case DOUBLE:
			switch (etp->base) {
			case COBJ:
				error("cannot castCO to%k",tt->base);
				break;
			}	
			break;
		
		}
		tp = t;
		return this;
	}

	case VALUE:
	{	Ptype tt = tp2;
		Pclass cl;
		Pname cn;
//error('d',"value %d %d (%d %k)",tt,tt?tt->base:0,e1,e1?e1->base:0);
		
		tt->dcl(tbl);
	vv:
//error('d',"vv %d %d",tt,tt?tt->base:0);
		switch (tt->base) {
		case TYPE:
			tt = Pbase(tt)->b_name->tp;
			goto vv;
		case EOBJ:
		default:
			if (e1 == 0) {
				error("value missing in conversion to%t",tt);
				tp = any_type;
				return this;
			}
			base = CAST;
			e1 = e1->e1;	// strip ELIST
			return typ(tbl);
		case CLASS:
			cl = (Pclass)tt;
			goto nn;
		case COBJ:
			cn = Pbase(tt)->b_name;
			cl = Pclass(cn->tp);
		nn:
			if (e1 && e1->e2==0) {		/* single argument */
				e1->e1 = e1->e1->typ(tbl);
				Pname acn=e1->e1->tp->is_cl_obj();
//error('d',"acn%n itor%d",acn,acn?cl->itor:0);
				if (acn
				&& acn->tp==cl
				&& cl->has_itor()==0) {
					if (e2) {	// x(x_obj) => e2=x_obj
						base = ASSIGN;
						Pexpr ee = e1->e1;
						e1 = e2;
						e2 = ee;
						tp = tp2;
						return this;
					}
					else		// x(x_obj) => x_obj
						return e1->e1;
				}
			}

		{	/* x(a) => obj.ctor(a); where e1==obj */
			Pexpr ee;
			Pexpr a = e1;
			Pname ctor = cl->has_ctor();
			if (ctor == 0) {
				error("cannot make a%n",cn);
				base = SM;
				e1 = dummy;
				e2 = 0;
				return this;
			}
//error('d',"value %n.%n",e2,ctor);
			int tv = 0;
			if (e2 == 0) {	/*  x(a) => x temp; (temp.x(a),temp) */
				Ptable otbl = tbl;
				if (Cstmt) { /*	make Cstmt into a block */
					if (Cstmt->memtbl == 0) Cstmt->memtbl = new table(4,tbl,0);
					tbl = Cstmt->memtbl;
				}
				char* s = make_name('V');
//error('d',"%s: %d %d",s,otbl,tbl);
				Pname n = new name(s);
				n->tp = tp2;
				n = n->dcl(tbl,ARG); /* no init! */
				n->n_scope = FCT;
				n->assign();
				e2 = n;
				ee = new expr(CM,this,n);
				tbl = otbl;
				tv = 1;
			}
			else
				ee = this;

			base = G_CALL;
			e1 = new ref(DOT,e2,ctor);
			e2 = a;
			ee = ee->typ(tbl);
//error('d',"ee %t",ee->tp);
			if (tv == 0) {	// deref value returned by constructor
				ee = new expr(DEREF,ee,0);
				ee->tp = ee->e1->tp;
			}
			return ee;
		}
		}
	}

	case NEW:
	{	Ptype tt = tp2;
		Ptype tx = tt;
		bit v = 0;
		bit old = new_type;
		new_type = 1;
/*error('d',"new%t e1 %d %d",tt,e1,e1?e1->base:0);*/
		tt->dcl(tbl);
		new_type = old;
		if (e1) e1 = e1->typ(tbl);
	ll:
//error('d',"tt %d %d",tt,tt?tt->base:0);
		switch (tt->base) {
		default:
			if (e1) {
				error("Ir for nonCO created using \"new\"");
				e1 = 0;
			}
			break;
		case VEC:
			v = 1;
			tt = Pvec(tt)->typ;
			goto ll;
		case TYPE:
			tt = Pbase(tt)->b_name->tp;
			goto ll;
		case COBJ:
		{	Pname cn = Pbase(tt)->b_name;
			Pclass cl = (Pclass)cn->tp;
			
			if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
				error("new%n;%n isU",cn,cn);
			}
			else {
				Pname ctor = cl->has_ctor();
				TOK su;
				if (ctor) {
/*error('d',"cobj%n tp%t",ctor,ctor->tp);*/
					if (v) {
						Pname ic;
						if (e1)
							error('s',"Ir forvector ofCO created using \"new\"");
						else if ((ic = cl->has_ictor())==0)
							error("vector ofC%n that do not have a constructor taking noAs",cn);
						else if (Pfct(ic->tp)->nargs)
							error('s',"defaultAs for constructor for vector ofC%n",cn);
					}
					e1 = new call(ctor,e1);
					e1 = e1->typ(tbl);
					/*(void) e1->fct_call(tbl);*/
				}
				else if (su=cl->is_simple()) { 
/*error('d',"simple cobj%k",su);*/
					if (e1) error("new%n withIr",cn);
				}
				else {
/*error('d',"not simple and no constructor?");*/
				}
			}
		}
		}
//error('d',"v==%d",v);
		tp = (v) ? (Ptype)tx : (Ptype)new ptr(PTR,tx,0);
		return this;
	}

	case DELETE:	// delete e1 OR delete[e2] e1
	{	int i;
		if (e1->base == ADDROF) error('w',"delete &E");
		e1 = e1->typ(tbl);
		i = e1->tp->num_ptr(DELETE);
		if (i != P) error("nonP deleted");
		if (e2) {
			e2 = e2->typ(tbl);
			e2->tp->integral(DELETE);
		}
		tp = void_type;
		return this;
	}
	}


	if (e1==0 && e2==0) error('i',"no operands for%k",b);

	switch(b) {
	case ILIST:	/* an ILIST is pointer to an ELIST */
		e1 = e1->typ(tbl);
		tp = any_type;
		return this;

	case ELIST:
		{	Pexpr e;
			Pexpr ex;

			if (e1 == dummy && e2==0) {
				error("emptyIrL");
				tp = any_type;
				return this;
			}
				
			for (e=this; e; e=ex) {
				Pexpr ee = e->e1;
/*error('d',"e %d %d ee %d %d",e,e?e->base:0,ee,ee?ee->base:0);*/
				if (e->base != ELIST) error('i',"elist%k",e->base);
				if (ex = e->e2) {	/* look ahead for end of list */
					if (ee == dummy) error("EX in EL");
					if (ex->e1 == dummy && ex->e2 == 0) {
						/* { ... , } */
						DEL(ex);
						e->e2 = ex = 0;
					}
				}
				e->e1 = ee->typ(tbl);
				t = e->e1->tp;
				
			}
			tp = t;
			return this;
		}

	case DOT:
	case REF:
	{
		Pbase b;
		Ptable atbl;
		Pname nn;
		char* s;
		Pclass cl;

		e1 = e1->typ(tbl);
		t = e1->tp;

		if (base == REF) {
		xxx:
//error('d',"xxx %t",t);
			switch (t->base) {
			case TYPE:	t = Pbase(t)->b_name->tp;	goto xxx;
			default:	error("nonP ->%n",mem);
			case ANY:	atbl = any_tbl;			goto mm;
			case PTR:
			case VEC:	b = Pbase(Pptr(t)->typ);	break;
			}
		}
		else {
		qqq:
			switch (t->base) {
			case TYPE:	t = Pbase(t)->b_name->tp;	goto qqq;
			default:	error("nonO .%n",mem);
			case ANY:	atbl = any_tbl;			goto mm;
			case COBJ:	break;
			}
//error('d',"dot e1 %k %d",e1->base,e1->base);
			switch (e1->base) {	/* FUDGE, but cannot use lval (consts) */
			case CM:
				/* ( ... , x). => ( ... , &x)-> */
			{	Pexpr ex = e1;
			cfr:	switch (ex->e2->base) {
				case NAME:
					base = REF;
					ex->e2 = ex->e2->address();
					goto xde;
				case CM:
					ex = ex->e2;
					goto cfr;
				}
			}
			case CALL:
			case G_CALL:
//error('d',"call%d, %n %d %d",e1->fct_name,e1->fct_name,Pfct(e1->fct_name->tp)->f_inline,Pfct(e1->fct_name->tp)->f_virtual);
#ifdef BSD
				if (e1->fct_name
				&& Pfct(e1->fct_name->tp)->f_inline
				&& Pfct(e1->fct_name->tp)->f_virtual==0) break;
#else
			//	if (e1->fct_name==0
			//	|| Pfct(e1->fct_name->tp)->f_inline==0)
#endif
			{
					/* f(). => (tmp=f(),&tmp)-> */
					Ptable otbl = tbl;
					if (Cstmt) { /*	make Cstmt into a block */
						if (Cstmt->memtbl == 0) Cstmt->memtbl = new table(4,tbl,0);
						tbl = Cstmt->memtbl;
					}
					char* s = make_name('T');
					Pname tmp = new name(s);
					tmp->tp = e1->tp;
					tmp = tmp->dcl(tbl,ARG); /* no init! */
					tmp->n_scope = FCT;
					e1 = new expr(ASSIGN,tmp,e1);
					e1->tp = tmp->tp;
					Pexpr aa = tmp->address();
					e1 = new expr(CM,e1,aa);
					e1->tp = aa->tp;
					base = REF;
					tbl = otbl;
				}
				break;
		//	case QUEST:
		//		error("non-lvalue .%n",mem);
		//		break;
		//	case NAME:
		//		Pname(e1)->take_addr();
		//		Pname(e1)->use();
			}
		xde:
			b = Pbase(t);
		}

	xxxx:
		switch (b->base) {
		case TYPE:	b = (Pbase) b->b_name->tp;	goto xxxx;
		default:	error("(%t) before %k%n (%n not aM)",e1->tp,base,mem,mem);
		case ANY:	atbl = any_tbl;			goto mm;

		case COBJ:
			if (atbl = b->b_table) goto mm;
			s = b->b_name->string;	/* lookup the class name */
			if (s == 0) error('i',"%kN missing",CLASS);
//error('d',"lookup %s",s);
			nn = tbl->look(s,CLASS);
			if (nn == 0) error('i',"%k %sU",CLASS,s);
			if (nn != b->b_name) b->b_name = nn;
			cl = (Pclass) nn->tp;
			PERM(cl);
			if (cl == 0) error('i',"%k %s'sT missing",CLASS,s);
			b->b_table = atbl = cl->memtbl;
		mm:
			if (atbl->base != TABLE) error('i',"atbl(%d)",atbl->base);
			nn = (Pname)atbl->find_name(mem,2,0);
//error('d',"nn%n %d %d",nn,nn->n_stclass,nn->n_scope);
			switch (nn->n_stclass) {
			case 0:
				mem = nn;	
				tp = nn->tp;
				return this;
			case STATIC:
				return nn;
			}
		}
	}

	case CALL:	/* handle undefined function names */
		if (e1->base==NAME && e1->tp==0) {
//error('d',"call %d %s",e1,e1->string);
			e1 = tbl->find_name(Pname(e1),1,e2);
		}
		break;
	case QUEST:
		cond = cond->typ(tbl);
	}

	if (e1) {
		e1 = e1->typ(tbl);
		if (e1->tp->base == RPTR) e1 = e1->contents();
		t1 = e1->tp;
	}
	else
		t1 = 0;

	if (e2) {
		e2 = e2->typ(tbl);
		if (e2->tp->base == RPTR) e2 = e2->contents();
		t2 = e2->tp;
	}
	else 
		t2 = 0;

	TOK bb;
	switch (b) {			/* filter non-overloadable operators out */
	default:	bb = b; break;
	case DEREF:	bb = (e2) ? DEREF : MUL; break;
	case CM:
	case QUEST:
	case G_ADDROF:
	case G_CALL:	goto not_overloaded;
	}

	Pname n1;
	if (e1) {
		Ptype tx = t1;
		while (tx->base == TYPE) tx = Pbase(tx)->b_name->tp;
		n1 = tx->is_cl_obj();
	}
	else
		n1 = 0;

	Pname n2;
	if (e2) {
		Ptype tx = t2;
		while (tx->base == TYPE) tx = Pbase(tx)->b_name->tp;
		n2 = tx->is_cl_obj();
	}
	else
		n2 = 0;
//error('d',"overload %k: %s %s\n", bb, n1?n1->string:"1", n2?n2->string:"2");
	if (n1==0 && n2==0) goto not_overloaded;
{
	/* first try for non-member function:	op(e1,e2) or op(e2) or op(e1) */
	Pexpr oe2 = e2;
	Pexpr ee2 = (e2 && e2->base!=ELIST) ? e2 = new expr(ELIST,e2,0) : 0;
	Pexpr ee1 = (e1) ? new expr(ELIST,e1,e2) : ee2;
	char* obb = oper_name(bb);
	Pname gname = gtbl->look(obb,0);
	int go = gname ? over_call(gname,ee1) : 0;
	int nc = Nover_coerce;	// first look at member functions						// then if necessary check for ambiguities
	if (go) gname = Nover;
//error('d',"global%n go=%d nc=%d",gname,go,nc);

	if (n1) {				/* look for member of n1 */	
		Ptable ctbl = Pclass(n1->tp)->memtbl;
		Pname mname = ctbl->look(obb,0);
		if (mname == 0) goto glob;
		switch (mname->n_scope) {
		default:	goto glob;
		case 0:
		case PUBLIC:	break;		/* try e1.op(?) */
		}

		int mo = over_call(mname,e2);
//error('d',"n1%n %d",mname,mo);
		switch (mo) {
		case 0:	
			if (go == 2) goto glob;
			if (1 < Nover_coerce) goto am1;
			goto glob;
		case 1:	if (go == 2) goto glob;
			if (go == 1) {
			am1:
				error("ambiguous operandTs%n%t for%k",n1,t2,b);
				tp = any_type;
				return this;
			}
			else {
				Pclass cl = (Pclass)n1->tp;
				if (cl->conv) error('w',"overloaded%k may be ambiguous",bb);
			}
			break;
		case 2:
			if (go == 2) error("%k defined both as%n and%n",bb,gname,Nover);
		}
//error('d',"%k mtbl %d ctbl %d",bb,mname->n_table,ctbl);
		if (bb==ASSIGN && mname->n_table!=ctbl) {	/* inherited = */
			//if (n1->tsizeof()!=mname->?)
			error("assignment not defined for class%n",n1);
			tp = any_type;
			return this;
		}
//error('d',"Nover %n %k",Nover,Nover->tp->base);
		base = G_CALL;			/* e1.op(e2) or e1.op() */
		e1 = new ref(DOT,e1,Nover);
		if (ee1) delete ee1;
		return typ(tbl);
	}
	
	if (n2 && e1==0) {			/* look for unary operator */
		Ptable ctbl = Pclass(n2->tp)->memtbl;
		Pname mname = ctbl->look(obb,0);
		if (mname == 0) goto glob;
		switch (mname->n_scope) {
		default:	goto glob;
		case 0:
		case PUBLIC:	break;		/* try e2.op() */
		}
		
		int mo = over_call(mname,0);
/*error('d',"n2%n %d",mname,mo);*/
		switch (mo) {
		case 0:		
			if (1 < Nover_coerce) goto am2;
			goto glob;
		case 1:	if (go == 2) goto glob;
			if (go == 1) {
			am2:
				error("ambiguous operandT%n for%k",n2,b);
				tp = any_type;
				return this;
			}
			break;
		case 2:
			if (go == 2) error("%k defined both as%n and%n",bb,gname,Nover);
		}

		base = G_CALL;			/* e2.op() */
		e1 = new ref(DOT,oe2,Nover);
		e2 = 0;
		if (ee2) delete ee2;
		if (ee1 && ee1!=ee2) delete ee1;
		return typ(tbl);
		
	}
	
glob:
//error('d',"glob %d",nc);
	if (1 < nc) {
		error("ambiguous operandTs%t%t for%k",t1,t2,b);
		tp = any_type;
		return this;
	}
	if (go) {
		if (go == 1) {	/* conversion necessary => binary */
			if (n1) {
				Pclass cl = (Pclass)n1->tp;
				if (cl->conv) error('w',"overloaded%k may be ambiguous",bb);
//error('d',"go n1");
			}
			else if (n2) {
				Pclass cl = (Pclass)n2->tp;
				if (cl->conv) error('w',"overloaded%k may be ambiguous",bb);
//error('d',"bb%k go n2 %n",bb,gname);
			}
		}
		base = G_CALL;			/* op(e1,e2) or op(e1) or op(e2) */
		e1 = gname;
		e2 = ee1;
		return typ(tbl);
	}

	if (ee2) delete ee2;
	if (ee1 && ee1!=ee2) delete ee1;
	e2 = oe2;
//error('d',"bb%k",bb);
	switch(bb) {
	case ASSIGN:
	case ADDROF:
		break;
	case CALL:
	case DEREF:
		if (n1 == 0) break;
	default:	/* look for conversions to basic types */
	{	int found = 0;
		if (n1) {
			int val = 0;
			Pclass cl = (Pclass)n1->tp;
			for ( Pname on = cl->conv; on; on=on->n_list) {
//error('d',"oper_coerce n1%n %t",on,(on)?Pfct(on->tp)->returns:0);
				Pfct f = (Pfct)on->tp;
				if (bb==ANDAND || bb==OROR) {
					e1 = check_cond(e1,bb,tbl);
					goto not_overloaded;
				}
				if (n2 
				|| (t2 && f->returns->check(t2,ASSIGN)==0)
				|| (t2 && t2->check(f->returns,ASSIGN)==0)) {
					Ncoerce = on;
					val++;
				}
			}
			switch (val) {
			case 0:
				break;
			case 1:
			{	Pref r = new ref(DOT,e1,Ncoerce);
				Pexpr rr = e1->typ(tbl);
				e1 = new expr(G_CALL,rr,0);
				found = 1;
				break;
			}
			default:
				error('s',"ambiguous coercion of%n to basicT",n1);
			}
		}
		if (n2) {
			int val = 0;
			Pclass cl = (Pclass)n2->tp;
			for ( Pname on = cl->conv; on; on=on->n_list) {
//error('d',"oper_coerce n2%n %t",on,(on)?on->tp:0);
				Pfct f = (Pfct)on->tp;
				if (bb==ANDAND || bb==OROR || bb==NOT) {
					e2 = check_cond(e2,bb,tbl);
					goto not_overloaded;
				}
				if (n1 
				|| (t1 && f->returns->check(t1,ASSIGN)==0)
				|| (t1 && t1->check(f->returns,ASSIGN)==0)) {
					Ncoerce = on;
					val++;
				}
			}
			switch (val) {
			case 0:
				break;
			case 1:
			{	Pref r = new ref(DOT,e2,Ncoerce);
				Pexpr rr = r->typ(tbl);
				e2 = new expr(G_CALL,rr,0);
				found++;
				break;
			}
			default:
				error('s',"ambiguous coercion of%n to basicT",n2);
			}
		}
		if (found) {
		/*	if (found == 2) error('w',"coercions of operands of%k may be ambiguous",b);*/
			return typ(tbl);
		}
		if (t1 && t2)
			error("bad operandTs%t%t for%k",t1,t2,b);
		else
			error("bad operandT%t for%k",t1?t1:t2,b);
		tp = any_type;
		return this;
	}
	}
}
not_overloaded:
	t = (t1==0) ? t2 : (t2==0) ? t1 : 0;
/*fprintf(stderr,"%s: e1 %d %d e2 %d %d\n",oper_name(b),e1,e1?e1->base:0,e2,e2?e2->base:0);*/
	switch (b) {		/* are the operands of legal types */
	case G_CALL:
	case CALL:
		tp = fct_call(tbl);	/* two calls of use() for e1's names */
		if (tp->base == RPTR) return contents();
		return this;

	case DEREF:
//error('d',"deref %t",t?t:t1);
		if (e1 == dummy) error("O missing before []\n");
		if (t) {	/*	*t	*/
			t->vec_type();
			tp = t->deref();
		}
		else {					// e1[e2] that is *(e1+e2)
			if (t1->vec_type()) {		// e1[e2]
				t2->integral(b);
				tp = t1->deref();
			}
			else if (t2->vec_type()) {	// really e2[e1]
				t1->integral(b);
				tp = t2->deref();
			}
			else {
				error("[] applied to nonPT:%t[%t]",t1,t2);
				tp = any_type;
			}
		}
		if (tp->base == RPTR) return contents();
		return this;

	case G_ADDROF:
	case ADDROF:	
		if (e2->lval(b) == 0) {
			tp = any_type;
			return this;
		}
		tp = t->addrof();
			/* look for &p->member_function */
		switch (e2->base) {
		case DOT:
		case REF:
		{	Pname m = e2->mem;
			Pfct f = (Pfct)m->tp;
			if (f->base==FCT && (f->f_virtual==0 || m->n_qualifier)) {
				DEL(e2);
				e2 = m;
			}
		}
		}
		return this;

	case UMINUS:
		t->numeric(b);
		tp = t;
		return this;
	case UPLUS:
		t->num_ptr(b);
		error('s',"unary + (ignored)");
		tp = t;
		base = PLUS;
		e1 = zero;
		return this;
	case NOT:
		e2 = check_cond(e2,NOT,tbl);
		tp = int_type;
		return this;
	case COMPL:
		t->integral(b);
		tp = t;
		return this;

	case INCR:
	case DECR:
		if (e1) e1->lval(b);
		if (e2) e2->lval(b);
		r1 = t->num_ptr(b);
		tp = t;
		return this;
	
	}

	if (e1==dummy || e2==dummy || e1==0 || e2==0) error("operand missing for%k",b);
	switch (b) {
	case MUL:
	case DIV:
		r1 = t1->numeric(b);
		r2 = t2->numeric(b);
		nppromote(b);
		break;
	case MOD:
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		nppromote(b);
		break;
	case PLUS:
		r2 = t2->num_ptr(b);
		r1 = t1->num_ptr(b);
		if (r1==P && r2==P) error("P +P");
		nppromote(b);
		tp = t;
		break;
	case MINUS:
		r2 = t2->num_ptr(b);
		r1 = t1->num_ptr(b);
		if (r2==P && r1!=P && r1!=A) error("P - nonP");
		nppromote(b);
		tp = t;
		break;
	case LS:
	case RS:
	case AND:
	case OR:
	case ER:
		switch (e1->base) {
		case LT:
		case LE:
		case GT:
		case GE:
		case EQ:
		case NE:
			error('w',"%kE as operand for%k",e1->base,b);
		}
		switch (e2->base) {
		case LT:
		case LE:
		case GT:
		case GE:
		case EQ:
		case NE:
			error('w',"%kE as operand for%k",e2->base,b);
		}
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		nppromote(b);
		break;
	case LT:
	case LE:
	case GT:
	case GE:
	case EQ:
	case NE:
		r1 = t1->num_ptr(b);
		r2 = t2->num_ptr(b);
		npcheck(b);
		t = int_type;
		break;
	case ANDAND:
	case OROR:
		e1 = check_cond(e1,b,tbl);
		e2 = check_cond(e2,b,tbl);
//		if (st2 != st3) error('s',"needs temporaryV to evaluateE after \"%k\" (please use ifS)",b);
		t = int_type;
		break;
	case QUEST:
		{
		Pname c1, c2;
		cond = check_cond(cond,b,tbl);
//		if (st1 != st2) error('s',"needs temporaryV to evaluateE after \"?\" (please use ifS)");
//		if (st2 != st3) error('s',"needs temporaryV to evaluateE after \":\" (please use ifS)");
		// still doesn't do complete checking for possible conversions...
		if (t1==t2
		|| (	(c1=t1->is_cl_obj())
			&& (c2=t2->is_cl_obj())
			&& (c1->tp==c2->tp)
		))
			t = t1;
		else {
			r1 = t1->num_ptr(b);
			r2 = t2->num_ptr(b);
//error('d',"r1 %d r2 %d",r1,r2);
			if (r1==FCT && r2==FCT) {	// fudge
				if (t1->check(t2,ASSIGN)) error("badTs in ?:E: %t and %t",t1,t2);
				t = t1;
			}
			else
				nppromote(b);
//error('d',"t: %d %t   t1: %d %t   t2: %d %t",t,t,t1,t1,t2,t2);
			if (t!=t1 && t->check(t1,0)) {
				e1 = new texpr(CAST,t,e1);
				e1->tp = t;
			}
			if (t!=t2 && t->check(t2,0)) {
				e2 = new texpr(CAST,t,e2);
				e2->tp = t;
			}
			
		}
		}
		break;
	case ASPLUS:
		r1 = t1->num_ptr(b);
		r2 = t2->num_ptr(b);
		if (r1==P && r2==P) error("P +=P");
		nppromote(b);
		goto ass;
	case ASMINUS:
		r1 = t1->num_ptr(b);
		r2 = t2->num_ptr(b);
		if (r2==P && r1!=P && r1!=A) error("P -= nonP");
		nppromote(b);
		goto ass;
	case ASMUL:
	case ASDIV:
		r1 = t1->numeric(b);
		r2 = t1->numeric(b);
		nppromote(b);
		goto ass;
	case ASMOD:
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		nppromote(b);
		goto ass;
	case ASAND:
	case ASOR:
	case ASER:
	case ASLS:
	case ASRS:
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		npcheck(b);
		t = int_type;
		goto ass;
	ass:
		as_type = t;	/* the type of the rhs */
		t2 = t;
	case ASSIGN:
		if (e1->lval(b) == 0) {
			tp = any_type;
			return this;
		}
	lkj:
		switch (t1->base) {
		case INT:
		case CHAR:
		case SHORT:
			if (e2->base==ICON && e2->tp==long_type)
				error('w',"long constant assigned to%k",t1->base);
		case LONG:
			if (b==ASSIGN
			&& Pbase(t1)->b_unsigned
			&& e2->base==UMINUS
			&& e2->e2->base==ICON)
				error('w',"negative assigned to unsigned");
			break;
		case TYPE:
			t1 = Pbase(t1)->b_name->tp;
			goto lkj;
		case COBJ:
		{	Pname c1 = t1->is_cl_obj();

			if (c1) {
				Pname c2 = t2->is_cl_obj();
//error('d',"%t=%t %d %d",t1,t2,c1,c2);
				if (c1 != c2) {
					e2 = new expr(ELIST,e2,0);
					e2 = new texpr(VALUE,t1,e2);
					e2->e2 = e1;
					e2 = e2->typ(tbl);
					*this = *e2;
					tp = t1;
					return this;
				}
				else {	// check for bitwise copy
					Pclass cl = Pclass(c1->tp);
//error('d',"bit %d",cl->bit_ass);
					if (cl->bit_ass == 0)
						error('s',"bitwise copy: %s has a member with operator=()",cl->string);
					else if (cl->itor && cl->has_dtor())
						error('w',"bitwise copy: %s has destructor and %s(%s&) but not assignment",cl->string,cl->string,cl->string);	
				}
			}
			break;
		}
		case PTR:
/*error('d',"ptr %d %d",t1,t1?t1->base:0);*/
		{	Pfct ef = Pfct(Pptr(t1)->typ);
			if (ef->base == FCT) {
				Pfct f;
				Pname n = 0;
				switch (e2->base) {
				case NAME:
					f = (Pfct)e2->tp;
					n = Pname(e2);
					switch (f->base) {
					case FCT:
					case OVERLOAD:
						e2 = new expr(G_ADDROF,0,e2);
						e2->tp = f;
					}
					goto ad;
				case DOT:
				case REF:
/*error('d',"dot %d %d",e2->mem->tp,e2->mem->tp?e2->mem->tp->base:0);*/
					f = (Pfct)e2->mem->tp;
					switch (f->base) {
					case FCT:
					case OVERLOAD:
						n = Pname(e2->mem);
						e2 = new expr(G_ADDROF,0,e2);
						e2 = e2->typ(tbl);
					}
					goto ad;
				case ADDROF:
				case G_ADDROF:
					f = (Pfct)e2->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);
							tp = any_type;
						}
						else
							tp = t1;
						e2->e2 = n;
						n->lval(ADDROF);
						return this;
					}
					if (n) n->lval(ADDROF);
				}
			}
			break;
		}
		}
		{	Pname cn;
			int i;
			if ((cn=t2->is_cl_obj())
			&& (i=can_coerce(t1,t2))
			&& Ncoerce) {
				if (1 < i) error("%d possible conversions for assignment",i);
//error('d',"%t =%t",t1,t2);
				Pclass cl = (Pclass)cn->tp;
				Pref r = new ref(DOT,e2,Ncoerce);
				Pexpr rr = r->typ(tbl);
				Pexpr c = new expr(G_CALL,rr,0);
				c->fct_name = Ncoerce;
				c->tp = t1;
				e2 = c;	
				tp = t1;	
				return this;
			}
		}
//error('d',"check(%t,%t)",e1->tp,t2);
		if (e1->tp->check(t2,ASSIGN)) error("bad assignmentT:%t =%t",e1->tp,t2);		
		t = e1->tp;				/* the type of the lhs */
		break;
	case CM:
		t = t2;
		break;
	default:
		error('i',"unknown operator%k",b);
	}

	tp = t;
	return this;
}

« 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: