File contents
/*ident "@(#)cls4:src/expr.c 1.28" */
/*******************************************************************************
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.
expr.c:
type check expressions
************************************************************************/
#include "cfront.h"
#include "size.h"
int const_save;
extern int no_const;
extern Ptype Pfct_type;
extern Pexpr make_dot(Pexpr, Ptable, char* c = "i");
int processing_sizeof = 0;
Pexpr expr::address()
{
// error('d',"address %k %d %s",base,base,base==NAME||base==ANAME?string:"?");
// error('d',"address e1 %d %k e2 %d %k", e1, e1?e1->base:0, e2, e2?e2->base:0);
switch (base) {
case DEREF:
if (e2 == 0) return e1; // &*e => e
break;
case QUEST: // &(a?b:c) => a?&b:&c
e1 = e1->address();
// no break;
case G_CM:
if (e1 && (e1->base == G_CALL || e1->base == CALL) &&
e2 && e2->base == G_ADDROF)
return this;
case CM:
if (e2 && e2->base == G_CALL) { // (x,f())=>(x,(tmp=f(),&tmp))
Pname tmp = make_tmp('Q',e2->tp,cc->ftbl);
e2 = init_tmp(tmp,e2,cc->ftbl);
Pexpr aa = tmp->address();
e2 = new expr(G_CM,e2,aa);
e2->tp = aa->tp;
}
else e2 = e2->address(); // &(e1,e2) => (e1,&e2)
tp = e2->tp; //LLL
return this;
case INCR:
case DECR: // &(++a) => (++a,&a)
if (e1) break;
nin++;
if (e2->not_simple()) error('s',"& of%k",base);
nin--;
e1 = new expr(base,0,e2);
e2 = e2->address();
base = G_CM;
tp = e2->tp;
return this;
case ASSIGN: // &(a=b) => ((a=b),&a)
case ASPLUS:
case ASMINUS:
case ASMUL:
case ASDIV:
case ASMOD:
case ASAND:
case ASOR:
case ASER:
case ASLS:
case ASRS:
{
nin++;
if (e1->not_simple()) error('s',"& of%k",base);
nin--;
Pexpr a = new expr(base,e1,e2);
a->tp = a->e1->tp;
base = G_CM;
e1 = a;
e2 = a->e1->address();
tp = e2->tp;
return this;
}
case NAME:
Pname(this)->take_addr();
if (Pname(this)->n_xref)
// function argument of class type becomes
// class* due to user-defined copy ctor
return this;
break;
case CALL:
case CAST:
case G_CAST:
case NEW:
case GNEW:
if (tp && tp->is_ptr_or_ref()) { // hack?
return this;
}
break;
}
register Pexpr ee = new expr(G_ADDROF,0,this);
if (tp) { // tp==0 ???
ee->tp = tp->addrof();
switch (tp->base) {
case PTR:
Pptr(ee->tp)->memof = Pptr(tp)->memof;
break;
case FCT:
if (Pfct(tp)->f_static==0)
Pptr(ee->tp)->memof = Pfct(tp)->memof;
break;
case OVERLOAD:
if (Pfct(Pgen(tp)->fct_list->f->tp)->f_static==0)
Pptr(ee->tp)->memof = Pfct(Pgen(tp)->fct_list->f->tp)->memof;
}
}
return ee;
}
Pexpr make_dot(Pexpr e, Ptable tbl, char* c)
{
if(!e->tp->memptr())
return e;
if(e->base==CM || e->base==G_CALL || e->base==CALL || e->base==ASSIGN) {
Pname atmp = make_tmp('A',e->tp,tbl);
Pexpr as = init_tmp(atmp,e,tbl);
e = new mdot(c,atmp);
e->i1 = 9;
e = new expr(G_CM,as,e);
}
else if(e->base == ILIST) {
if (c[0]=='i') e = e->e1->e2;
if (c[0]=='f') e = e->e2;
}
else {
e = new mdot(c,e);
e->i1 = 9;
}
return e;
}
Pexpr expr::contents()
{
//error('d',"deref %k %d %t",base,base,tp);
switch (base) {
case ADDROF:
case G_ADDROF:
return e2; // *&
case ELIST:
//error('d',"contents of elist");
e1 = e1->contents();
tp = e1->tp;
return this;
};
register Pexpr ee = new expr(DEREF,this,0);
if (tp) { // tp==0 ???
Ptype tt = tp->skiptypedefs();
ee->tp = Pptr(tt)->typ;
Pname cn = ee->tp->is_cl_obj();
if (cn) {
// look for first use of class
Pclass cl = Pclass(cn->tp);
if (cl->c_body==1) cl->dcl_print(0);
}
}
return ee;
}
#if 0
static Pexpr
make_postfix( Pexpr op, Pname fn=0 )
{
/* apply the postfix form of increment/decrement operator
* if (fn) special call from check_postscipt to handle
* the two operator instances declared at different scopes
* i.e., member and non-member, therefore stored as FCTs.
*/
Pfct f;
Plist fl;
Pname n = fn?fn:0;
Pexpr e = op->e1->base==NAME?op->e1:op->e1->mem;
if (n) goto mk_postfix; // sorry(!!!)
for (fl=Pgen(e->tp)->fct_list;fl; fl=fl->l) {
n = fl->f;
f = Pfct(n->tp);
if ((f->nargs==1 && f->f_this) ||
(f->nargs==2 && f->f_this==0)) {
mk_postfix: // rewrite the call expression
if (op->e1->base == NAME) {
op->e1 = n;
op->e2->e2 = new expr(ELIST,zero,0);
} else {
op->e1->mem = n;
op->e2 = new expr(ELIST,zero,0);
}
op->fct_name = n;
n->dcl_print(0);
return op;
}
}
error('w',"no postfix instance of%n, although overloaded",Pname(e));
return op; // as it were
}
static Pexpr
check_postfix( Pexpr op )
{
/* special case: member and non-member operator++/-- instances
* each stored as FCT, and so oper_overload() returns prefix instance
* need to make an explicit check if postfix instance exists
*/
int is_glob = op->e1->base==NAME ? 1: 0;
Pname fn = is_glob ? Pname(op->e1) : Pname(op->e1->mem);
// error('d',"check_postfix: fn: %n is_glob: %d",fn,is_glob);
if (is_glob == 0) { // found operator++/--() as member
Pname n = gtbl->look(fn->string,0);
Ptype arg_tp = op->e1->e1->tp;
if (n==0) return op;
if (n->tp->base == FCT) { // one global instance
Pfct ff = Pfct(n->tp);
// error('d',"check_postfix: global n:%n arg: %t act: %t",n,ff->argtype->tp,arg_tp);
extern int exact1(Pname,Ptype); // place in cfront.h
if (ff->nargs != 2) return op;
if (exact1(ff->argtype, arg_tp)==0) return op;
return make_postfix(op,n);
}
if (n->tp->base == OVERLOAD) { // multiple global instances
for (Plist fl=Pgen(n->tp)->fct_list; fl; fl=fl->l) {
Pname nn = fl->f;
Pfct ff = Pfct(nn->tp);
if (ff->nargs != 2) continue;
if (exact1(ff->argtype, arg_tp)==0) continue;
return make_postfix(op,nn);
}
return op;
}
}
else { // examine class table for postfix member
Pfct f = Pfct(fn->tp);
Pptr p = f->argtype->tp->is_ptr_or_ref();
Ptype t = p?p->typ:f->argtype->tp;
Pname cn = t->is_cl_obj();
if (cn == 0) error('i',"check_postfix: %n(%n %t),CTX",fn,f->argtype,t);
Pname nn = Pclass(cn->tp)->memtbl->look(fn->string,0);
// error('d',"check_postfix: found: %n %t", nn, nn->tp);
if (nn) return make_postfix(op,nn);
return op;
}
error('i', "fall off end of check_postfix()");
return 0;
}
#endif
int bound;
int chars_in_largest; // no of characters in largest int
static bit
ptr_is_template_formal(Pptr p)
{
// error('d',"ptr_is_template_formal: %t",p);
if (p->typ) {
if (p->typ->base != TYPE) return 0;
Pname n = p->typ->bname();
return n->is_template_arg();
} else
return 0;
}
Ptype common_base(Pclass cl1, Pclass cl2)
/*
do cl1 and cl2 have one common base class?
*/
{
if (cl1 == 0 || cl2 == 0) return 0;
if (cl1->baselist == 0 || cl2->baselist == 0) return 0;
Pbase answer = 0;
for (Pbcl b = cl1->baselist; b; b=b->next) {
if (b->ppp!=PUBLIC && !same_class(cc->cot,cl1)
&&
(cc->nof==0 || cl1->has_friend(Pfct(cc->nof->tp))==0)
&&
(cc->cot==0 || cl1->has_friend(cc->cot)==0)
)
continue;
Nvis = 0;
if (cl2->has_base(b->bclass)) {
if (Nvis) continue;
if (answer) return 0;
Pname bn = new name(b->bclass->string);
bn->tp = b->bclass;
answer = new basetype(COBJ,bn);
}
}
return answer;
}
static Pexpr
do_qualifiers( Ptype t, Pexpr mem )
/*
** saw ( (t*) p )->mem
** if mem has unprocessed qualifiers, look up qualifier names
*/
{
// qualifiers after . or -> processed after type of base object is known
Pname m = Pname(mem);
if ( m->base != NAME && m->base != DTOR
|| m->n_qualifier == 0
|| m->n_qualifier->base != MEMQ )
return mem;
Pname cn = t ? t->is_cl_obj() : 0;
Pname tn = 0;
Pname q = m->n_qualifier;
m->n_qualifier = 0;
if ( q->string == 0 ) { // ->::
//error("scope qualification syntax");
do {
Pname qx = q->n_list;
delete q;
q = qx;
} while ( q && q->string == 0 );
if ( q == 0 ) { m->n_initializer = sta_name; return mem; }
tn = k_find_name(q->string,Gtbl,HIDDEN);
} else if ( cn )
tn = k_find_name(q->string,Pclass(cn->tp)->k_tbl,HIDDEN);
else
tn = k_find_name(q->string,Ctbl,HIDDEN);
/* // check if first qualifier is a base class of cn
** if ( cn && tn ) {
** Pclass cl = Pclass(cn->tp);
** Pname qn = tn->is_cl_obj();
** if (qn && !same_class(Pclass(qn->tp),cl)) { // really a base?
** Pclass qcl = Pclass(qn->tp);
** Pclass bcl = cl->is_base(qcl->string);
** if (bcl == 0 || !same_class(bcl,qcl)) {
** error("(%n*)->%n:: --%n is not aBC of%n",cn,qn,qn,cn);
** return mem;
** }
** }
** }
*/
Pname cx = 0;
for(;;) {
if ( tn == 0 ) {
error("%n :: --TN%n not found",q,q);
return mem;
}
cn = tn->tp->is_cl_obj();
if ( cn == 0 ) {
// if at the final qualifier and mem is
// a dtor, mem could be a basic type dtor,
// in which case the qualifier doesn't have
// to be a class name
if ( q->n_list==0 && m->base==DTOR )
m->n_qualifier = tn;
else
error("%n :: --%n is not aCN",tn,tn);
return mem;
}
if ( cx ) { // cx::cn::
if ( Pclass(cx->tp)->has_base(Pclass(cn->tp)) )
error("%n ::%n :: --%n not aM of%n",cx,cn,cn,cx);
}
cx = cn;
{ Pname qx = q->n_list; delete q; q = qx; }
if ( q == 0 ) break;
if ( q->string == 0 ) { // ->X:: ::
error("scope qualification syntax");
return mem;
}
tn = k_find_member(q->string,Pclass(cn->tp),HIDDEN);
}
m->n_qualifier = tn;
return mem;
}
static Pexpr
do_dtor( Ptype t, Pexpr mem)
{
Pname m = Pname(mem);
// m->base == DTOR
// represents
// p->something::~something
// something::~something
// p->~something
// where t == type of *p or 0
// fields of m (see dummy_dtor() in gram.y):
// X::~Y m->n_qualifier==X m->n_dtag==Y
// int::~int m->tp2==int_type m->tpdef==int_type
// X::~int m->n_qualifier==X m->tpdef==int_type
// int::~Y m->tp2==int_type m->n_dtag==Y
// etc
Pname q = m->n_qualifier;
Pname d = m->n_dtag;
Pname cn = (t ? t->is_cl_obj() : 0);
DB(if(Edebug>=1){
error('d',"do_dtor: t%t b%k cn%n",t,m->base,cn);
error('d'," q%n d%n tp2%t tpdef%t",q,d,m->tp2,m->tpdef);
error('d'," qtp%t dtp%t",q->tp,d->tp);
});
if ( cn ) { // cp->something::~something -- look up qualifier again
// q already looked up in do_qualifiers()
if ( d && d->string ) {
Pclass cl = (q && q->tp->is_cl_obj())
? q->tp->skiptypedefs()->classtype()
: Pclass(cn->tp);
Pname dx = k_find_name(d->string,cl->k_tbl,HIDDEN);
if (dx == 0) { error("TN%n not found in%t",d,t); dx = q; }
d = m->n_dtag = dx;
}
}
DB(if(Edebug>=1){
error('d'," new q%n%t d%n%t",q,q?q->tp:0,d,d?d->tp:0);
});
if ( q ) {
if ( d && d->tp->check(q->tp,0) ) {
error("bad syntax for destructor call:N andQr do not match");
q = d;
} else if ( m->tpdef && m->tpdef->check(q->tp,0) )
error("bad syntax for destructor call:N andQr do not match");
if ( d && d->tp->is_cl_obj() ) {
real_dtor:
m->base = NAME;
//// m->n_dtag = 0; // Keep n_dtag for find_name if needed.
m->tp = m->tpdef = m->tp2 = 0;
m->string = oper_name(DTOR);
m->n_oper = DTOR;
} else {
if ( m->tpdef ) m->tp2 = m->tpdef;
else m->tp2 = m->tpdef = q->tp;
m->n_qualifier = m->n_dtag = 0;
}
}
else { // int::~something or p->~something
if ( d && m->tp2==0 && d->tp->is_cl_obj() ) {
goto real_dtor;
}
if ( d && m->tp2 && d->tp->check(m->tp2,0) )
error("bad syntax for destructor call:N andQr do not match");
if ( d ) { m->tp2 = m->tpdef = d->tp; m->n_dtag = 0; }
}
DB(if(Edebug>=1)error('d',"do_dtor: returning%k%t",mem->base,mem->tp););
// If "t" is provided, check that the type of the object referenced
// agrees with the type associated with the DTOR or that the DTOR
// is an accessible base class of that object.
if ( t ) {
if ( mem->tp2 ) {
// i.int::~int() or some basic type.
if ( t->check(mem->tp2,0) ) {
error("T mismatch for simpleT destructor:XO ofT%t",mem->tp2);
} /* if */
} else {
if (cn) {
// The object referenced is a class object; the DTOR must be for
// the same object or at least a base class.
if ( d && t->check(d->tp,0) ) {
// This was not an identical match. Check if a DTOR of a
// base class before complaining of an error.
Pname dn = ( d->tp ? d->tp->is_cl_obj() : 0 );
if ( cn && dn ) {
if ( ! q && ! Pclass(cn->tp)->has_base(Pclass(dn->tp)) ) {
// The class of the DTOR is not a
// base class of the referenced object. The
// "X is not a base class of Y" message will
// be generated by find_name later in
// expr::typ().
error("bad syntax for destructor call");
} /* if */
} else {
error("T mismatch for destructor:XO ofT%t", d->tp);
} /* if */
} /* if */
} else {
error("T mismatch for destructor:XO ofT%t", d->tp);
} /* if */
} /* if */
} /* if */
return mem;
}
#define nppromote(b) t=np_promote(b,r1,r2,t1,t2,1)
#define npcheck(b) (void)np_promote(b,r1,r2,t1,t2,0)
Pname Ntmp_flag_list;
bit in_quest;
con_dtor *pdlist;
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"
*/
{
Pname n;
Ptype t = 0;
Ptype t1, t2;
TOK b = base;
TOK r1, r2;
if (tbl->base != TABLE) error('i',"expr::typ(%d)",tbl->base);
DB( if(Tdebug>=1) {
error('d',"%d->expr::typ(%d) %k %t",this,tbl,b,tp);
display_expr(this);
});
// error('d',"%k->typ %n tp: %t", b,b==NAME?this:0,tp);
// error('d'," e1 %d %k e1 %d %k",e1,e1?e1->base:0,e2,e2?e2->base:0);
if (tp) {
switch (b) {
case NAME:
break;
case MDOT:
mem = mem->typ(tbl);
} ;
return this;
}
switch (b) { // is it a basic type
case MDOT:
error('i',"mdot %s",string2);
case DUMMY:
error("emptyE");
tp = any_type;
case DTOR: // dummy type destructor
{
Pexpr e = do_dtor(0,this);
return e->base==NAME ? e->typ(tbl) : e;
}
case ZERO:
tp = zero_type;
return this;
case IVAL:
tp = int_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':
switch (string[ll-2]) {
case 'u':
case 'U':
string[ll-2] = 0;
tp = ulong_type;
goto cast_n_save;
}
lng:
tp = long_type;
goto save;
case 'u':
case 'U': // 1u => unsigned(1)
switch (string[ll-2]) {
case 'l':
case 'L':
string[ll-2] = 0;
ulng:
tp = ulong_type;
goto cast_n_save;
default:
string[ll-1] = 0;
labuint:
tp = uint_type;
goto cast_n_save;
}
}
// no suffix - see if we can figure it out
if (string[0] == '0') { // assume 8 bits in byte
register int index = 1;
switch (string[1]) {
case 'x':
case 'X':
{
while(string[++index]=='0') ;
ll -= index;
int HSZ = SZ_INT+SZ_INT;
if(ll < HSZ) goto nrm;
if(ll == HSZ)
if(string[2]>='8') goto labuint;
else goto nrm;
if(SZ_INT==SZ_LONG) break;
HSZ = SZ_LONG+SZ_LONG;
if(ll < HSZ) goto lng;
if(ll == HSZ)
if(string[2]>='8') goto ulng;
else goto lng;
break;
}
default: // OCTAL
{
register int IBITS = BI_IN_BYTE*SZ_INT;
while(string[index]=='0') index++;
register char x = string[index];
int lbt = x=='1' ? 1 :
( x=='2' || x=='3' ? 2 : 3 );
int nbits = (ll-index-1)*3 + lbt;
if(nbits < IBITS) goto nrm;
if(nbits == IBITS) goto labuint;
if(nbits < BI_IN_BYTE*SZ_LONG) goto lng;
}
}
goto ulng;
}
else { // DECIMAL
if (ll<chars_in_largest) {
nrm:
tp = int_type;
goto save;
}
if (ll>chars_in_largest) {
if(SZ_INT==SZ_LONG || ll>2*chars_in_largest)
goto ulng;
goto lng;
}
// ll == chars_in_largest
char* p = string;
char* q = LARGEST_INT;
do if (*p>*q) {
if(SZ_INT==SZ_LONG) goto ulng;
goto lng;
} while (*p++==*q++ && *p);
}
goto nrm;
}
case CCON:
tp = c_strlen(string)<5 ? char_type : int_type; // stored as 'a'
goto save;
case FCON:
{ int ll = strlen(string);
int last = string[ll-1];
tp = double_type;
if (last=='F' || last=='f') {
tp = float_type;
if (!ansi_opt) {
string[ll-1] = 0;
goto cast_n_save;
}
}
else if (last=='L' || last=='l') {
if (ansi_opt == 0) string[ll-1] = 0;
tp = ldouble_type;
}
goto save;
}
case STRING: // type of "as\tdf" is char[6]
// c_strlen counts the terminating '\0'
{ Pvec v = new vec(char_type,0);
v->size = c_strlen(string);
tp = v;
}
save:
if (const_save) { // "as\tdf" needs 7 chars for storage
char* p = new char[strlen(string)+1];
strcpy(p,string);
string = p;
}
return this;
cast_n_save:
if (const_save) { // "as\tdf" needs 7 chars for storage
char* p = new char[strlen(string)+1];
strcpy(p,string);
string = p;
}
return new cast(tp,this);
case THIS:
delete this;
if (cc->c_this) {
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:
{
Pname q = Pname(this)->n_qualifier; // suppress virtual iff x::
Pexpr ee = find_name(Pname(this),cc->cot,tbl,0,cc->nof);
if (q && (ee->base==REF || ee->base==DOT))
ee->n_initializer = Pexpr(q);
if(
cc->nof
&&
Pfct(cc->nof->tp)->f_const
&&
(ee->base==REF||ee->base==DOT)
&&
ee->tp
&&
ee->tp->skiptypedefs()->base!=FCT
&&
ee->tp->skiptypedefs()->base!=OVERLOAD
)
ee->tp = ee->tp->mkconst();
//error('d',"ee %k %t %n",ee->base,ee->tp,ee->base==NAME?ee:ee->base==REF?ee->mem:0);
if (ee->tp->is_ref()) return ee->contents();
if (ee->base==NAME && Pname(ee)->n_xref) {
// fudge to handle X(X&) args
ee = new expr(DEREF,ee,0);
ee->tp = ee->e1->tp; // !!
}
return ee;
}
case ADDROF:
if (e2->base == THIS) {
error("&this");
break;
}
case G_ADDROF: // handle lookup for &s::i
if (e2->base == NAME) e2 = find_name(Pname(e2),cc->cot,tbl,ADDROF,cc->nof);
if(
cc->nof
&&
Pfct(cc->nof->tp)->f_const
&&
(e2->base==REF||e2->base==DOT)
&&
e2->tp
&&
e2->tp->skiptypedefs()->base!=FCT
&&
e2->tp->skiptypedefs()->base!=OVERLOAD
)
e2->tp = e2->tp->mkconst();
if (e2->base==NAME && Pname(e2)->n_xref) {
// fudge to handle X(X&) args
e2 = new expr(DEREF,e2,0);
e2->tp = e2->e1->tp; // !!
}
if (e2->base==DOT) { // &f().x = > &(tmp=f(),&tmp)->x
switch (e2->e1->base) {
case CALL:
case G_CALL:
{
Pcall c=Pcall(e2->e1);
if (c && c->e1) {
c->e1=c->e1->typ(tbl);
if (c->e1->tp && Pfct(c->e1->tp)->returns->base==RPTR) break;
}
}
case VALUE:
error("& non-lvalue");
}
}
break;
case SIZEOF:
if (tp2) {
tp2->dcl(tbl);
switch (tp2->base) {
case VOID:
error("sizeof(void)");
break;
case CLASS:
{
Pclass cl = Pclass(tp2);
if (cl->c_body==1
&& (cl->defined&(DEFINED|SIMPLIFIED)) == 0)
error('s',"class defined within sizeof");
}
}
if (e1 && e1!=dummy) {
e1 = e1->typ(tbl);
DEL(e1);
e1 = dummy;
}
Pptr r = tp2->is_ref();
if (r) tp2 = r->typ; // sizeof(T&)==sizeof(T)
}
else if (e1 == dummy) {
error("sizeof emptyE");
tp = any_type;
return this;
}
else {
++processing_sizeof;
e1 = e1->typ(tbl);
--processing_sizeof;
tp2 = e1->tp;
if(tp2->base == VEC) tp2->permanent = 1;
if (e1->base==ILIST) // PtoM
e1 = dummy;
else if (tp2 == char_type) // sizeof ('a')
e1 = dummy;
}
(void) tp2->tsizeof();
if (tp2->base==VOID) error("sizeof(void)");
tp = size_t_type;
return this;
case CAST:
case G_CAST:
{ Pexpr ee = docast(tbl);
return ee->tp->is_ref() ? ee->contents() : ee;
}
case VALUE:
//SYM obsolete table hack removed
return dovalue(tbl);
case NEW:
case GNEW:
return donew(tbl);
case DELETE: // delete e1 OR delete[e2] e1
case GDELETE:
{ int i;
//if (e1->base == ADDROF) error('w',"delete &E");
e1 = e1->typ(tbl);
if (e1->tp->skiptypedefs()->base == COBJ) {
Pexpr x = try_to_coerce(Pvoid_type,e1,"argument",tbl);
if (x) e1 = x;
}
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;
}
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;
if (t->base == FCT) { // yuk!
ee = new expr(G_ADDROF,0,e->e1);
e->e1 = ee->typ(tbl);
t = e->e1->tp;
}
}
tp = t;
return this;
}
case DOT:
case REF:
{
if (e2) { // .* or ->*
if (b == REF) b = base = REFMUL;
if (e2->base == NAME && Pname(e2)->permanent != 1) PERM(Pname(e2));
break;
}
Pbase b;
bit bcc;
e1 = e1->typ(tbl);
t = e1->tp->skiptypedefs(bcc);
if ( base==DOT &&
e1->base==DEREF &&
e1->e1->base==NAME &&
is_probably_temp(Pname(e1->e1)->string)
)
bcc=0;
// check that . (->) is applied to class object (pointer)
if (base == REF) {
switch (t->base) {
case COBJ:
{
Pname n = t->classtype()->has_oper(REF);
if (n) {
n->n_used += 2;
e1 = new call(new ref(DOT,e1,new name(n->string)),0);
return typ(tbl);
}
// no break;
}
default:
error("nonP ->%n",mem);
t = any_type;
// no break;
case ANY:
goto qqq;
case PTR:
case VEC:
b = Pbase(Pptr(t)->typ->skiptypedefs(bcc));
mem = do_qualifiers(b,mem);
if (mem->base == DTOR) mem = do_dtor(b,mem);
}
}
else { // base == DOT
qqq:
mem = do_qualifiers(t,mem);
switch (t->base) {
default:
if (mem->base == DTOR) mem = do_dtor(t,mem);
if ( mem->base == DTOR ) // i.int::~int(), etc
break;
error("nonO .%n",mem); t = any_type;
case ANY:
break;
case COBJ:
if (mem->base == DTOR) mem = do_dtor(t,mem);
}
//error('d',"dot %k",e1->base);
switch (e1->base) {
case QUEST:
case ASSIGN:
case INCR:
case DECR:
case ASPLUS:
case ASMINUS:
case ASMUL:
case ASDIV:
case ASMOD:
case ASAND:
case ASOR:
case ASER:
case ASLS:
case ASRS:
case CM:
case G_CM:
base = REF;
e1 = e1->address();
break;
case CALL:
case G_CALL:
//error('d'," f(). %n mem->tp %t",e1->fct_name,mem->tp);
#ifdef FDOTRIGHT
// this rewrite is only necessary on machines with broken C compilers
// there seems to be a lot of those
// and for inlines (a,b).c
if (e1->fct_name && Pfct(e1->fct_name->tp)->f_inline)
#endif
{ // f(). => (tmp=f(),&tmp)->
Pname tmp = make_tmp('Q',e1->tp,tbl);
//error('d',"fdot2 %k",e1->base);
e1 = init_tmp(tmp,e1,tbl);
Pexpr aa = tmp->address();
e1 = new expr(G_CM,e1,aa);
e1->tp = aa->tp;
base = REF;
break;
}
}
b = Pbase(t);
}
switch (b->base) {
default:
if ( mem->base == DTOR ) { // i.int::~int(), etc.
// // Error check moved into do_dtor().
// if ( mem->tp2 && Ptype(b)->check(mem->tp2,0) )
// error("T mismatch for simpleT destructor:XO ofT%t",mem->tp2);
return mem;
} else
error("(%t) before%k%n (%n not aM)",e1->tp,base,mem,mem);
case ANY:
tp = any_type;
return this;
case COBJ:
{
Pclass cl = b->classtype();
if (cl->c_body == 1) cl->dcl_print(0);
break;
}
}
/*
x.m is not a const even if x is a const object, this case is handled
by lval() rejecting it
*/
if (mem->tp) {
tp = mem->tp;
for (Pexpr ee = mem; ee->base==REF; ee = ee->e1) {
if (ee->e1 == cc->c_this) { // this-> => p->
ee->e1 = e1;
ee->base = base;
if(
bcc
&&
mem->tp
&&
mem->tp->skiptypedefs()->base!=FCT
&&
mem->tp->skiptypedefs()->base!=OVERLOAD
)
mem->tp = mem->tp->mkconst();
return mem->tp->is_ref() ? mem->contents() : mem;
}
}
return tp->is_ref() ? contents() : this;
}
Pname q = Pname(mem)->n_qualifier;
// For a DTOR without a qualifier, ie. p->~A(), use the
// n_dtag as if it were a qualifier to insure getting
// the DTOR for the correct base class. This will also
// generate a "X is not a base class of Y" message to
// supplement a "bad syntax for destructor call" diagnostic
// generated in do_dtor().
if ( !q && (strcmp(Pname(mem)->string, oper_name(DTOR)) == 0)) {
Pname(mem)->n_qualifier = Pname(mem)->n_dtag;
} /* if */
Pexpr e = find_name(Pname(mem),b->classtype(),0,base,cc->nof);
if (q && (e->base==REF || e->base==DOT)) {
Pname(e)->n_initializer = Pexpr(q);
//error('d',"q%n e%k%t%n",q,e->base,e->tp,e->base==NAME?e:e->base==REF?e->mem:0);
}
for (Pexpr ee = e; ee->base==REF; ee = ee->e1) {
if (ee->e1 == cc->c_this) { // this-> => p->
ee->e1 = e1;
ee->base = base;
if(
bcc
&&
e->tp
&&
e->tp->skiptypedefs()->base!=FCT
&&
e->tp->skiptypedefs()->base!=OVERLOAD
)
e->tp = e->tp->mkconst();
break;
}
}
if (e->base == NAME) {
switch (e->tp->base) {
case FCT:
case OVERLOAD:
mem = e;
tp = e->tp;
e = this;
}
}
// function or static member
return e->tp->is_ref() ? e->contents() : e;
}
case CALL: /* handle undefined function names */
//error('d',"call %k %t %k",e1->base,e1->tp,e2?e2->base:0);
if (e1->base==NAME && e1->tp==0) {
Pname q = Pname(e1)->n_qualifier;
e1 = find_name(Pname(e1),cc->cot,tbl,CALL,cc->nof);
//error('d',"e1 %k %t %n",e1->base,e1->tp,e1->base==NAME?e1:e1->base==REF?e1->mem:0);
if (q && (e1->base==REF ||e1->base==DOT)) // suppress virtual call
e1->n_initializer = Pexpr(q);
}
if (e1->base==NAME && Pname(e1)->n_xref) {
// fudge to handle X(X&) args
e1 = new expr(DEREF,e1,0);
e1->tp = e1->e1->tp; // !!
}
switch (e1->base) {
case DTOR:
// This is an explicit DTOR call without -> or .
error('e', "O orP missing for explicit destructor call\n");
break;
case DOT:
case REF: // becomes ob.x::~x(0) or
if (e2==0 // becomes p->x::~x(0)
&& Pref(e1)->mem
&& Pref(e1)->mem->base==DTOR ) {
Pref r = Pref(e1);
if ( r->base == DOT ) {
r->e1 = new expr(ADDROF,0,r->e1);
r->base = REF;
}
Pname m = Pname( r->mem );
bit qual = m->n_qualifier != 0;
int tok = qual ? 0 : REF;
// tok==REF => allow virtual call in call_dtor()
// error('d',"qual: %d, e1: %k tok: %d", qual, e1->base, tok );
e1 = e1->typ(tbl);
// The memory pointed to by the previous value of
// "r->mem" or "m" has been deleted.
r = Pref(e1);
m = Pname(r->mem);
if ( m->base == NAME ) { // "real" dtor
Pexpr ee = call_dtor(e1->e1,r->mem,0,tok,one);
ee->tp = void_type;
return ee;
} /* if */
} /* if */
}
break;
case QUEST:
Ntmp = 0;
Ntmp_flag = 0;
if (in_quest < 1) {
Ntmp_refd = 0;
Ntmp_flag_list = 0;
}
cond = cond->typ(tbl);
in_quest++;
if (Ntmp_refd) {
Pname n = Ntmp_refd;
Pname nn = Ntmp_flag_list;
for (; n && nn; n = n->n_list, nn = nn->n_list) {
// error('d',"pdlist: n: %n nn: %n",n,nn);
Pname nc = new name("");
*nc = *n;
nc->string = new char[strlen(n->string) + 1];
strcpy(nc->string, n->string);
Pname nnc = new name("");
*nnc = *nn;
nnc->string = new char[strlen(nn->string) + 1];
strcpy(nnc->string, nn->string);
con_dtor *t = new con_dtor(nc, nnc);
if (pdlist) t->next = pdlist;
pdlist = t;
}
Ntmp_flag = 0;
}
break;
case ANDAND:
case OROR:
Ntmp = 0;
Ntmp_flag = 0;
if (in_quest < 2) {
Ntmp_refd = 0;
Ntmp_flag_list = 0;
}
}
if (e1) {
e1 = e1->typ(tbl);
if (e1->tp->is_ref()) e1 = e1->contents();
t1 = e1->tp;
if (Ntmp_flag) {
if (b==QUEST || in_quest ) {
Pexpr e = new expr(ASSIGN,Ntmp_flag,one);
e->tp = int_type;
e1 = new expr(G_CM,e,e1);
e1->tp = t1;
}
Ntmp_flag = 0;
}
}
else
t1 = 0;
if (e2) {
e2 = e2->typ(tbl);
if (e2->tp->is_ref()) e2 = e2->contents();
t2 = e2->tp;
if (Ntmp_flag) {
if (b==QUEST || in_quest) {
Pexpr e = new expr(ASSIGN,Ntmp_flag,one);
e->tp = int_type;
if (e2->base == ELIST) {
Ptype t = e2->e1->tp;
e2->e1 = new expr(G_CM,e,e2->e1);
e2->e1->tp = t;
} else {
e2 = new expr(G_CM,e,e2);
e2->tp = t2;
}
}
Ntmp_flag = 0;
}
}
else
t2 = 0;
switch (b) { // filter out non-overloadable operators
default:
{
Pexpr x = oper_overload(tbl);
if (x) {
if (x->tp != any_type
&&
(b==INCR || b==DECR)
&&
x->base != INCR && x->base != DECR
) {
#if 0
if (t2==0 && t1) { // postfix
Pexpr ox = x;
Pexpr fe;
if (x->base == DEREF
&&
x->e1->tp->is_ref()
)
x = x->e1;
fe = x->e1->base==NAME?x->e1:x->e1->mem;
if (fe->tp->base==OVERLOAD)
x = make_postfix(x);
else x = check_postfix(x);
if (
(warning_opt || strict_opt)
&&
x->e2==0
)
error(warning_opt?'w':0,"prefix ``%k'' used for postfix call (anachronism)",b);
if (x != ox) {
x->tp = 0;
x = x->typ(tbl);
}
}
#endif
}
return x;
}
if (t2 && t1==0 && t2!=e2->tp) t2 = e2->tp;
}
case DOT:
case G_CM:
case G_ADDROF:
case G_CALL:
case QUEST:
break;
}
switch (b) {
case QUEST:
in_quest--;
case ANDAND:
case OROR:
if (Ntmp && b != QUEST ) {
Ntmp_dtor = new expr(ELIST,this,Ntmp_dtor);
// error('d',"(e %d) temp ofC%n with dtor needed in%kE",this,Ntmp,b);
}
if (b==QUEST && Ntmp_refd) {
Pname n = Ntmp_refd;
Pname nn = Ntmp_flag_list;
for (; n && nn; n = n->n_list, nn = nn->n_list) {
// error('d',"pdlist: n: %n nn: %n",n,nn);
Pname nc = new name("");
*nc = *n;
nc->string = new char[strlen(n->string) + 1];
strcpy(nc->string, n->string);
Pname nnc = new name("");
*nnc = *nn;
nnc->string = new char[strlen(nn->string) + 1];
strcpy(nnc->string, nn->string);
con_dtor *t = new con_dtor(nc, nnc);
if (pdlist) t->next = pdlist;
pdlist = t;
}
Ntmp_flag = 0;
}
}
t = (t1==0) ? t2 : (t2==0) ? t1 : 0;
switch (b) { /* are the operands of legal types */
case REFMUL:
base = REF;
// no break;
case DOT:
{ // a .* p => &a MEMPTR p => appropriate indirection
// to be considered: what happens if a .* expression
// is used except in a call/=?
Pexpr a = e1->typ(tbl);
Ptype at = a->tp->skiptypedefs();
if (base == DOT) {
a = a->address();
at = at->addrof(); // beware of n_xref
}
Pname cn = at->base==PTR ? Pptr(at)->typ->is_cl_obj() : 0;
Pclass mm = cn ? Pclass(cn->tp) : 0;
Pexpr p = e2->typ(tbl);
Ptype pt = p->tp->skiptypedefs();
Pname pcn = pt->is_cl_obj();
//error('d',"mm %t pt %t",mm,pt);
if (pcn) {
Pclass cl = Pclass(pcn->tp);
Pname found = 0;
for (Pname on=cl->conv; on; on=on->n_list) {
Pfct f = Pfct(on->tp);
Pptr frt = Pptr(f->returns->skiptypedefs());
if (frt->base!=PTR || Pptr(frt)->memof==0) break;
if (same_class(Pptr(frt)->memof,mm) || mm->has_base(Pptr(frt)->memof)) {
if (found)
error("two possible conversions forP toM: %n and %n",found,on);
else
found = on;
}
}
//error('d',"found %n",found);
if (found) {
p = new ref(DOT,p,found);
p = new call(p,0);
p = p->typ(tbl);
pt = p->tp->skiptypedefs();
}
}
if (pt->base!=PTR || Pptr(pt)->memof==0) {
if (b==DOT)
error("P toMX in .*E: %t",pt);
else
error("P toMX in ->*E: %t",pt);
tp = any_type;
base = DUMMY;
return this;
}
Pclass pm = Pptr(pt)->memof;
if ( !same_class(mm,pm) ) {
if (mm->has_base(pm) == 0) {
error("badOT in .*E: %t (%s*X)",a->tp,pm->string);
tp = any_type;
}
a = new texpr(G_CAST,pm->this_type,a);
e1 = a = a->typ(tbl);
}
Ptype tpx = Pptr(pt)->typ->skiptypedefs();
if (tpx->base == FCT) { // a.*p => (&a MEMPTR p)
base = MEMPTR;
tp2 = mm; // keep the class for simpl.c
e1 = a;
e2 = p;
}
else { // a .* p => *(typeof(p))((char*)&a + (int)p-1)
a = new cast(Pchar_type,a);
p = new cast(int_type,p);
p = new expr(MINUS,p,one);
p->tp = int_type;
Pexpr pl = new expr(PLUS,a,p);
pl->tp = Pchar_type;
base = DEREF;
pt = new ptr(PTR,tpx); // need a T* not a T C::*
Pptr(pt)->b_const = Pptr(tpx)->b_const;
e1 = new cast(pt,pl);
e2 = 0;
}
tp = tpx;
return tp->is_ref() ? contents() : this;
}
case G_CALL:
case CALL:
tp = call_fct(tbl); /* two calls of use() for e1's names */
if (tp->is_ref()) return contents();
return this;
case DEREF:
if (e1 == dummy) error("O missing before []\n");
if (e2 == dummy) error("subscriptE missing");
if (t) { /* *t */
t = t->skiptypedefs();
if (t->base==PTR && Pptr(t)->memof) error("P toM dereferenced");
tp = t->deref();
}
else { // e1[e2] that is *(e1+e2)
//error('d',"deref %t[%t]",t1,t2);
if (t1->vec_type()) { // e1[e2]
switch (t2->base) {
case CHAR:
case SHORT:
case INT:
case LONG:
case EOBJ:
break;
default:
{ Pname cn = t2->is_cl_obj();
if (cn) // conversion to integral?
e2 = check_cond(e2,DEREF,tbl);
else
t2->integral(DEREF);
}
}
t1 = t1->skiptypedefs();
if (t1->base==PTR && Pptr(t1)->memof) error("P toM dereferenced");
tp = t1->deref();
(void) tp->tsizeof();
}
else if (t2->vec_type()) { // really e2[e1]
t1->integral(DEREF);
t2 = t2->skiptypedefs();
if (t2->base==PTR && Pptr(t2)->memof) error("P toM dereferenced");
tp = t2->deref();
(void) tp->tsizeof();
}
else {
error("[] applied to nonPT:%t[%t]",t1,t2);
tp = any_type;
}
}
if (tp->is_ref()) return contents();
return this;
case G_ADDROF:
case ADDROF:
//error('d',"addrof(%d) %k %d",base,e2->base,e2->base);
{
switch (e2->base) { // potential lvalues
case G_CM:
if (base==ADDROF && e2->e2->base==NAME) {
// check for cfront generated result variable
char* s = e2->e2->string;
if (s[0]=='_' && s[1] && s[1]=='_') {
if (s[2] && (s[2]=='R' || s[2]=='V')) {
error("address of non-lvalue");
break;
}
}
}
case CM: // &(a,b) => (a,&b)
{
Pexpr ee = e2;
ee->tp = 0;
ee->e2 = new expr(base,0,ee->e2);
delete this;
return ee->typ(tbl);
}
case QUEST: // & (a?b:c) => (a?&b:&c)
{
Pexpr ee = e2;
ee->tp = 0;
ee->e1 = new expr(base,0,ee->e1);
ee->e2 = new expr(base,0,ee->e2);
delete this;
return ee->typ(tbl);
}
case INCR:
case DECR:
if (e2->e1) break;
case ASSIGN:
case ASPLUS:
case ASMINUS:
case ASMUL:
case ASDIV:
case ASMOD:
case ASAND:
case ASOR:
case ASER:
case ASLS:
case ASRS:
return e2->address();
}
int oerror_count = error_count;
if (e2->lval(ADDROF) == 0) {
if (error_count>oerror_count) { // error_count == oerror_count
// possible in case of & const
tp = any_type;
return this;
}
}
tp = t->addrof();
if (e2->tp->base == VEC) {
if(e2->base != NAME) {
base = G_CAST;
tp2 = tp;
e1 = e2;
e2 = 0;
return this;
}
}
if (t->base==FCT)
Pptr(tp)->memof = Pfct(t)->memof;
// if (t->tconst() && vec_const==0 && fct_const==0) Pptr(tp)->b_const = 1;
// ??? & (const T) is NOT T*const but const T*
switch (e2->base) {
case NAME:
mname: // check for &s::i
{ Pname n2 = Pname(e2);
Pname cn = (n2->n_table && n2->n_table!=gtbl) ? n2->n_table->t_name : 0;
// error('d',"n2 %k cn %n t %t",n2->base,cn,t);
if (cn == 0) break;
if (t->base==FCT && Pfct(t)->f_static) {
Pptr(tp)->memof = 0;
break;
}
switch (t->base) {
case OVERLOAD:
return e2;
case FCT:
// error('d', "cn->tp: %d, %k", cn->tp, cn->tp->base);
{
Pclass cl = Pclass(cn->tp);
Pptr(tp)->memof = cl; //SSS
if (Pfct(t)->f_virtual) {
// { 0,vtbl index,0 }
e1 = new ival(Pfct(t)->f_virtual);
e1 = new expr(ELIST,zero,e1);
e2 = zero;
base = ILIST;
return this;
} // use the pointer
// { 0,-1,(int(*)())ptr }
e1 = new ival(-1);
e1 = new expr(ELIST,zero,e1);
// e2 is the name
if(
Pname(e2)->n_oper == ASSIGN
&&
cl->memtbl->look(e2->string,0)->tp->base
!= OVERLOAD
) {
Pname nmw = new name;
*nmw = *((Pname)e2);
e2 = new cast(Pfct_type,nmw);
}
else {
e2 = new cast(Pfct_type,e2);
}
base = ILIST;
return this;
}
default:
if (n2->n_stclass != STATIC) { // offset + 1
e1 = new ival(n2->n_offset+1);
Pptr(tp)->memof = Pclass(cn->tp);
//error('d',"cl %d %s i %d",Pclass(cn->tp),Pclass(cn->tp)?Pclass(cn->tp)->string:"0",n2->n_offset);
}
else
return this;
}
//error('d',"int_type");
e1->tp = int_type;
e2 = 0;
tp2 = tp;
base = G_CAST;
return this;
}
case DOT:
case REF:
{
Pname m = Pname(e2->mem);
while ( m->base == MDOT ) m = Pname(Pexpr(m)->mem);
Pfct f = Pfct(m->tp);
if (t->base==FCT && Pfct(t)->f_static) {
Pptr(tp)->memof = 0;
break;
}
bit all_stat = 1;
if (f->base == OVERLOAD) {
Plist gl = Pgen(m->tp)->fct_list;
for(; gl; gl=gl->l) {
if (Pfct(gl->f->tp)->f_static == 0) {
all_stat = 0;
break;
}
}
}
if (f->base == FCT || f->base == OVERLOAD) { // &p->f
Pexpr q = Pname(e2)->n_initializer; // &p->x::f
if (q && bound==0 && e2->e1==cc->c_this) {
// FUDGE: &this->x::f => &x::f
DEL(e2);
e2 = m;
goto mname;
}
bound = 1;
if (f->base==OVERLOAD && all_stat==0
||
f->base==FCT && !f->f_static
) {
error(
"address of boundF (try using ``%s::*'' forPT and ``&%s::%s'' for address)",
m->n_table->t_name->string,
m->n_table->t_name->string,
m->string
);
}
if (q || f->f_virtual==0) {
// & x.f => & f
DEL(e2);
e2 = m;
}
}
break;
}
case MEMPTR:
// &(p->*q)
error("& .* E");
}
return this;
}
case UMINUS:
t->numeric(UMINUS);
tp = t;
return this;
case UPLUS:
tp = t;
if (t->num_ptr(UPLUS)=='P' || ansi_opt==0) {
base = PLUS;
e1 = zero;
}
return this;
case NOT:
e2 = check_cond(e2,NOT,tbl);
tp = int_type;
return this;
case COMPL:
t->integral(COMPL);
tp = t;
return this;
case INCR:
case DECR:
{
// error('d',"incr-decr: e1: %k e2: %k", e1?e1->base:0, e2?e2->base:0);
Pexpr e = e1?e1:e2; // e1!=0 ==> e++ or e--
// e1==0 ==> ++e or --e
e->lval(b);
switch(e->base) {
case QUEST:
e->tp=0;
e->e1 = e1 ? new expr(base,e->e1,0) : new expr(base,0,e->e1);
e->e2 = e1 ? new expr(base,e->e2,0) : new expr(base,0,e->e2);
delete this;
return e->typ(tbl);
case CM:
case G_CM:
e->tp=0;
e->e2 = e1 ? new expr(base,e->e2,0) : new expr(base,0,e->e2);
delete this;
return e->typ(tbl);
case INCR:
case DECR:
if(e->e1)
break;
nin++;
if(e->e2->not_simple())
error('s',"overly complex %k of %k",b,e->base);
nin--;
e = new expr(G_CM,e,e->e2->typ(tbl));
if (e1) e1=e; else e2=e;
// e1?e1:e2 = e;
return typ(tbl);
case ASSIGN:
case ASPLUS:
case ASMINUS:
case ASMUL:
case ASDIV:
case ASMOD:
case ASAND:
case ASOR:
case ASER:
case ASLS:
case ASRS:
nin++;
if(e->e1->not_simple())
error('s',"overly complex %k of %k",b,e->base);
nin--;
e = new expr(G_CM,e,e->e1->typ(tbl));
if (e1) e1=e; else e2=e;
return typ(tbl);
}
}
r1 = t->num_ptr(b);
if (r1=='P' && t->check(Pvoid_type,IGNORE_CONST)==0 &&
ptr_is_template_formal(Pptr(t))==0)
error("%k of void*",b);
tp = t;
return this;
}
if (e1==dummy || e1==0) error("operand missing for%k",b);
if (e2==dummy || e2==0) error("initializer missing for%k",b);
switch (b) {
case MUL:
case DIV:
r1 = t1->numeric(b);
r2 = t2->numeric(b);
nppromote(b);
break;
case PLUS:
r2 = t2->num_ptr(PLUS);
r1 = t1->num_ptr(PLUS);
nppromote(PLUS);
goto void_check;
case MINUS:
r2 = t2->num_ptr(MINUS);
r1 = t1->num_ptr(MINUS);
if (r2=='P' && r1!='P' && r1!='A') error("nonP - P");
nppromote(MINUS);
void_check:
// error('d',"t1: %t %k t2: %t %k", t1, t1->base, t2, t2->base);
if ((r1=='P' && t1->check(Pvoid_type,IGNORE_CONST)==0 &&
ptr_is_template_formal(Pptr(t1))==0)
|| (r2=='P' && t2->check(Pvoid_type,IGNORE_CONST)==0 &&
ptr_is_template_formal(Pptr(t2))==0))
error("%k of void*",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);
}
case MOD:
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);
if (r1=='P' && r2=='I') { // allow things like:
// if (p==2-2)
// YUCK!
Neval = 0;
long i = e2->eval();
if (Neval==0 && i==0) {
DEL(e2);
e2 = zero;
r2 = 'Z';
}
}
else if (r2=='P' && r1=='I') {
Neval = 0;
long i = e1->eval();
if (Neval==0 && i==0) {
DEL(e1);
e1 = zero;
r1 = 'Z';
}
}
if (b!=EQ && b!=NE) {
if (r1=='P' && r2=='Z') error("P%k 0",b);
if (r2=='P' && r1=='Z') error("P%k 0",b);
}
// make sure functions are properly converted to pointers to
// functions and make sure overloaded functions are rejected
if (r1 == FCT) {
e1 = ptof(0,e1,tbl);
t1 = e1->tp;
r1 = t1->num_ptr(b);
}
if (r2 == FCT){
e2 = ptof(0,e2,tbl);
t2 = e2->tp;
r2 = t2->num_ptr(b);
}
npcheck(b);
if (r1=='P') { // need cast for pointers to virtual and second bases
Pptr p1 = t1->is_ptr();
Pptr p2 = t2->is_ptr();
Pname cn = p1?p1->typ->is_cl_obj():0;
Pname cn2 = p2?p2->typ->is_cl_obj():0;
if (cn && cn2) {
Pclass cl = Pclass(cn->tp);
Pclass cl2 = Pclass(cn2->tp);
if (cl->has_base(cl2)) {
e1 = cast_cptr(cl2,e1,tbl,base==CAST?1:0);
e1 = new cast(p2,e1);
}
else if (cl2->has_base(cl)) {
e2 = cast_cptr(cl,e2,tbl,base==CAST?1:0);
e2 = new cast(p1,e2);
}
}
}
if (r1=='P' && t1->memptr()
||
t1->base==FCT && Pfct(t1)->memof
||
r2=='P' && t2->memptr()
||
t2->base==FCT && Pfct(t2)->memof
) {
if (r1=='Z') {
e1 = zero;
if(e2->base == ILIST) e2 = e2->e1->e2;
else e2 = make_dot(e2,tbl);
}
else if (r2=='Z') {
e2 = zero;
if(e1->base == ILIST) e1 = e1->e1->e2;
else e1 = make_dot(e1,tbl);
}
else if (
r2=='P' && !t2->memptr()
||
r1=='P' && !t1->memptr()
) {
;//error('s',"%t %k %t",t1,base,t2);
}
else {
// ERROR: no check for sideeffects
Pexpr i1;
i1 = e1;
while ( i1->base == G_CAST || i1->base == CAST )
i1 = i1->e1;
if ( i1->base == ILIST ) {
e1 = i1;
i1 = make_dot(i1,tbl,"i");
}
else if (i1->base == ZERO) {
i1 = zero;
e1 = i1;
}
else {
i1 = make_dot(i1,tbl,"i");
}
Pexpr i2;
i2 = e2;
while ( i2->base == G_CAST || i2->base == CAST)
i2 = i2->e1;
if ( i2->base == ILIST ) {
e2 = i2;
i2 = make_dot(i2,tbl,"i");
}
else if (i2->base == ZERO) {
i2 = zero;
e2 = i2;
}
else {
i2 = make_dot(i2,tbl,"i");
}
Pexpr f1;
if(e1->base == ILIST) {
f1 = e1->e2;
}
else if (e1->base == ZERO) {
f1 = zero;
}
else {
f1 = make_dot(e1,tbl,"f");
}
Pexpr f2;
if (e2->base == ILIST) {
f2 = e2->e2;
}
else if (e2->base == ZERO) {
f2 = zero;
}
else {
f2 = make_dot(e2,tbl,"f");
f2->tp = f1->tp;
}
if (b != EQ && b != NE) {
f1 = new cast(Pvoid_type, f1);
f2 = new cast(Pvoid_type, f2);
}
Pexpr ei = new expr(base,i1,i2);
Pexpr fi = new expr(base,f1,f2);
base = b==NE ? OROR : ANDAND;
e1 = ei;
e2 = fi;
}
}
else if (b != EQ && b != NE) {
bit doit = 0;
if (r1 == 'P') {
Ptype tt1 = t1;
Ptype tt2;
while (tt2 = tt1->is_ptr_or_ref())
tt1 = Pptr(tt2)->typ;
if (tt1->base == FCT)
doit = 1;
}
if (!doit && r2 == 'P') {
Ptype tt1 = t2;
Ptype tt2;
while (tt2 = tt1->is_ptr_or_ref())
tt1 = Pptr(tt2)->typ;
if (tt1->base == FCT)
doit = 1;
}
if (doit) {
e1 = new cast(Pvoid_type, e1);
e2 = new cast(Pvoid_type, e2);
}
}
t = int_type;
break;
case ANDAND:
case OROR:
e1 = check_cond(e1,b,tbl);
e2 = check_cond(e2,b,tbl);
if (Ntmp && b != QUEST ) {
Ntmp_dtor = new expr(ELIST,this,Ntmp_dtor);
// error('d',"(e %d) temp ofC%n with dtor needed in%kE",this,Ntmp,b);
}
t = int_type;
break;
case QUEST:
{
Pname c1, c2;
cond = check_cond(cond,b,tbl);
// still doesn't do complete checking for possible conversions
bit MPTR = 0; // local hack
suppress_error++;
r1 = t1->num_ptr(b);
r2 = t2->num_ptr(b);
suppress_error--;
if (
(r1=='P' && t1->memptr() || r1==FCT && Pfct(t1)->memof && Pfct(t1)->f_static==0)
&&
(r2=='P' && t2->memptr() || r2==FCT && Pfct(t2)->memof && Pfct(t2)->f_static==0)
) {
++MPTR; // prevent later sorry
if(r1==FCT) {
e1 = new expr(G_ADDROF,0,e1);
e1->typ(tbl);
t1 = e1->tp;
r1 = t1->num_ptr(b);
}
if(r2==FCT) {
e2 = new expr(G_ADDROF,0,e2);
e2->typ(tbl);
t2 = e2->tp;
r2 = t2->num_ptr(b);
}
// watch for casts
Pexpr tt = e1;
while ( tt->base == CAST || tt->base == G_CAST )
tt = tt->e1;
if ( tt->base == ILIST ) e1 = tt;
tt = e2;
while ( tt->base == CAST || tt->base == G_CAST )
tt = tt->e1;
if ( tt->base == ILIST ) e2 = tt;
// cannot have sides return (expr?{}:{})
// reuse same temp for both sides ?:
if (e1->base == ILIST || e2->base == ILIST) {
Pname temp = make_tmp( 'A', mptr_type, tbl );
if (e1->base == ILIST) {
e1 = mptr_assign( temp, e1 );
e1 = new expr( G_CM, e1, temp );
e1->tp = temp->tp;
}
if (e2->base == ILIST) {
e2 = mptr_assign( temp, e2 );
e2 = new expr( G_CM, e2, temp );
e2->tp = temp->tp;
}
}
}
bit redo1 = 0;
bit redo2 = 0;
c1 = t1->is_cl_obj();
Pname eo1 = eobj;
c2 = t2->is_cl_obj();
Pname eo2 = eobj;
if (t1 == t2
||
c1 && c2 && c1->tp==c2->tp
||
eo1 && eo2 && eo1->tp==eo2->tp
)
t = t1;
else {
if (c1 && c2) {
Ptype tt;
Pclass cl1 = Pclass(c1->tp);
Pclass cl2 = Pclass(c2->tp);
if (same_class(cl1,cl2) || cl2->has_base(cl1)) {
t = t1;
redo2=1;
goto caca;
}
else if (cl1->has_base(cl2)) {
t = t2;
redo1=1;
goto caca;
}
else if (tt = common_base(cl1,cl2)) {
redo1 = redo2 = 1;
t = tt;
goto caca;
}
}
r1 = t1->num_ptr(b);
r2 = t2->num_ptr(b);
if (r1=='P' && r2=='P') {
Pptr p1 = t1->is_ptr();
Pptr p2 = t2->is_ptr();
Ptype tt;
if ((c1 = p1->typ->is_cl_obj())
&& (c2 = p2->typ->is_cl_obj())) {
Pclass cl1 = Pclass(c1->tp);
Pclass cl2 = Pclass(c2->tp);
if (same_class(cl1,cl2) || cl2->has_base(cl1)) {
t = t1;
goto caca;
}
else if (cl1->has_base(cl2)) {
t = t2;
goto caca;
}
else if (tt = common_base(cl1,cl2)) {
t = tt->addrof();
goto caca;
}
}
}
if (r1==FCT && r2==FCT) {
if (t1->check(t2,ASSIGN))
error("badTs in ?:E: %t and %t",t1,t2);
t = t1;
}
else
nppromote(b);
caca:
Pptr pt = t->is_ptr();
bit t_ptr = pt && pt->base == PTR;
Pname cn = !t_ptr ? 0 : pt->typ->is_cl_obj();
if (t!=t1 && t->check(t1,0)) {
PERM(t);
if (redo1) {
e1 = e1->address();
e1 = new cast(t->addrof(),e1);
e1 = e1->docast(tbl);
e1 = new expr(DEREF,e1,0);
e1->tp = t;
}
else {
e1 = new cast(t,e1);
if (cn) e1->e1=cast_cptr(Pclass(cn->tp),e1->e1,tbl,e1->base==CAST?1:0);
}
}
if (t!=t2 && t->check(t2,0)) {
PERM(t);
if (redo2) {
e2 = e2->address();
e2 = new cast(t->addrof(),e2);
e2 = e2->docast(tbl);
e2 = new expr(DEREF,e2,0);
e2->tp = t;
}
else {
e2 = new cast(t,e2);
if (cn) e2->e1=cast_cptr(Pclass(cn->tp),e2->e1,tbl,e2->base==CAST?1:0);
}
}
if (t_ptr && pt->memof && MPTR == 0)
error('s',"conditionalE with%t",t);
}
}
break;
case ASPLUS:
r1 = t1->num_ptr(ASPLUS);
r2 = t2->num_ptr(ASPLUS);
nppromote(ASPLUS);
goto ass;
case ASMINUS:
r1 = t1->num_ptr(ASMINUS);
r2 = t2->num_ptr(ASMINUS);
if (r2=='P' && r1!='P' && r1!='A') error("P -= nonP");
nppromote(ASMINUS);
goto ass;
case ASMUL:
case ASDIV:
r1 = t1->numeric(b);
r2 = t2->numeric(b);
nppromote(b);
goto ass;
case ASMOD:
r1 = t1->integral(ASMOD);
r2 = t2->integral(ASMOD);
nppromote(ASMOD);
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:
if (r1=='P' && t1->check(Pvoid_type,IGNORE_CONST)==0 &&
ptr_is_template_formal(Pptr(t1))==0)
error("%k of void*",b);
tp = t;
as_type = t; /* the type of the rhs */
t2 = t;
case ASSIGN:
//error('d'," e1 %d %k e1 %d %k",e1,e1->base,e2,e2->base);
switch (e1->base) {
case G_CM:
case CM: // (a,b)=c => *(a,&b)=c
{
e1->e2 = new expr(G_ADDROF,0,e1->e2);
e1->tp = 0;
e1 = new expr(DEREF,e1,0);
return typ(tbl);
}
case QUEST: // (a?b:c)=d => *(a?&b:&c)=c
{
e1->e1 = new expr(G_ADDROF,0,e1->e1);
e1->e2 = new expr(G_ADDROF,0,e1->e2);
e1->tp = 0;
e1 = new expr(DEREF,e1,0);
return typ(tbl);
}
case ASSIGN: // (a*=b)=c => a*=b,a=c
case ASPLUS:
case ASMINUS:
case ASMUL:
case ASDIV:
case ASMOD:
case ASAND:
case ASOR:
case ASER:
case ASLS:
case ASRS:
{
base = G_CM;
nin++;
if (e1->e1->not_simple()) error('s',"lvalue %k too complicated",b);
nin--;
Pexpr aa = new expr(e1->base,e1->e1,e1->e2);
Pexpr bb = new expr(b,e1->e1,e2);
e1 = aa;
e2 = bb;
return typ(tbl);
}
case INCR:
case DECR: // ++a=b => ++a,a=b
{
if(!e1->e2) break ;
base = G_CM;
nin++;
if (e1->e2->not_simple()) error('s',"lvalue %k too complicated",b);
nin--;
Pexpr aa = new expr(e1->base,0,e1->e2);
Pexpr bb = new expr(b,e1->e2,e2);
e1 = aa;
e2 = bb;
return typ(tbl);
}
case REF:
{
Pexpr r = e1;
// hack to prevent
// f().i = j
// transformed into
// ((t=f()),&t)->i = j
if (r->e1->base==G_CM
&& r->e1->e2->base==G_ADDROF
&& r->e1->e2->e2->base==NAME) {
char* s = r->e1->e2->e2->string;
if (s[0]=='_' && s[1]=='_')
error("left hand side not lvalue");
}
}
}
if (e1->lval(b) == 0) {
tp = any_type;
return this;
}
t1 = t1->skiptypedefs();
switch (t1->base) {
case INT:
case CHAR:
case SHORT:
{ Ptype t = e2->tp->skiptypedefs();
switch (t->base) {
case LONG:
case FLOAT:
case DOUBLE:
case LDOUBLE:
error('w',"%t assigned to %t",e2->tp,t1);
}
}
// no break
case LONG:
if (b==ASSIGN
&& Pbase(t1)->b_unsigned
&& e2->base==UMINUS
&& e2->e2->base==ICON)
error('w',"negative assigned to unsigned");
break;
case PTR:
if (b == ASSIGN) {
e2 = ptr_init(Pptr(t1),e2,tbl);
t2 = e2->tp;
//error('d',"pchecked %d",Pchecked);
if (Pchecked) {
tp = e1->tp;
return this;
}
}
break;
case COBJ:
{ Pname c1 = t1->is_cl_obj();
// test of c1->tp necessary for ``fake classes''
// _Sdd generated for vector assignemnts
if (c1
&& c1->tp
/* && Pclass(c1->tp)->memtbl->look("__as",0)==0*/) {
Pname c2 = t2->is_cl_obj();
// error('d', "expr::typ: c1: %n c2: %n", c1, c2 );
if (c1 != c2) {
/*
consider:
struct A { A(B&); };
struct B : A {};
A aa;
B bb;
aa = bb; // aa.operator=(A(bb));
// optimize to aa.A(bb) when possible
// avoid temporary where aa = *(A*)&bb is legal
*/
// error('d',"expr::typ c1 %n %d c2 %n %d",c1,c1?c1->tp:0,c2,c2?c2->tp:0);
if (c2
&& c2->tp
&& can_coerce(t1,t2)==0
&& (vcllist->clear(),vcllist=0,1<is_unique_base(Pclass(c2->tp),c1->string,0))
&& Pclass(c1->tp)->c_xref&(C_VBASE|C_VPTR|C_ASS)) {
// error('d',"aaa");
if (make_assignment(c1)) return oper_overload(tbl);
}
// optimize
else {
e2 = new expr(ELIST,e2,0);
e2 = new texpr(VALUE,t1,e2);
if (Pclass(c1->tp)->has_dtor()==0 &&
Pclass(c1->tp)->has_oper(ASSIGN)==0) {
// optimize
// error('d',"bbb");
e2->e2 = e1;
e2 = e2->typ(tbl);
if (e2->base==DEREF && e2->e1->base==G_CALL ||
e2->base==ASSIGN && e2->e1==e1) {
// error('d',"ccc");
*this = *e2;
}
tp = t1;
return this;
}
return typ(tbl);
}
}
// test of c1->tp necessary for ``fake classes''
// _Sdd generated for vector assignemnts
else if (c1->tp && Pclass(c1->tp)->c_xref&(C_VBASE|C_VPTR|C_ASS)) {
if (make_assignment(c1)) return oper_overload(tbl);
}
}
(void) t1->tsizeof();
break;
}
}
//error('d',"check(%t,%t) -> %d",e1->tp,t2,try_to_coerce(t1,e2,"assignment",tbl));
{
Pexpr x = try_to_coerce(t1,e2,"assignment",tbl);
if (t1->base==COBJ && t1->classtype() && t1->classtype()->has_const_mem())
error("cannot assign to an object of class %t with const member(s)",t1->classtype());
if (x)
e2 = x;
else if (t2->is_or_pts_to(OVERLOAD))
error("bad assignmentT:%t =&overloaded function",e1->tp);
else if (e1->tp->check(t2,ASSIGN)) {
error('e',"bad assignmentT:%t =%t",e1->tp,t2);
if (no_const)
error('c'," (no usable const conversion)\n");
else error('c',"\n");
}
else if ((t1 = t1->is_ptr()) && t1->memptr()) {
if (t2 == zero_type) {
Pexpr ee = new expr(ELIST,zero,zero);
e2 = new expr(ILIST,ee,zero);
}
else if (t2->base==PTR && t2->memptr()) {
// do nothing: structure assignment
}
else {
Pexpr x = ptr_init(Pptr(t1),e2,tbl);
if (x != e2) e2 = x;
}
}
}
t = e1->tp; // the type of the lhs
break;
case CM:
case G_CM:
// cannot have sides return ({},{})
if (t1->base == FCT) {
e1 = new expr(G_ADDROF,0,e1);
e1->typ(tbl);
t1 = e1->tp;
}
if (t2->base == FCT){
e2 = new expr(G_ADDROF,0,e2);
e2->typ(tbl);
t2 = e2->tp;
}
if (e1->base == ILIST) {
Pname temp1 = make_tmp( 'A', mptr_type, tbl );
e1 = mptr_assign( temp1, e1 );
e1 = new expr( G_CM, e1, temp1 );
e1->tp = temp1->tp;
}
if (e2->base == ILIST) {
Pname temp2 = make_tmp( 'A', mptr_type, tbl );
e2 = mptr_assign( temp2, e2 );
e2 = new expr( G_CM, e2, temp2 );
e2->tp = temp2->tp;
//t2 = e2->tp;
}
t = t2;
break;
default:
error('i',"unknown operator%k",b);
}
tp = t;
return this;
}
bit
expr::is_const_obj()
{
Pexpr ee = this;
if(ee == 0) return 0;
while (ee && (ee->base==DOT || ee->base==REF)) {
Pexpr m = ee->mem;
if ( ee->base==REF && m->tp && m->tp->is_ptr())
break;
ee = ee->e1;
}
if (ee) {
Pptr p;
Ptype ttt = ee->tp;
switch (base) {
case REF:
{
p = ttt?ttt->is_ptr():0;
if (p && p->typ->tconst())
return 1;
break;
}
case DOT:
{
p = ttt?ttt->is_ptr():0;
int tc = ttt ? ttt->tconst() : 0;
if (!p && ttt && tc && (!strict_opt || tc!=2))
return 1;
break;
}
}
}
return 0;
}