/*               
 * 68K/386 32-bit C compiler.
 *
 * copyright (c) 1997, David Lindauer
 * 
 * This compiler is intended for educational use.  It may not be used
 * for profit without the express written consent of the author.
 *
 * It may be freely redistributed, as long as this notice remains intact
 * and either the original sources or derived sources 
 * are distributed along with any executables derived from the originals.
 *
 * The author is not responsible for any damages that may arise from use
 * of this software, either idirect or consequential.
 *
 * V2.05 June 2002
 * David Lindauer, camille@bluegrass.net
 *
 * Credits to Mathew Brandt for original K&R C compiler
 *
 */
/*
 * Evaluate expressions very recursive descent.  MAke sure your STACK
 * is large enough to parse the expressions you want to parse.  a 4K stack
 * will handle all but the very extreme cases
 */
#include        <stdio.h>
#include				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "errors.h"
#include				"lists.h"

extern LIST *instantiated_inlines ;
extern int stdretblocksize,stdintsize;
extern int block_nesting;
extern int global_flag;
extern enum e_sym lastst;
extern char lastid[],laststr[];
extern TABLE *gsyms,lsyms;
extern long ival;
extern long double rval;
extern int skm_declcomma[],skm_declclosepa[];
extern TYP      *head;          /* shared with decl */
extern TABLE    tagtable;
extern char declid[100];
extern int goodcode;
extern int prm_cplusplus;
extern int regdsize,regasize,regfsize,stackadd,stackmod;
extern int stdaddrsize;
extern long nextlabel;
extern int prm_ansi;
extern SYM *declclass;
extern int prm_cmangle;
extern SYM *currentfunc;
extern int stdmemberptrsize;
extern int laststrlen;
extern SYM *typequal;
extern char *cpp_funcname_tab[];

/* Default types */
extern TYP stdint,stdlongdouble, stduns,stdstring;
TYP             stdfloat = { bt_float, 0, UF_DEFINED | UF_USED,-1, -1, 6};
TYP             stddouble = { bt_double, 0, 0,-1, -1, 8};
TYP             stdvoid = { bt_matchall, 0, 0 ,-1, -1, 4};
TYP             stdmatch = { bt_matchall, 0, UF_DEFINED | UF_USED,-1, -1, 4, 0, &stdvoid};
TYP             stdlong = {bt_long, 0, 0,-1, -1, 4};
TYP             stdunsigned = {bt_unsigned, 0, 0,-1, -1, 4};
TYP             stdchar = {bt_char, 0, 0,-1, -1, 1};
TYP             stdfunc = {bt_func, 1, UF_DEFINED | UF_USED,-1, -1, 0, 0, &stdint};

int skm_closepa[] = { closepa, comma, semicolon, end, 0 };
int skm_closebr[] = { closebr, comma, openbr, semicolon, end, 0 };
SYM undef;
SYM *thissp;

static int dumpos;
static ENODE *thisx;
static SYM *lastsym;
static char regname[] = "processor reg" ;
static char *nm = 0;
static TYP *asntyp = 0, *andtyp = 0;
static int global_deref=0;
ENODE *thisenode;

void exprini(void)
{
	ENODE *newnode;
	SYM *sp;
	asntyp = 0;
	dumpos = 0;
	undef.value.i = 0;
	undef.name = "UNDEFINED";
	global_deref = 0;
#ifdef CPLUSPLUS
	thissp = sp = xalloc(sizeof(SYM));
	sp->name = "**THIS**";
	sp->value.classdata.defalt = 0;
   sp->storage_class = sc_auto;
   sp->tp = 0; /* should never be used */
	sp->extflag = FALSE;
	sp->absflag = FALSE;
	sp->intflag = FALSE;
	sp->pascaldefn = FALSE;
	sp->isstdcall = FALSE;
	sp->init = 0;
	sp->indecltable = 0;
	sp->funcparm = 1;
	sp->inreg = 0;
	sp->staticlabel = FALSE;
	sp->value.i = stdretblocksize-stdintsize; /* back end is going to up this again */
	thisenode = makenode(en_autocon,sp,0);
#endif
}
TYP *basictype(TYP *t)
{
	while (t->type == bt_cond || t->type == bt_member)
		t = t->btp ;
	return t ;
}
ENODE    *makenode(enum e_node nt, char *v1, char *v2)
/*
 *      build an expression node with a node type of nt and values
 *      v1 and v2.
 */
{       ENODE    *ep;
        ep = xalloc(sizeof(ENODE));
        ep->nodetype = (char)nt;
				ep->cflags = 0;
        ep->v.p[0] = v1;
        ep->v.p[1] = v2;
        return ep;
}

TYP *deref(ENODE **node, TYP *tp)
/*
 *      build the proper dereference operation for a node using the
 *      type pointer tp.
 */
{
				ENODE *onode = *node;
				if ((*node)->nodetype == en_placeholder)
					return tp;
				switch( tp->type ) {
								case bt_double:
                        *node = makenode(en_doubleref,*node,0);
                        break;
								case bt_longdouble:
                        *node = makenode(en_longdoubleref,*node,0);
                        break;
								case bt_float:
                        *node = makenode(en_floatref,*node,0);
                        break;
								case bt_unsignedchar:
                        *node = makenode(en_ub_ref,*node,0);
                        break;
								case bt_unsignedshort:
                        *node = makenode(en_uw_ref,*node,0);
                        break;
                case bt_char:
                        *node = makenode(en_b_ref,*node,0);
                        break;
                case bt_bool:
                        *node = makenode(en_bool_ref,*node,0);
                        break;
                case bt_short:
                        *node = makenode(en_w_ref,*node,0);
                        break;
                case bt_unsigned:
                case bt_enum:
                        *node = makenode(en_ul_ref,*node,0);
												break;
                case bt_pointer:
								case bt_ref:
								case bt_int:
                case bt_matchall:
								case bt_memberptr:
                        *node = makenode(en_l_ref,*node,0);
                        break;
                case bt_long:
                        *node = makenode(en_ll_ref,*node,0) ;
                        break ;
                case bt_unsignedlong:
                        *node = makenode(en_ull_ref,*node,0) ;
                        break ;
                default:
                        generror(ERR_DEREF,0,0);
                        break;
                }
				(*node)->cflags = onode->cflags;
        return tp;
}
ENODE* make_callblock(ENODE *ep1, ENODE *ep2,TYP *tp, int size)
{
#ifdef CPLUSPLUS
	ENODE *ep3;
	int thiscall = 0;
	if (ep2->nodetype == en_thiscall) {
		ep3 = ep2->v.p[0];
		ep2 = ep2->v.p[1];
		thiscall = 1;
	}
#endif
	if (ep2->nodetype == en_fcallb || ep2->nodetype == en_pfcallb || ep2->nodetype == en_sfcallb) {
		if (!ep1)
			ep1 = (ENODE*) dummyvar(size,tp);
		
		if (ep2->nodetype == en_pfcallb) 
			ep1 = makenode(en_pcallblock,ep1,ep2);
		else
			if (ep2->nodetype == en_sfcallb) 
				ep1 = makenode(en_scallblock,ep1,ep2);
			else
				ep1 = makenode(en_callblock,ep1,ep2);
	} 
#ifdef CPLUSPLUS
	else
		if (thiscall || !ep1)
			ep1 = ep2;
	if (thiscall)
		ep1 = makenode(en_thiscall,ep3,ep1);
#endif
	return ep1;
}



ENODE *dummyvar(int size, TYP *type)
{
	char nm[20];
	ENODE *newnode;
	SYM *sp = xalloc(sizeof(SYM));
	sprintf(nm,"**DUMMY%d",dumpos++);
	sp->name = litlate(nm);
#ifdef CPLUSPLUS
	sp->value.classdata.defalt = 0;
#endif
  sp->storage_class = sc_auto;
  sp->tp = type;
	type->uflags |= UF_USED;
	sp->extflag = FALSE;
	sp->absflag = FALSE;
	sp->intflag = FALSE;
	sp->pascaldefn = FALSE;
	sp->isstdcall = FALSE;
	sp->init = 0;
	sp->indecltable = 0;
	sp->funcparm = 0;
	sp->inreg = 0;
	sp->staticlabel = FALSE;
	sp->value.i = block_nesting;
	insert(sp,&lsyms);
	newnode = makenode(en_autocon,sp,0);
	return newnode;
}
int isintconst(int type)
{
	switch (type) {
		case en_icon:
		case en_lcon:
		case en_lucon:
		case en_iucon:
      case en_ccon:
      case en_llcon:
      case en_llucon:
			return 1;
	}
	return 0;
}
int isfloatconst(int type)
{
	switch (type) {
		case en_rcon:
		case en_lcon:
		case en_lrcon:
			return 1;
	}
	return 0;
}
int matchreflvalue(ENODE **node,TYP *tp1, TYP *tp2)
{
	if (node && !*node || !exactype(tp1->btp, tp2)) {
		generror(ERR_REFLVALUE,0,0);
		return 0;
	}
	if (node)
		*node = (*node)->v.p[0];
	return 1;
}
TYP     *nameref(ENODE **node, TYP *tin)
/*
 * get an identifier.  If it is followed by parenthesis gather the
 * function parms.  If it is an undefined function declare it as external
 * for now.
 *
 * For C++ also gather in the class type qualifier
 *
 */
{       SYM             *sp, *cosym=0,*sp1;
        TYP             *tp,*tp1;
				ENODE *pnode=0,*qnode = 0,*xnode = 0;
				int override = FALSE , member = FALSE;
				char buf[40],cobuf[40];
				int notbase = FALSE;
				cobuf[0] = 0;
				strcpy(buf,lastid);
				getsym();
#ifdef CPLUSPLUS
				if (typequal) {
					override = TRUE;
					cosym = typequal;
					if (declclass) {
						*node = xnode = makenode(en_l_ref,thisenode,0);
					}
					else
						*node = xnode = 0;
					typequal = 0;
				}
				else if (lastst == classsel) {
					override = TRUE;
					cosym = gsearch(lastid);
					if (declclass) {
						*node = xnode = makenode(en_l_ref,thisenode,0);
					}
					else {
						*node = xnode = makenode(en_icon,0,0); /* better be a member ptr ref if we get here */
						if (!(cosym->value.classdata.cppflags & PF_STATIC))
							member = TRUE ;
					}
					if (!cosym || (cosym->tp->type != bt_struct && cosym->tp->type != bt_class))
						generror(ERR_TYPEQUALEXP,0,0);
						
					getsym();
					if (lastst != id) {
						*node = makenode(en_icon,(char *) -4,0);
						return &stdint;
					}
					strcpy(buf,lastid);
					getsym();
				} else if (tin && isstructured(tin)) {
					override = TRUE;
					cosym = tin->sp ;
					xnode = *node ;
				} else if (declclass) {
					cosym = declclass;
					*node = xnode = makenode(en_l_ref,thisenode,0);
				}

				if (cosym)
					strcpy(cobuf,cosym->name);
#endif
 				{
					sp = 0;
					nm = litlate(buf);
#ifdef CPLUSPLUS
					if (prm_cplusplus && andtyp && andtyp->type == bt_memberptr
							&& (andtyp->btp->type == bt_func || andtyp->btp->type == bt_ifunc)) {
						tp1 =	andtyp->btp;
						pnode = makenode(en_icon,0,0);
					}
					if (prm_cplusplus && andtyp && andtyp->type == bt_pointer
							&& (andtyp->btp->type == bt_func || andtyp->btp->type == bt_ifunc)) {
						tp1 =	andtyp->btp;
						pnode = makenode(en_icon,0,0);
					}
					if (cosym) {
						if (!override)
							sp = search(buf,&lsyms);
						if (sp) {
							cosym = 0; 	
							xnode = 0;
						} else {
							sp = basesearch(buf,&cosym->tp->lst.head,TRUE);
                     if (sp && (sp->storage_class != sc_defunc) && currentfunc && (currentfunc->value.classdata.cppflags & PF_MEMBER)
												&& (currentfunc->value.classdata.cppflags & PF_STATIC))
								generror(ERR_STATICNOACCESS,0,0);
							if (!sp && !override)
								sp = gsearch(buf);
						}
					}
					else
#endif
						sp = gsearch(buf);
				}

        if( sp == 0 ) {
/* No such identifier */
                if (lastst == openpa) {
/* External function, put it in the symbol table */
                        ++global_flag;
												sp = xalloc(sizeof(SYM));
                				sp->name = litlate(buf);
												sp->tp = maketype(bt_func,0);
												*(sp->tp) = stdfunc;
												sp->tp->sp = sp;
                        sp->storage_class = sc_externalfunc;
												sp->extflag = TRUE;
												setalias(sp);
												*node = makenode(en_nacon,sp,0);
#ifdef CPLUSPLUS
												if (cosym)
                                       insert(sp,&cosym->tp->lst.head);
												else
#endif
      	                  insert(sp,gsyms);
                        --global_flag;
                        tp = sp->tp;
												goodcode |= GF_ASSIGN;
                }
                else    {
/* External non-function.  These also get put in the symbol table so that
 * we don't keep spitting errors out but also put an error out
 */
												sp = xalloc(sizeof(SYM));
                				sp->name = litlate(buf);
                        sp->tp = tp = &stdmatch;
												sp->storage_class = sc_external;
#ifdef CPLUSPLUS
												if (!cosym)
#endif
													insert(sp,&lsyms);
												*node = makenode(en_nacon,&undef,0);
												if (prm_cplusplus && override)
													genclass2error(ERR_UNDEFINED,cobuf,buf);	
												else
													gensymerror(ERR_UNDEFINED,buf);
                        tp = deref(node,tp);
												/* now skip sub-pointers if it was an unknown struct ref */
												if (tin) {
												 	while (lastst == pointsto || lastst == dot) {
												 		getsym();
												 		getsym();
												 	}
                        }
								}
        }
        else    {
/* If we get here the symbol was already in the table
 */
foundsp:
								sp->tp->uflags |= UF_USED;
                if( (tp = sp->tp) == 0 ) {
/* This lack of type info should never happen */
                        tp = &stdmatch;
												*node = makenode(en_nacon,&undef,0);
												gensymerror(ERR_UNDEFINED,buf);
                        tp = deref(node,tp);
                        return tp;       /* guard against untyped entries */
                }
  							switch( sp->storage_class ) {
									case sc_defunc:
										if (*node && !(sp->value.classdata.cppflags & PF_STATIC))
				 							*node = makenode(en_thiscall,*node,0) ;
										else
											*node = makenode(en_placeholder,0,0);
										break;
    							case sc_static:
    							case sc_global:
    							case sc_external:
    							case sc_externalfunc:
	  							case sc_abs:
                           if ((sp->tp->cflags & DF_CONST) && isscalar(sp->tp) &&
                                 sp->tp->btp != bt_float && sp->tp->btp != bt_double && sp->tp->btp != bt_longdouble) {
                              if (sp->init)
                                 *node = makenode(en_icon,(char *)sp->init->val.i,0) ;
                              else
                                 *node = makenode(en_icon,0,0) ;
                              return sp->tp ;
                           }
                           else {
                              sp->extflag = TRUE;
#ifdef CPLUSPLUS
										if (sp->value.classdata.gdeclare)
										  sp->value.classdata.gdeclare->extflag = TRUE ;
#endif
										if (sp->absflag)
      								*node = makenode(en_absacon,sp,0);
										else
			 								if (sp->tp->type == bt_func || sp->tp->type == bt_ifunc) {
       									*node = makenode(en_napccon,sp,0);
											}
			  							else
				  							if (sp->staticlabel)
													*node = makenode(en_nalabcon,(char *)sp->value.i,0);
												else
           								*node = makenode(en_nacon,sp,0);
                           }
      							break;
    							case sc_const:
									/* constants and enums */
      							*node = makenode(en_icon,(char *)sp->value.i,0);
		  							return &stdint;
									/* structure/class elements */
		 							case sc_member:
										if (sp->value.classdata.cppflags & PF_STATIC) {
											*node = makenode(en_nacon,sp,0) ;
											sp->extflag = sp->value.classdata.gdeclare->extflag = TRUE ;
										} else {
	        						qnode = makenode(en_icon,(char *)sp->value.i,0);
  	      						*node = makenode(en_addstruc,qnode,*node);
										}
		 								break;
     							default:        /* auto and any errors */
                           if ((sp->tp->cflags & DF_CONST) && sp->init && isscalar(sp->tp) &&
                                 sp->tp->btp != bt_float && sp->tp->btp != bt_double && sp->tp->btp != bt_longdouble) {
                              *node = makenode(en_icon,(char *)sp->init->val.i,0) ;
                              return sp->tp ;
                           }
                           else {
                              if( sp->storage_class != sc_auto && sp->storage_class != sc_autoreg) {
                                 gensymerror(ERR_ILLCLASS2,sp->name);
                                 tp = 0;
			 							}
			 							else {
											/* auto variables */
			 								if (sp->storage_class == sc_auto)
         								*node = makenode(en_autocon,sp,0);
			  							else if (sp->storage_class == sc_autoreg)
         								*node = makenode(en_autoreg,sp,0);
										}
                          }
        						break;
  							}
/* dereference if it isn't an array or structure address */

								if (tp) {
									(*node)->cflags = tp->cflags;
								/* deref if not an array or if is function parm */
  	              if(tp && (tp->val_flag == 0 || (sp->funcparm && tp->type == bt_pointer)) && (*node)->nodetype != en_icon)
											if (tp->type != bt_defunc)
  	                     tp = deref(node,tp);
/* and dereference again if it is a refernece variable */
	  							if (tp->type == bt_ref) {
                                    //if (tp->btp->type == bt_pointer)
                                    deref(node,tp->btp);
												tp->btp->cflags = tp->cflags;
												tp = tp->btp;
		  						}
												
								}
								if (member) {
									TYP *tp1 = maketype(bt_member,0) ;
									tp1->btp = tp ;
									tp = tp1 ;
								}
							}
				lastsym = sp;
        return tp;
}

void promote_type(TYP *typ, ENODE **node)
/*
 * Type promotion for casts and function args 
 */
{
		switch (typ->type) {
      case bt_bool:
          *node = makenode(en_cbool,*node,0);
							break;
			case bt_char:
					*node = makenode(en_cb,*node,0);
							break;
			case bt_unsignedchar:
					*node = makenode(en_cub,*node,0);
					break;
			case bt_enum:
			case bt_short:
	  			*node = makenode(en_cw,*node,0);
		  		break;
			case bt_unsignedshort:
  				*node = makenode(en_cuw,*node,0);
					break;
      case bt_int:
    			*node = makenode(en_cl,*node,0);
					break;
			case bt_unsigned:
					*node = makenode(en_cul,*node,0);
		  		break;
			case bt_float:
  				*node = makenode(en_cf,*node,0);
					break;
			case bt_double:
					*node = makenode(en_cd,*node,0);
					break;
			case bt_longdouble:
					*node = makenode(en_cld,*node,0);
					break;
         case bt_long:
               *node = makenode(en_cll,*node,0);
               break ;
         case bt_unsignedlong:
               *node = makenode(en_cull,*node,0);
               break ;
			default:
					*node = makenode(en_cp,*node,0);
					break;
		}
	(*node)->cflags = typ->cflags;
}
TYP *gatherparms( ENODE **node,int isvoid)
/*
 * create a type tree and primary parameter list for a function
 *
 * At this point the parameter list is backwards from what codegen
 * needs!
 */
{
	ENODE *ep1 = 0,*ep2=0,**ep3 = &ep1;
	TABLE tbl;
	int odf = global_deref;
	SYM **t = &tbl.head,*newt;
	TYP *tp;
	int ogc = goodcode;
	tbl.tail = tbl.head = 0;
	goodcode |= DF_FUNCPARMS;
	global_deref = 0;
	if (lastst == closepa || isvoid) {
#ifdef CPLUSPLUS
		if (prm_cplusplus)
			tbl.head=tbl.tail=(SYM *)-1;
		else
#endif
			tbl.head=tbl.tail = 0;
	}
	else if (lastst == kw_void)
		tbl.head = tbl.tail = (SYM *)-1;
	else
	  while (lastst != closepa) {
			tp = exprnc(&ep2);
			if (!tp) {
				generror(ERR_EXPREXPECT,0,0);
				break;
			}
			ep2->cflags = tp->cflags;
		  if (tp->bits != -1) {
				ep2 = makenode(en_bits,ep2,0);
				ep2->bits = tp->bits;
				ep2->startbit = tp->startbit;
		  }
			newt = xalloc(sizeof(SYM));
			newt->tp = tp;
			newt->next = 0;
			newt->name = 0;
			*t = newt;
			t = &newt->next;
			tbl.tail = newt;
			*ep3 = makenode(en_void,ep2,0);
			ep3 = &(*ep3)->v.p[1];
			if (lastst == comma)
				getsym();
		} 	
	if (!isvoid)
		needpunc(closepa,skm_closepa);
	tp = maketype(bt_func,0);
	tp->val_flag = 1;
	tp->btp = &stdint;
	tp->lst = tbl;
	tp->bits = -1;
	tp->startbit = -1;
	tp->uflags = UF_DEFINED | UF_USED;
	goodcode = ogc;
	*node = ep1;
	global_deref = odf;
	return tp;
}
int checkparmconst(TYP *tp, TYP *tpi)
/*
 * Check the CONST flags for parameters
 */
{
	if (tpi->type != bt_pointer && tpi->type != bt_ref)
		return 0;
	while ((tp->type == bt_pointer || tp->type == bt_ref)&& !tp->val_flag && (!tpi || tpi->type == bt_pointer || tpi->type == bt_ref)) {
		if ((tp->cflags & DF_CONST) && (!tpi || !(tpi->cflags & DF_CONST))) {
			if (prm_cplusplus)
				generror(ERR_MODCONS,0,0);
			else
				generror(ERR_SUSPICIOUS,0,0);
			return 1;
		}
		tp = tp->btp;
		tpi = tpi->btp;
	}
	if ((tp->cflags & DF_CONST) && (!tpi || !(tpi->cflags & DF_CONST))) {
		if (prm_cplusplus)
			generror(ERR_MODCONS,0,0);
		else
			generror(ERR_SUSPICIOUS,0,0);
		return 1;
	}
	return 0;
}
ENODE *copy_enode(ENODE *node)
{
/*
 * routine takes an enode tree and replaces it with a copy of itself.
 * Used because we have to munge the block_nesting field (value.i) of each
 * sp in an inline function to force allocation of the variables
 */
				ENODE *temp;
        if( node == 0 )
                return 0;
				temp = xalloc(sizeof(ENODE));
				memcpy(temp,node,sizeof(ENODE));
				switch (temp->nodetype) {
                case en_autoreg:
                case en_autocon:
                case en_rcon: case en_lrcon: case en_fcon:
                case en_icon:
								case en_lcon:
								case en_iucon:
								case en_lucon:
								case en_ccon:
                case en_nacon:
								case en_absacon:
                case en_napccon:
                case en_llcon:
                case en_llucon:
											break;
								case en_bits:
								case en_floatref:
								case en_doubleref:
								case en_longdoubleref:
                case en_ll_ref: case en_ull_ref:
                case en_b_ref:
                case en_w_ref:
                case en_ul_ref:
                case en_l_ref:
                case en_ub_ref:
                case en_uw_ref:
                case en_bool_ref:
                case en_uminus: case en_asuminus: case en_ascompl:
                case en_compl:  case en_ainc:
                case en_adec:   case en_not:
								case en_cf: case en_cd: case en_cld:
                case en_cb: case en_cub: case en_cbool:
                        case en_cw: case en_cuw: case en_cll: case en_cull:
								case en_cl: case en_cul: case en_cp:
                case en_trapcall:  case en_cl_reg:
												temp->v.p[0] = copy_enode(node->v.p[0]);
												break;
                case en_asadd:  case en_assub:
                case en_add:    case en_sub: case en_addstruc:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_aslsh:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asrsh:  case en_asand:
                case en_assign: case en_refassign:
								case en_asor:  case en_asxor:
								case en_callblock:
								case en_pcallblock: case en_scallblock:
								case en_void:
								case en_pmul:		case en_pdiv:
                case en_mul:    case en_div:
                case en_umul:    case en_udiv: case en_umod:
                case en_lsh:    case en_rsh:
                case en_mod:    case en_and:
                case en_or:     case en_xor:
                case en_lor:    case en_land:
                case en_eq:     case en_ne:
                case en_gt:     case en_ge:
                case en_lt:     case en_le:
								case en_ugt:	case en_uge: case en_ult: case en_ule:
                case en_cond:  case en_intcall:
								case en_moveblock: case en_stackblock: 
                case en_fcall: case en_fcallb:
								case en_pfcall: case en_pfcallb:
								case en_sfcall: case en_sfcallb:
								case en_thiscall:
												temp->v.p[0] = copy_enode(node->v.p[0]);
								case en_repcons:
												temp->v.p[1] = copy_enode(node->v.p[1]);
												break;
        }
	return temp;
}
void parmlist(ENODE **node, TYP *tpi, TYP *tp)
/*
 * take the primary type and node trees, the function argument expectations,
 * and check for type mismatch errors
 *
 * also reverse the primary node tree so the parms will be ready for
 * code generation
 */
{       ENODE    *ep1=0,*ep2=0,*ep3=*node;
				SYM *spi=tpi->lst.head,*sp=0;
				TYP *tp2;
				int matching = FALSE;
				if (tp->type == bt_pointer)
					tp = tp->btp;
				if (tp)
					sp=tp->lst.head;
				if (tp && !sp)
               if (!tp->sp->hasproto)
                  gensymerror(ERR_NOPROTO,tp->sp->name);
				
					if (!prm_cplusplus && sp && (sp == (SYM *) -1 || sp->tp->type != bt_ellipse))
							matching = TRUE;
					while (TRUE) {
							if (!spi || spi == (SYM *)-1){
								if (sp == (SYM *) -1)
									break;
								if (sp && sp->tp->type != bt_ellipse) 
#ifdef CPLUSPLUS
									if (!sp->value.classdata.defalt) 
#endif
										genfuncerror(ERR_CALLLENSHORT,tp->sp->name,0);
#ifdef CPLUSPLUS
									else
										while (sp && sp != (SYM *)-1) {
											ENODE *en;
											if (sp->tp->val_flag && isstructured(sp->tp)) {
												ep1 = makenode(en_stackblock,en = copy_enode(sp->value.classdata.defalt),ep1);
												en->size = sp->tp->size;
											}
											else
	    			    		   	ep1 = makenode(en_void,copy_enode(sp->value.classdata.defalt),ep1);
											sp = sp->next;
										}
#endif
								break;
							}
							else {
							ep2 = ep3->v.p[0];
							ep3 = ep3->v.p[1];
							if (matching) {
								if (!sp || sp == (SYM *)-1) {
                           if (!tp->sp->oldstyle)
                              genfuncerror(ERR_CALLLENLONG,tp->sp->name,0);
									break;
								}
								else {
									checkparmconst(spi->tp,sp->tp);
									if (!checktype(spi->tp,sp->tp,FALSE)) {
								  	if (!(isscalar(sp->tp) && isscalar(spi->tp)))
											if (sp->tp->type == bt_pointer) {
												if (isintconst(ep2->nodetype)) {
													if (ep2->v.i != 0)
														generror(ERR_NONPORT,0,0);
												}
												else if (spi->tp->type != bt_pointer)
													if (spi->tp->type == bt_void)
														generror(ERR_NOVOID,0,0);
													else
														genfuncerror(ERR_CALLMISMATCH,tp->sp->name,sp->name);
						 					}
											else 
													if (spi->tp->type == bt_void)
														generror(ERR_NOVOID,0,0);
													else
														genfuncerror(ERR_CALLMISMATCH,tp->sp->name,sp->name);
									}
								}
							}
							else if (spi->tp->type == bt_void)	
								generror(ERR_NOVOID,0,0);
							}
							if (sp && sp->tp->type == bt_ref) {
								if (!isintconst(ep2->nodetype) && !isfloatconst(ep2->nodetype)) {
									while (castvalue(ep2))
										ep2 = ep2->v.p[0];
									if (lvalue(ep2))
										ep2 = ep2->v.p[0];
								}
								else {
									ENODE *x;
									tp2 = sp->tp->btp;
									x = dummyvar(tp2->size,tp2);
									deref(&x,tp2);
									ep2 = makenode(en_refassign,x,ep2);
									genfuncerror(ERR_TEMPUSED,tp->sp->name,sp->name);
								}
							}
							if (spi && spi != (SYM *) -1 && spi->tp->val_flag && isstructured(spi->tp)) {
								ep1 = makenode(en_stackblock,ep2,ep1);
								ep2->size = spi->tp->size;
							}
							else {
								if (sp && sp != (SYM *)-1 && sp->tp->type != bt_ellipse)
									promote_type(sp->tp,&ep2);
								else if (isintconst(ep2->nodetype))
									promote_type(&stdint,&ep2);
								else if (isfloatconst(ep2->nodetype))
									promote_type(&stdfloat,&ep2);
	        	   	ep1 = makenode(en_void,ep2,ep1);
							}
							
							spi = spi->next;
 							if (sp && sp != (SYM *)-1) {
								sp = sp->next;
 								if (sp && sp->tp->type == bt_ellipse)
									matching = FALSE;
							}
					}
					if (tp) {
						if (!tp->btp)
							tp->btp = &stdint;
						promote_type(tp->btp,&ep1);
					}
					else
						promote_type(tpi->btp,&ep1);
					*node = ep1;
}

int floatrecurse(ENODE *node)
/*
 * Go through a node and see if it will be promoted to type FLOAT
 */
{
	if (!node)
		return 0;
	switch (node->nodetype) {
								case en_rcon:
								case en_lrcon:
								case en_fcon:
								case en_doubleref:
								case en_longdoubleref:
								case en_floatref:
								case en_cld:
								case en_cd:
								case en_cf:
												return 1;
                case en_labcon: case en_trapcall: 
                case en_nacon:  case en_autocon:  case en_autoreg: case en_nalabcon:
                case en_l_ref:  case en_tempref: case en_napccon: case en_absacon:
								case en_cl: case en_regref:
                case en_ul_ref: case en_ll_ref: case en_ull_ref:
                        case en_cul: case en_cll: case en_cull:
								case en_cp:
                case en_icon:
								case en_lcon: case en_iucon: case en_lucon: case en_ccon:
                        case en_llcon: case en_llucon:
								case en_bits:
                case en_ub_ref:
								case en_cub:
                case en_b_ref: case en_bool_ref:
								case en_cb:
                case en_uw_ref:
								case en_cuw:
                case en_cw:
                case en_w_ref:
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                        return 0;
								case en_fcall: case en_pfcall:
								case en_sfcall: case en_sfcallb:
								case en_fcallb: case en_pfcallb:
								case en_callblock:
												return(floatrecurse(node->v.p[1]));
                case en_not:    case en_compl:
                case en_uminus:  case en_asuminus: case en_ascompl:
                case en_ainc:   case en_adec: case en_cl_reg:
								case en_moveblock: case en_stackblock:
                        return floatrecurse(node->v.p[0]);
								case en_refassign: case en_assign:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_udiv:	case en_umod: case en_pmul:
                case en_mul:    case en_div:
                case en_mod:    case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_land:   case en_lor:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh: case en_asxor:
                case en_asrsh:
                        return(floatrecurse(node->v.p[0]) || floatrecurse(node->v.p[1]));
                case en_void:   case en_cond: case en_repcons:
                        return floatrecurse(node->v.p[1]);
	}
	return(0);
}
void floatcheck(ENODE *node)
/*
 * Error if node will be promoted to type float
 */
{
	if (floatrecurse(node))
		generror(ERR_INVFLOAT,0,0);
}
int     castbegin(int st)
/*
 *      return 1 if st in set of [ kw_char, kw_short, kw_long, kw_int, kw_bool
 *      kw_float, kw_double, kw_struct, kw_union, kw_float, or is typedef ]
 */
{      
	SYM *sp;
	switch(st) {
		case kw_void:
		case kw_char: case kw_short: case kw_int: case kw_long:
		case kw_float: case kw_double:	case kw_bool:
		case kw_struct:	case kw_union: case kw_signed:
		case kw_unsigned:	case kw_volatile:	case kw_const:
			return 1;
		default:
			if (st != id)
				return 0;
	} 
	nm = lastid;
	sp = gsearch(lastid);
	if (sp && sp->storage_class == sc_type)
		return 1 ;
	return 0;
}

int tostring()
{
	char string[4096];
	int st = lastst;
	int size = 0;
	string[0] = 0;
	while (lastst == st) {
		if (st == lsconst) {
			if (laststrlen + size > 2040) {
				generror(ERR_STRINGTOOBIG,0,0);
				break;
			}
			else {
				memcpy(string+size*2,laststr,2*laststrlen);
				((short *)string)[size + laststrlen] = 0;
			}
		}
		else {
			if (laststrlen + size > 4090) {
				generror(ERR_STRINGTOOBIG,0,0);
				break;
			}
			else {
				memcpy(((char *)string)+size,laststr,laststrlen);
				((char *) string)[size + laststrlen] = 0;
			}
		}
		size += laststrlen;
		getsym();
	}
	return(stringlit(string,st == lsconst,size+1));
}
#ifdef CPLUSPLUS
static void postfixwarning(int st)
{
	char buf[100],*p;
	sprintf(buf,"@%s",cpp_funcname_tab[st + IT_THRESHOLD]);
	p = litlate(buf);
	gensymerror(ERR_OVOPPOSTFIX,p);
}
#endif

ENODE *onefunc(ENODE *pnode , TYP **tptr, ENODE *qnode, TYP *tp1) 
{
   int continuetc = FALSE ;
	SYM *sp ;
	ENODE *tcnode = 0,*rnode;
	/* Now a check for overloaded () */
#ifdef CPLUSPLUS
	tcnode = 0 ;
	if (pnode->nodetype == en_thiscall) {
		tcnode = pnode->v.p[0] ;
      pnode = pnode->v.p[1] ;
	}
	if (prm_cplusplus && isstructured((*tptr))) {
		SYM *sp1 = search(cpp_funcname_tab[ov_arg],(*tptr)->lst.head);
		if (!sp1) {
      gensymerrorexp(ERR_NOFUNC,nm);
			goto exit ;
		}
      sp = funcovermatch(sp1,tp1,FALSE);
		if (!sp) {
      gensymerrorexp(ERR_NOFUNC,nm);
			goto exit ;
		}		
		(*tptr) = sp->tp;
		tcnode = pnode ;
		pnode = makenode(en_napccon,sp,0) ;
		goto foundfunc;
	}
#endif
  if( (*tptr)->type != bt_defunc && (*tptr)->type != bt_func &&
  			(*tptr)->type != bt_ifunc && ((*tptr)->type != bt_pointer || (*tptr)->btp->type != bt_func)) {
		if ((*tptr)->type != bt_matchall)
         gensymerrorexp(ERR_NOFUNC,nm);
	}
  else {
		int notbase=0;
#ifdef CPLUSPLUS
		if (prm_cplusplus && (*tptr)->sp) {
			char *p = (*tptr)->sp->name;
			if (prm_cmangle && (*p == '_')) p++;
			if (!strcmp(p,"main"))
				generror(ERR_NOMAIN,0,0);
		}
		if ((*tptr)->type == bt_defunc) {
         int icon ;
			nm = fullcppmangle((*tptr)->sp->parentclass,(*tptr)->sp->name,tp1);
         sp = funcovermatch((*tptr)->sp,tp1,FALSE);
			if (!sp) {
				gensymerror(ERR_NOFUNCMATCH,nm);
            pnode = 0;
				goto exit ;
			}
			sp->extflag = TRUE ;
         if (tcnode) {
            icon = 0 ;
            if (sp->value.classdata.vtaboffs)
               icon = sp->value.classdata.vtaboffs ;
            else if (declclass) {
               CLASSLIST *l = declclass->value.classdata.baseclass ;
               while (l) {
                  if (!strcmp(l->data->name,sp->parentclass->name))
                     break ;
                  l = l->link ;
               }
               if (l)
                  icon = l->offset ;
            }
            if (icon)
               tcnode = makenode(en_addstruc,tcnode,makenode(en_icon,(char *)icon,0)) ;
         }
			if ((sp->value.classdata.cppflags & PF_VIRTUAL) && !notbase) {
				ENODE *inode,*nnode ;
				inode = makenode(en_icon,(char *)sp->value.classdata.vtabindex,0);
				nnode = makenode(en_l_ref,tcnode,0) ;
				pnode = makenode(en_add,inode,nnode);
				pnode = makenode(en_l_ref,pnode,0);
            if (tcnode && icon)
               tcnode = makenode(en_addstruc,tcnode,makenode(en_icon,(char *)icon,0)) ;
		  } else 
				if (sp->tp->type == bt_pointer) {
       		pnode = makenode(en_nacon,sp,0);
					deref(&pnode,sp->tp);
				}
				else
       		pnode = makenode(en_napccon,sp,0);
				(*tptr) = sp->tp;
		} else
#endif
		{
			sp = (*tptr)->sp;
		}
#ifdef CPLUSPLUS
foundfunc:
		/* Check if (*tptr) is a base class of the current func */
      if (prm_cplusplus && sp->parentclass) {
			SYM *sp1 = declclass;
         if (sp1) {
            CLASSLIST *l = sp1->value.classdata.baseclass ;
            notbase = TRUE;   
            while (sp1) {
               if (sp1 == sp->parentclass) {
                  notbase = FALSE ;
                  goto finish ;
               }
               sp1 = l->data;
               l = l->link ;
            }
			}
			if (sp &&
					((sp->value.classdata.cppflags & PF_MEMBER) && 
					!(sp->value.classdata.cppflags & PF_STATIC) &&
					(!tcnode) && 
					((!declclass || notbase) ||
					(currentfunc && (currentfunc->value.classdata.cppflags & PF_MEMBER) &&
					(currentfunc->value.classdata.cppflags & PF_STATIC)))))
				if (!strstr(sp->name,"$ocall"))
					gensymerror(ERR_NONSTATICMUSTCLASS,sp->name);
		}
#endif
finish:
		sp->extflag = TRUE ;
		/* make a function node */
		parmlist(&qnode,tp1,(*tptr));
		pnode = makenode(en_void,pnode,qnode);
      rnode = makenode(en_icon,(char *)(sp->tp->btp->type == bt_float ? 6 : sp->tp->btp->size),0);
      if ((*tptr)->type == bt_pointer) {
         (*tptr) = (*tptr)->btp;
         continuetc = TRUE; 
      }
     (*tptr) = (*tptr)->btp;

		if (sp->intflag)
      pnode = makenode(en_intcall,qnode,pnode);
		else
			if (isstructured((*tptr))) {
				if (sp->pascaldefn)
	       		pnode = makenode(en_pfcallb,rnode,pnode);
					else 
				  	if (sp->isstdcall)
	        	  pnode = makenode(en_sfcallb,rnode,pnode);
						else
	        	  pnode = makenode(en_fcallb,rnode,pnode);
               pnode->size = (*tptr)->size;
			}
			else
				if (sp->pascaldefn)
          pnode = makenode(en_pfcall,rnode,pnode);
				else
					if (sp->isstdcall)
            pnode = makenode(en_sfcall,rnode,pnode);
          else
						pnode = makenode(en_fcall,rnode,pnode);
#ifdef CPLUSPLUS
      if (prm_cplusplus && tcnode && (continuetc ||
				(sp->value.classdata.cppflags & PF_MEMBER) &&
            !(sp->value.classdata.cppflags & PF_STATIC)))
			pnode = makenode(en_thiscall, tcnode, pnode);
		pnode = doinline(pnode);
#endif
		pnode->cflags = (*tptr)->cflags;
	}
exit :
	return pnode ;
}
ENODE *complex_functions(ENODE *pnode , TYP **tptr, ENODE *qnode, TYP *tp1) 
{
	TYP **tp3, **tp4 ;
	ENODE *ep3, *ep4 ;
	if ((*tptr)->type != bt_cond)
		return onefunc(pnode,tptr,qnode,tp1) ;

	ep3 = pnode->v.p[1]->v.p[0] ;
	ep4 = pnode->v.p[1]->v.p[1] ;
	tp3 = &(*tptr)->lst.head ;
	tp4 = &(*tptr)->lst.tail ;
	ep3 = complex_functions(ep3,tp3,qnode,tp1 );
	ep4 = complex_functions(ep4,tp4,qnode,tp1 );
	pnode->v.p[1]->v.p[0] = ep3 ;
	pnode->v.p[1]->v.p[1] = ep4 ; 
	return pnode ;
	
}
TYP     *primary(ENODE **node)
/*
 *      primary will parse a primary expression and set the node pointer
 *      returning the type of the expression parsed. primary expressions
 *      are any of:
 *                      id
 *                      constant
 *											true or false
 *                      string
 *											this
 *											::primary
 *                      ( expression )
 *                      primary++
 *                      primary--
 *                      primary[ expression ]
 *                      primary.id
 *                      primary->id
 *                      primary( parameter list )
 *                      primary.*id
 *                      primary->*id
 *											(* expression)( parameter list )
 *                      (typecast)primary
 *                      (typecast)(unary)
 */
{       ENODE    *pnode=0, *qnode, *rnode;
        SYM             *sp=0;
        TYP             *tptr,*tp1,*tp2;
				int flag = 0;
				int gcode;
				int isstring = FALSE,gdf;
				SYM *lastdeclclass =declclass;
        switch( lastst ) {
						case kw__trap:    
									getsym();
									if (needpunc(openpa,0)) {
										long num = intexpr(0);
										if (num > 255 || num < 0)
											generror(ERR_INVTRAP,0,0);
										qnode = makenode(en_icon,(char *)num,0);
										pnode = makenode(en_trapcall,qnode,0);
										needpunc(closepa,0);
									}
									goodcode |= GF_ASSIGN;
									*node = pnode;
									return &stdint;

						case kw_D0:
						case kw_D1:
						case kw_D2:
						case kw_D3:
						case kw_D4:
						case kw_D5:
						case kw_D6:
						case kw_D7:
						case kw_D8:
						case kw_D9:
						case kw_DA:
						case kw_DB:
						case kw_DC:
						case kw_DD:
						case kw_DE:
						case kw_DF:
												tptr = xalloc(sizeof(TYP));
												*tptr = stduns;
												tptr->sp = 0;
												pnode = makenode(en_regref,(char *)(regdsize*256+lastst-kw_D0),0);
												pnode = makenode(en_ul_ref,pnode,0);
												*node = pnode;
												getsym();
												return tptr;
						case kw_A0:
						case kw_A1:
						case kw_A2:
						case kw_A3:
						case kw_A4:
						case kw_A5:
						case kw_A6:
						case kw_A7:
						case kw_A8:
						case kw_A9:
						case kw_AA:
						case kw_AB:
						case kw_AC:
						case kw_AD:
						case kw_AE:
						case kw_AF:
												tptr = xalloc(sizeof(TYP));
												*tptr = stduns;
												tptr->sp = 0;
												pnode = makenode(en_regref,(char *)(regasize*256+lastst-kw_D0),0);
												pnode = makenode(en_ul_ref,pnode,0);
												*node = pnode;
												getsym();
												return tptr;
						case kw_F0:
						case kw_F1:
						case kw_F2:
						case kw_F3:
						case kw_F4:
						case kw_F5:
						case kw_F6:
						case kw_F7:
						case kw_F8:
						case kw_F9:
						case kw_FA:
						case kw_FB:
						case kw_FC:
						case kw_FD:
						case kw_FE:
						case kw_FF:
												tptr = xalloc(sizeof(TYP));
												*tptr = stdlongdouble;
												tptr->sp = 0;
												pnode = makenode(en_regref,(char *)(regfsize *256+lastst-kw_D0),0);
												pnode = makenode(en_longdoubleref,pnode,0);
												*node = pnode;
												getsym();
												return tptr;
						case kw_asm:
												if (prm_ansi) {
													strcpy(lastsym,"_asm");
												}
												else goto dodefault;
						case kw__export:
												if (prm_ansi) {
													strcpy(lastsym,"_export");
												}
												else goto dodefault;
						case kw__import:
												if (prm_ansi) {
													strcpy(lastsym,"_import");
												}
												else goto dodefault;
						case kw__pascal:
												if (prm_ansi) {
													strcpy(lastsym,"_pascal");
												}
												else goto dodefault;
						case kw__stdcall:
												if (prm_ansi) {
													strcpy(lastsym,"_stdcall");
												}
												else goto dodefault;
						case kw__indirect:
												if (prm_ansi) {
													strcpy(lastsym,"_indirect");
												}
												else goto dodefault;
						case classsel:
												getsym();
												declclass = 0;
												tptr = nameref(&pnode,0);
												declclass = lastdeclclass;
												break;
            case id:  
                        tptr = nameref(&pnode,0);
                        break;
                case iconst:
                        tptr = &stdint;
                        pnode = makenode(en_icon,(char *)ival,0);
                        getsym();
												*node = pnode;
												return tptr;
                case iuconst:
                        tptr = &stduns;
                        pnode = makenode(en_iucon,(char *)ival,0);
                        getsym();
												*node = pnode;
												return tptr;
                case lconst:
                        tptr = &stdlong;
                        pnode = makenode(en_lcon,(char *)ival,0);
                        getsym();
												*node = pnode;
												return tptr;
                case luconst:
                        tptr = &stdunsigned;
                        pnode = makenode(en_lucon,(char *)ival,0);
                        getsym();
												*node = pnode;
												return tptr;
                case cconst:
                        tptr = &stdchar;
                        pnode = makenode(en_ccon,(char *)ival,0);
                        getsym();
												*node = pnode;
												return tptr;
								case rconst:
												tptr = &stddouble;
        								pnode = xalloc(sizeof(ENODE));
								        pnode->nodetype = en_rcon;
												pnode->cflags = 0;
												pnode->v.f = rval;
												getsym();
												*node = pnode;
												return tptr;
								case lrconst:
												tptr = &stdlongdouble;
        								pnode = xalloc(sizeof(ENODE));
								        pnode->nodetype = en_lrcon;
												pnode->cflags = 0;
												pnode->v.f = rval;
												getsym();
												*node = pnode;
												return tptr;
								case fconst:
												tptr = &stdfloat;
        								pnode = xalloc(sizeof(ENODE));
								        pnode->nodetype = en_fcon;
												pnode->cflags = 0;
												pnode->v.f = rval;
												getsym();
												*node = pnode;
												return tptr;
                case sconst:
												isstring = TRUE;
                        tptr = &stdstring;
                        pnode = makenode(en_labcon,(char *)tostring(),0);
												*node = pnode;
												break;
                case lsconst:
												isstring = TRUE;
                        tptr = &stdstring;
                        pnode = makenode(en_labcon,(char *)tostring(),0);
												*node = pnode;
												break;
#ifdef CPLUSPLUS
								case kw_true:
                        tptr = &stdchar;
                        pnode = makenode(en_ccon,(char *)1,0);
                        getsym();
												*node = pnode;
												return tptr;
								case kw_false:
                        tptr = &stdchar;
                        pnode = makenode(en_ccon,(char *)0,0);
                        getsym();
												*node = pnode;
												return tptr;
								case kw_this:
												getsym();
												if (declclass) {
													if (currentfunc->value.classdata.cppflags & PF_STATIC)
														generror(ERR_STATICNOTHIS,0,0);
													pnode = makenode(en_l_ref,thisenode,0);
													tptr = maketype(bt_pointer,stdaddrsize);
													tptr->btp = declclass->tp;
												}
												else {
													generror(ERR_NOCLASSNOTHIS,0,0);
													tptr = 0;
												}
												break;
#endif
			
                case openpa:
                        getsym();
												if (lastst == star) {
/* function pointers */
																gcode = goodcode;
																goodcode &= ~(GF_AND | GF_SUPERAND);
                                getsym();
																gdf = global_deref;
																global_deref = 1;
																tptr = expression(&pnode,FALSE);
																global_deref = gdf;
																if (!tptr)
																	return 0;
																needpunc(closepa, skm_closepa);
																break;
												}
												else
castcont:
                          if( !castbegin(lastst) ) {
/* an expression in parenthesis */
																gcode = goodcode;
																goodcode &= ~(GF_AND | GF_SUPERAND);
																gdf = global_deref;
																global_deref = 0;
																tptr = expression(&pnode,FALSE);
																global_deref = gdf;
																if (!tptr)
																	return 0;
																goodcode = gcode | (goodcode & GF_ASSIGN);
                                needpuncexp(closepa,skm_closepa);
																goto contfor;
                                }
                          else    {       /* cast operator */
/* a cast */
																declid[0] = 0;
																typequal = 0;
                                decl(0,0); /* do cast declaration */
                                decl1(sc_type,0);
                                tptr = head;
                                if (needpunc(closepa, 0)) {
																	gcode = goodcode;
																	goodcode &= ~(GF_AND | GF_SUPERAND);
																	gdf = global_deref;
																	global_deref = 0;
                                 if( (tp1 = unary(&pnode)) == 0 ) {
                                        generror(ERR_IDEXPECT,0,0);
                                        tptr = 0;
                                	}
																	global_deref = gdf;
																	goodcode = gcode | (goodcode & GF_ASSIGN);
																	pnode->cflags = tptr->cflags;
																	if (tptr) {
                                                      if (prm_cplusplus && tptr->type == bt_pointer && tp1->type == bt_pointer &&
                                                            isstructured(tptr->btp) && isstructured(tp1->btp)) {
                                                         SYM *sp = tptr->btp->sp ;
                                                         SYM *s1 = tp1->btp->sp ;
                                                         CLASSLIST *l = s1->value.classdata.baseclass ;
                                                         while (l) {
                                                            if (!strcmp(sp->name,l->data->name)) {
                                                               pnode = makenode(en_addstruc,pnode,makenode(en_icon,(char *)l->offset,0)) ;
                                                               break ;
                                                            }
                                                            l = l->link ;
                                                         }
                                                      }
																		promote_type(tptr, &pnode);
																	}
																}
                                                else {
                                                   *node = makenode(en_icon,0,0) ;
                                                   return(&stdint);
                                                }
                                       } 
												*node = pnode;
												return tptr;
                default:
dodefault:
                        return 0;
                }
contfor:
/* modifiers that can appear after an expression */
        for(;;) {
								int i;
                switch( lastst ) {
                        case autoinc:
												case autodec:
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tp = mathoverload(lastst,tptr,0,&pnode,0);
													if (tp) {
														tptr = tp;
														postfixwarning(lastst);
														getsym();
											 			break;
													}
												}
#endif
																if (isstring)
																	generror(ERR_INVALIDSTRING,0,0);
                                if( tptr->type == bt_pointer )
                                        i = tptr->btp->size;
                                else
                                        i = 1;
																if (i == 0)
																	generror(ERR_ZEROPTR,0,0);
                                if(! lvalue(pnode) ) 
                                  if (tptr->cflags & DF_CONST)
                                    generror(ERR_MODCONS,0,0);
                                  else
                                    generror(ERR_LVALUE,0,0);
																if (pnode->cflags & DF_CONST)
																	generror(ERR_MODCONS,0,0);
							
#ifdef CPLUSPLUS
																checkConstClass(pnode);
#endif
                                pnode = makenode(lastst==autoinc ? en_ainc : en_adec,pnode,(char *)i);
																goodcode |= GF_ASSIGN;
																tptr->uflags |= UF_ALTERED;
                                getsym();
																break;
                        case openbr:    /* build a subscript reference */
																flag = 1;
                                getsym();
																gcode = goodcode;
																goodcode &= ~(GF_AND | GF_SUPERAND);
																gdf = global_deref;
																global_deref = 0;
																tp2 = expression(&rnode,FALSE);
																global_deref = gdf;
																goodcode = gcode & ~GF_ASSIGN;
                                needpuncexp(closebr,skm_closebr);
#ifdef CPLUSPLUS
																if (prm_cplusplus) {
																	TYP *tp = mathoverload(openbr,tptr,tp2,&pnode,&rnode);
																	if (tp) {
																		tptr = tp;
											 							break;
																	}
																}
#endif
                                if( tptr->type != bt_pointer )
                                        generrorexp(ERR_NOPOINTER,0,skm_closebr);
                                else
                                        tptr = tptr->btp;
                                qnode = makenode(en_icon,(char *)tptr->size,0);
																if (tp2) {
																	if (!isscalar(tp2) || tp2->type == bt_float || tp2->type == bt_double || tp2->type == bt_longdouble)
  	                                generror(ERR_ARRAYMISMATCH,0,0);
    	                            qnode = makenode(en_pmul,qnode,rnode);
      	                          pnode = makenode(en_add,pnode,qnode);
																	pnode->cflags = tptr->cflags;
																}
																else pnode = makenode(en_icon,0,0);
                                if( tptr->val_flag == 0 )
                                        tptr = deref(&pnode,tptr);
                            		break;
                        case pointsto: /* pointer reference */
#ifdef CPLUSPLUS
																if (prm_cplusplus) {
																	TYP *tp = mathoverload(pointsto,tptr,0,&pnode,0);
																	if (tp) {
																		tptr = tp;
																	}
																}
#endif
                                if( tptr->type != bt_pointer ) {
                                        generror(ERR_POINTTOSTRUCT,0,0);
																				while (lastst == pointsto || lastst == dot) {
																					getsym();
																					getsym();
																				}
																				break;
																}
                                else
                                        tptr = tptr->btp;
																pnode->cflags = tptr->cflags;
                                if( tptr->val_flag == 0 ) {
                                        pnode = makenode(en_ul_ref,pnode,0);
																				pnode->cflags = tptr->cflags;
																}
																goto arounddot;
/*
 *      fall through to dot operation
 */
                        case dot:
                                if( tptr->type == bt_pointer ) {
                                        generror(ERR_ADDROFSTRUCT,0,0);
																				while (lastst == pointsto || lastst == dot) {
																					getsym();
																					getsym();
																				}
																				break;
																}
arounddot:
																if (isstring)
																	generror(ERR_INVALIDSTRING,0,0);
                                getsym();       /* past -> or . */
                                if( lastst != id )
																				if (lastst == compl) {
																					getsym() ;
																					if (lastst != id) {
                                        	  generror(ERR_IDEXPECT,0,0);
																					} else {
																						TYP *tp;
																						if (strcmp(tptr->sp->name,lastid))
																							gensymerror(ERR_BADESTRUCT,tptr->sp->name);
																						else {
																							tp = gatherparms(&qnode,TRUE) ;
																							pnode = do_destructor(tptr->sp,tp,tptr,pnode,1) ;
																						}
																						getsym() ;
																						goodcode |= GF_ASSIGN ;
																						needpunc(openpa,skm_closepa) ;
																						needpunc(closepa,0) ;
																					}
																				} else
                                        	generror(ERR_IDEXPECT,0,0);
                                else    {
																				
																				tp2 = nameref(&pnode,tptr);
																			  if (tp2->bits != -1) {
																				  qnode = pnode;
																					pnode = makenode(en_bits,qnode,0);
																					pnode->bits = tp2->bits;
																					pnode->startbit = tp2->startbit;
																					pnode->cflags = tptr->cflags | pnode->v.p[0]->cflags;
																			  }
																				if (pnode->nodetype != en_placeholder)
																					pnode->cflags = tptr->cflags | pnode->v.p[0]->cflags;
																				tp2->uflags |= tptr->uflags;
																				tptr = tp2; 
																				break;
/* don't get here */
                                        sp = search(nm=litlate(lastid),&tptr->lst);
                                        if( sp == 0 ) {
                        												tptr = &stdmatch;
																								pnode = makenode(en_nacon,&undef,0);
                                                gensymerror(ERR_UNDEFINED,nm);
																								getsym();
																								while (lastst == pointsto || lastst == dot) {
																									getsym();
																									getsym();
																								}
																								break;
																				}
                                        else    {
                                                tp2 = sp->tp;
#ifdef CPLUSPLUS
																								if (prm_cplusplus) {
																									if (tp2->type == bt_class) {
																										declclass = tp2->sp;
																									}
																								}
#endif																								
																								pnode = make_callblock(0,pnode,tp2,pnode->size);
                                                qnode = makenode(en_icon,(char *)sp->value.i,0);
                                                pnode = makenode(en_addstruc,pnode,qnode);
																								pnode->cflags = tptr->cflags | pnode->v.p[0]->cflags;
																								tp2->uflags |= tptr->uflags;
																								tptr = tp2; 
                                                if( tptr->val_flag == 0 )
                                                  tptr = deref(&pnode,tptr);
																			  if (tp2->bits != -1) {
																				  qnode = pnode;
																					pnode = makenode(en_bits,qnode,0);
																					pnode->bits = tp2->bits;
																					pnode->startbit = tp2->startbit;
																					pnode->cflags = tptr->cflags | pnode->v.p[0]->cflags;
																			  }
                                        }
                                        getsym();       /* past id */
                                }
                                break;
#ifdef CPLUSPLUS
                        case pointstar: /* pointer reference to member ptr */
																if (prm_cplusplus) {
																	TYP *tp = mathoverload(pointsto,tptr,0,&pnode,0);
																	if (tp) {
																		tptr = tp;
																	}
																}
                                if( tptr->type != bt_pointer ) {
                                        generror(ERR_NOPOINTER,0,0);
																				break;
																}
                                else
                                        tptr = tptr->btp;
																pnode->cflags = tptr->cflags;
                                if( tptr->val_flag == 0 ) {
                                        pnode = makenode(en_ul_ref,pnode,0);
																				pnode->cflags = tptr->cflags;
																}
																
/*
 *      fall through to dot operation
 */
                        case dotstar:
																if (isstring)
																	generror(ERR_INVALIDSTRING,0,0);
                                getsym();       /* past ->* or .* */
                                if( lastst != id )
                                        generror(ERR_IDEXPECT,0,0);
                                else    {
																				ENODE *vnode,*snode = pnode;
                                                            if (tptr->type != bt_class && tptr->type != bt_struct)
																					generror(ERR_CLASSINSTDOTSTAR,0,0);
																				tp2 = unary(&vnode);
																				if (!tp2 || tp2->type != bt_memberptr) {
																					generror(ERR_MEMBERNAMEEXP,0,0);
																				} else {
																						sp = tp2->sp;
																						tp2 = tp2->btp;
																						if (tp2->type == bt_pointer)
		 																					tp2 = tp2->btp;
																						if (tp2->type == bt_func || tp2->type == bt_ifunc) {
																								thisx = snode;
                                                                        pnode = makenode(en_thiscall,thisx,vnode) ;
                              
																								pnode->cflags = tp2->cflags | pnode->v.p[0]->cflags;
																								tptr = maketype(bt_pointer,stdaddrsize);
																								tptr->btp = tp2;
																								tp2 = tptr;
																								tp2->uflags |= tp2->btp->uflags;
																						} else {
																							pnode = makenode(en_add,pnode,vnode);
                                                                     tptr = deref(&pnode,tp2);
																						}
                                                                  tptr->sp = sp ;
                                                            }
                                        }
                                break;
#endif
                        case openpa:    /* function reference */
																getsym();
																flag = 1;
																if (isstring)
																	generror(ERR_INVALIDSTRING,0,0);
																/* Get function args */
																tp1 = gatherparms(&qnode,FALSE);
																pnode = complex_functions(pnode,&tptr,qnode,tp1) ;
																goodcode |= GF_ASSIGN;
                                break;
                        default:
                                goto fini;
                }
        }
fini:   
				*node = pnode;
/* symbol level error checking */
				if (tptr && !flag && !isstring && !(goodcode & GF_AND) && lastsym && tptr->type != bt_func && tptr->type != bt_ifunc
							&&!tptr->val_flag && lastsym->storage_class != sc_type 
							&& lastsym->storage_class != sc_static && lastsym->storage_class != sc_global
							&& lastsym->storage_class != sc_external && lastsym->storage_class != sc_externalfunc) {
					if (!(lastsym->tp->uflags & UF_DEFINED) && lastst != assign
						&&lastst != asplus && lastst != asminus && lastst != astimes
						&& lastst!= asdivide && lastst != asmodop && lastst != asrshift
						&& lastst != aslshift && lastst != asor && lastst != asxor && lastst != asand) {
							gensymerror(ERR_SYMUNDEF,lastsym->name);
							lastsym->tp->uflags |= UF_DEFINED;
					}
					lastsym->tp->uflags &=  ~UF_ASSIGNED;
				}
				declclass = lastdeclclass;
        return tptr;
}
int isstructured(TYP *tp)
{
	switch (tp->type) {
		case bt_struct:
		case bt_class:
		case bt_union:
			return TRUE;
	}
	return FALSE;
}
int			castvalue(ENODE *node)
/*
 * See if this is a cast operator */
{
				switch(node->nodetype) {
                case en_cb: case en_cub: case en_cbool:
								case en_cw: case en_cuw:
								case en_cl: case en_cul:
								case en_cf: case en_cd: case en_cp: case en_cld:
                        case en_cll: case en_cull:
                        return 1;
                }
        return 0;
}
int     lvalue(ENODE *node)
/* See if this is an lvalue; that is has it been dereferenced?
 */
{       
				if (!prm_cplusplus) {
					while (castvalue(node))
						node = node->v.p[0];
				}
				switch( node->nodetype ) {
                case en_bool_ref:
                case en_b_ref:
                case en_w_ref:
                case en_l_ref:
                case en_ub_ref:
                case en_uw_ref:
                case en_ul_ref:
								case en_floatref:
								case en_doubleref:
								case en_longdoubleref:
                        case en_ull_ref:
                        case en_ll_ref:
                        return 1;
                        case en_bits: case en_cl_reg:
                        return lvalue(node->v.p[0]);
                }
        return 0;
}

TYP     *unary(ENODE **node)
/*
 *      unary evaluates unary expressions and returns the type of the
 *      expression evaluated. unary expressions are any of:
 *
 *                      primary
 *                      ++unary
 *                      --unary
 *                      !unary
 *                      ~unary
 *                      &unary
 *                      -unary
 *                      *unary
 *                      sizeof(typecast)
 *
 */
{       TYP             *tp,*tp1,*oldandtyp = andtyp;
        ENODE    *ep1, *ep2;
        int            i,gdf, needclose,st;
				
				thisx = 0;
        switch( lastst ) {
                case autodec:
                /* fall through to common increment */
                case autoinc:
												st = lastst;
                        getsym();
												gdf = global_deref;
												global_deref = 0;
                        tp = unary(&ep1);
												global_deref = gdf;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
												goodcode |= GF_ASSIGN;
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(st,tp,0,&ep1,0);
													if (tptr) {
														tp = tptr;
											 			break;
													}
												}
#endif
                        if( lvalue(ep1)) {
#ifdef CPLUSPLUS
																checkConstClass(ep1);
#endif
                                if( tp->type == bt_pointer ) {
																				if (tp->btp->size == 0)
																					generror(ERR_ZEROPTR,0,0);
                                        ep2 = makenode(en_icon,(char *)tp->btp->size,0);
																}
                                else
                                        ep2 = makenode(en_icon,(char *)1,0);
																if (ep1->cflags & DF_CONST)
																	generror(ERR_MODCONS,0,0);
                                ep1 = makenode(st == autodec ? en_assub : en_asadd,ep1,ep2);
                                }
                        else {
                                  if (tp->cflags & DF_CONST)
                                    generror(ERR_MODCONS,0,0);
                                  else
                                    generror(ERR_LVALUE,0,0);
																return(0);
												}
												tp->uflags |= UF_ALTERED;
                        break;
                case minus:
								case plus: {
												int stt = lastst;
                        getsym();
												gdf = global_deref;
												global_deref = 0;
                        tp = unary(&ep1);
												global_deref = gdf;
												goodcode &= ~GF_ASSIGN;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(stt,tp,0,&ep1,0);
													if (tptr) {
														tp = tptr;
											 			break;
													}
												}
#endif
												if (stt == minus) 
                        	ep1 = makenode(en_uminus,ep1,0);
												}
                        break;
                case not:
                        getsym();
												gdf = global_deref;
												global_deref = 0;
                        tp = unary(&ep1);
												global_deref = gdf;
												goodcode &= ~GF_ASSIGN;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(not,tp,0,&ep1,0);
													if (tptr) {
														*node = ep1;
														tp = tptr;
											 			break;
													}
												}
#endif
                        ep1 = makenode(en_not,ep1,0);
                        break;
                case compl:
                        getsym();
												if (lastst == id) {
													if (declclass && !strcmp(lastid,declclass->name)) {
                                          generror(ERR_ILLSTRUCT,0,0) ;
														tp = gatherparms(&ep1,TRUE ) ;
														ep2 = thisenode ;
														deref(&ep2,&stdint); /* fixme */
														ep1 = do_destructor(declclass,tp,declclass->tp,ep2,1) ;
														goodcode |= GF_ASSIGN ;
														getsym() ;
														needpunc(openpa, skm_closepa) ;
														needpunc(closepa, 0) ;
														break ;
													}
												}
												gdf = global_deref;
												global_deref = 0;
                        tp = unary(&ep1);
												global_deref = gdf;
												goodcode &= ~GF_ASSIGN;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
												floatcheck(ep1);
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(compl,tp,0,&ep1,0);
													if (tptr) {
														*node = ep1;
														tp = tptr;
											 			break;
													} else if (tp->type == bt_struct || tp->type == bt_class) {
														if (lastst == openpa) {
															getsym() ;
					 		      	      	if (lastst != closepa)
																generror(ERR_NODESTRUCTARG,0,skm_declclosepa);
															else
																getsym();
														
														}
													}
												}
#endif
                        ep1 = makenode(en_compl,ep1,0);
                        break;
                case star:
                        getsym();
												gdf = global_deref;
												global_deref = 0;
                        tp = unary(&ep1);
												global_deref = gdf;
												goodcode &= ~GF_ASSIGN;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(star,tp,0,&ep1,0);
													if (tptr) {
														tp = tptr;
											 			break;
													}
												}
#endif
                        if( tp->btp == 0 ) {
                                generror(ERR_DEREF,0,0);
												}
                        else
														if (tp->btp->type != bt_void)
                                tp = tp->btp;
												ep1->cflags = tp->cflags;
                        if( tp->val_flag == 0 )
                                tp = deref(&ep1,tp);
                        break;
                case and:
                        getsym();
												if (!(goodcode & GF_INFUNCPARMS))
													goodcode |= GF_AND;
												gdf = global_deref;
												global_deref = 0;
												andtyp = asntyp;
                        tp = unary(&ep1);
												andtyp = oldandtyp;
												global_deref = gdf;
												goodcode &= ~GF_AND;
												goodcode &= ~GF_ASSIGN;
                        if( tp == 0 ) {
                                generror(ERR_IDEXPECT,0,0);
                                return 0;
                                }
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(and,tp,0,&ep1,0);
													if (tptr) {
														tp = tptr;
											 			break;
													}
												}
												if (tp->btp == bt_memberptr) {
								          generror(ERR_NOADDRMEMBERPTR,0,0);
													return 0;
												} 

#endif
												else if (tp->startbit != -1) 
													generror(ERR_BFADDR,0,0);
												else if (tp->cflags & DF_AUTOREG)
													gensymerror(ERR_NOANDREG,tp->sp->name);
												else if (tp->type == bt_pointer && tp->val_flag && !(goodcode & GF_SUPERAND))
													generror(ERR_SUPERAND,0,0);

												tp->uflags |= UF_ALTERED;
#ifdef CPLUSPLUS
												if (prm_cplusplus && tp->sp && !tp->sp->parentclass) {
													char *p = tp->sp->name;
													if (prm_cmangle)
														p++;
													if (!strcmp(p,"main"))
														generror(ERR_MAINNOPTR,0,0);
												}
												if ((tp->type == bt_defunc || tp->type == bt_func) &&
														tp->sp->parentclass)
													generror(ERR_MUSTCALLMEMBER,0,0);
												if (tp->type == bt_member) {
													SYM *sp = tp->btp->sp;
													tp = sp->tp;
													tp1 = maketype(bt_memberptr,stdmemberptrsize);
													tp1->btp = copytype(tp,0);;
													tp1->sp = tp->sp->parentclass;
													if (tp->type == bt_func || tp->type == bt_ifunc) {
														if (tp->sp->value.classdata.cppflags & PF_VIRTUAL) {
															SYM *sp1=gen_mp_virtual_thunk(sp);
															ep1 = makenode(en_napccon,sp1,0);
														} else {
															ep1 = makenode(en_napccon,sp,0);
														}
													} else {
														ep1 = makenode(en_icon,(void *)sp->value.i,0);
													}
													tp = tp1;
												}
												else 
#endif
												{
	                        if( lvalue(ep1) && !tp->val_flag) {
																	while (castvalue(ep1))
																		ep1 = ep1->v.p[0];
  	                              ep1 = ep1->v.p[0];
																 	if (ep1->nodetype == en_regref)
																		gensymerror(ERR_NOANDREG,tp->sp->name);
													}
													tp1 = maketype(bt_pointer,4);
                	        tp1->btp = tp;
													tp = tp1;
												}
												break;
                case kw_sizeof:
                        getsym();
												needclose = FALSE;
												if (lastst == openpa) {
													needclose = TRUE;
													getsym();
												}

												if (castbegin(lastst)) {
sizeof_cast:
													typequal = 0;
                        	decl(0,0);
													decl1(sc_type,0);
												}
												else if (lastst == id) {
													SYM *sp = gsearch(lastid);
													if (!sp)
														sp = search(lastid,&lsyms);
													if (sp) {
															goto sizeof_primary;
													}
													if ((sp = search(nm,&tagtable)) != 0) {
														head = sp->tp;
														getsym();
													}
													else {
														generror(ERR_SIZE,0,0);
														head = 0;
													}
												}
												else if (lastst == kw_enum) {
													getsym();
													if (lastst == id) {
														SYM *sp;
														if ((sp = search(nm,&tagtable)) != 0) {
															head = sp->tp;
															getsym();
														}
														else goto sizeof_primary;
													}
												}
												else  {
													ENODE *node = 0;
sizeof_primary:
													gdf = global_deref;
													global_deref = 0;
													head = unary(&node);
													global_deref = gdf;
												}
                        if( head != 0 ) {
																if (head->size == 0)
																	generror(ERR_SIZE,0,0);
                                ep1 = makenode(en_icon,(char *)head->size,0);
												}
                        else    {
                                generror(ERR_IDEXPECT,0,0);
                                ep1 = makenode(en_icon,(char *)0,0);
                                }
												goodcode &= ~GF_ASSIGN;
                        tp = &stdint;
												if (needclose)
                        	needpunc(closepa,0);
                        break;
                default:
                        tp = primary(&ep1);
												if (!tp)
													return 0;
                        break;
                }
/* Dereference if necessary */
				if (global_deref) {
								global_deref = 0;
								goodcode &= ~GF_ASSIGN;
                if( tp == 0 ) {
                        generror(ERR_IDEXPECT,0,0);
                        return 0;
                        }
                if( tp->btp == 0 ) {
                        generror(ERR_DEREF,0,0);
								}
                else
										if (tp->btp->type != bt_void)
                        tp = tp->btp;
								ep1->cflags = tp->cflags;
                if( tp->val_flag == 0 )
                		tp = deref(&ep1,tp);
				}
        *node = ep1;
        return tp;
}
#ifdef CPLUSPLUS
/*
 * This handles calling an overloaded math (unary or binary) operator
 * in C++.
 */
ENODE *makeparam(ENODE *in, ENODE *link, TYP *tp)
{
	ENODE *rv;
	if (tp->val_flag && isstructured(tp)) {
		rv = makenode(en_stackblock,in,link);
		in->size = tp->size;
	}
	else
	 	rv = makenode(en_void,in,link);
	return rv;
}
TYP *mathoverload(enum e_bt lst,TYP *tp1,TYP *tp2,ENODE **ep1,ENODE **ep2)
{
	ENODE *rte=0;
	TYP *rtp = 0;
	TYP tpfunc,tpvoid;
	SYM s1,s2,*spx=0;
	char *buf;
	int memfunc = FALSE;
	if (!prm_cplusplus)
		return 0;
	memset(&s1,0,sizeof(s1));
	memset(&s2,0,sizeof(s2));
	memset(&tpfunc,0,sizeof(tpfunc));
	memset(&tpvoid,0,sizeof(tpvoid));
	tpvoid.type = bt_void;
	tpfunc.type = bt_func;
	s1.tp = tp1;
	if (tp2)
		s2.tp = tp2;
	else
		s2.tp = &tpvoid;
	if (isstructured(tp1)) {
		tpfunc.lst.head = &s2;
		spx = search(cpp_funcname_tab[lst + IT_THRESHOLD],tp1->lst.head);
		if (spx)
         spx = funcovermatch(spx,&tpfunc,FALSE);
		if (spx)
			memfunc = TRUE;
	} 
	if (!spx && (isstructured(tp1) || tp2 && isstructured(tp2))) {
		tpfunc.lst.head = &s1;
		if (tp2)
			s1.next = &s2;
		else
			s1.next = 0;
		spx = gsearch(cpp_funcname_tab[lst + IT_THRESHOLD]);
		if (spx)
         spx = funcovermatch(spx,&tpfunc,FALSE);
	}
	if (spx) {
		ENODE *qnode;
		spx->extflag = TRUE ;
		rtp = spx->tp->btp;
		if (memfunc) {
			if (tp2)
				rte = makeparam(*ep2,rte,spx->tp->lst.head->tp);
		} else {
			rte = makeparam(*ep1,0,spx->tp->lst.head->tp);
			if (tp2)
				rte = makeparam(*ep2,rte,spx->tp->lst.head->next->tp);
		}
		if (rte)
			rte = makenode(en_cp,rte,0);
		else
			rte = makenode(en_void,0,0);
		rte = makenode(en_void,makenode(en_napccon,spx,0),rte);
		qnode = makenode(en_icon,(char *)spx->tp->btp->size,0);
					if (isstructured(rtp)) {
	        	rte = makenode(en_fcallb,qnode,rte);
						(rte)->size = rtp->size;
					}
					else
						rte = makenode(en_fcall,qnode,rte);
		if (memfunc) {
			rte = makenode(en_thiscall,*ep1,rte);
		}
		rte = doinline(rte);
		*ep1 = rte;
	}
	return rtp;
}
#endif
TYP *maxsize(TYP *tp1, TYP *tp2)
/*
 * return the type that has the maximum size
 */
{
	if (tp1->type > tp2->type)
		return tp1;
	return tp2;
}
#ifdef CPLUSPLUS
TYP *ambigcontext(TYP *tp, int *rv)
{
	SYM *sp;
	if (tp->type != bt_defunc)
		return tp;
   if (tp->lst.head != tp->lst.tail) {
		gensymerror(ERR_AMBIGCONTEXT,tp->sp->name);
		*rv = 1;
	}
	sp = tp->lst.head;
	return sp->tp;
}
#endif
TYP     *forcefit(ENODE **node1,TYP *tp1,ENODE **node2,TYP *tp2, int max, int allowpointers, int matchref)
/*
 * compare two types and determine if they are compatible for purposes
 * of the current operation.  Return an appropriate type.  Also checks for
 * dangerous pointer conversions...
 */
{				int error = ERR_MISMATCH;
				TYP *tp3;
				if (tp1->type == bt_matchall)
					return tp1;
				if (tp2->type == bt_matchall)
					return tp2;
#ifdef CPLUSPLUS
				if (matchref && tp1->type == bt_memberptr && tp2->type == bt_memberptr) {
					if (exactype(tp1,tp2))
						return tp1;
				}
#endif
				if (tp1->type == bt_member || tp2->type == bt_member) {
					generror(ERR_OBJECTNEEDED,0,0);
					return tp1->btp ;
				}
				tp1 = basictype(tp1);
				tp2 = basictype(tp2) ;
       	switch( tp1->type ) {
								case bt_defunc:
									if (exactype(tp1,tp2))
										return tp1 ;
								case bt_void:
									if (tp2->type == bt_void)
										return tp1 ;
                           break ;
                case bt_long:
								case bt_int:
												if (isintconst((*node2)->nodetype)) {
													if ((!prm_cplusplus && (tp2->type == bt_pointer)))
														return tp2;
												}
                        if( tp2->type == bt_pointer)
                          return tp2;
												else if  (allowpointers && (tp2->type == bt_pointer))
													return &stdint;
												else if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
														return(tp1);
                        break;
                case bt_pointer:
												if (!prm_cplusplus && !max && (tp2->type == bt_short || tp2->type == bt_unsignedshort
													|| tp2->type == bt_char || tp2->type == bt_unsignedchar)) {
														error = ERR_SHORTPOINTER;
														break;
												}
												if (tp2->type == bt_func || tp2->type == bt_ifunc)
													return tp1;
                        if( tp2->type == bt_pointer) {

											  	if  (allowpointers)
													  return &stdint;
													else
                            return tp1;
												}
												if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
														return(tp1);
                        break;
								case bt_enum:
                case bt_unsignedshort:
                case bt_short:
												if (isintconst((*node2)->nodetype)) {
													if (!max && ((*node2)->v.i < -65536L || ((*node2)->v.i > 65535L))) {
														error = ERR_LOSTCONV;
														break;
													}
												}
												else
					 								if (!max && (tp2->type == bt_long || tp2->type == bt_unsigned || (!prm_cplusplus && (tp2->type == bt_pointer)))) {
						 								error = ERR_LOSTCONV;
							 	 						break;
													}
											  if  (allowpointers && tp2->type == bt_pointer)
													return &stdint;
												else if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
                            return(tp1);
												break;
                case bt_char:
                case bt_unsignedchar:
                case bt_bool:
												if (isintconst((*node2)->nodetype)) {
													if (!max && ((*node2)->v.i < -256 || ((*node2)->v.i > 255))) {
														error = ERR_LOSTCONV;
														break;
													}
												}
												else
					 								if (!max && (tp2->type == bt_long || tp2->type == bt_unsigned || ( !prm_cplusplus && tp2->type == bt_pointer)
						 									|| tp2->type == bt_short || tp2->type == bt_unsignedshort)) {
						 								error = ERR_LOSTCONV;
							 	 						break;
													}
											  if  (allowpointers && (tp2->type == bt_pointer))
													return &stdint;
												else if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
														return(tp1);
												break;
								case bt_float:
								case bt_double:
								case bt_longdouble:
												if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
														return(tp1);
												break;
                case bt_unsigned:
								case bt_unsignedlong:
												if (isintconst((*node1)->nodetype)) {
													if (!prm_cplusplus && tp2->type == bt_pointer)
														return tp2;
												}
                        if( !prm_cplusplus && (tp2->type == bt_pointer))
											  	if  (allowpointers)
														return &stdint;
													else
														return tp2;
											  if (isscalar(tp2))
													if (max)
														return(maxsize(tp1,tp2));
													else
														return(tp1);
                        break;
								case bt_func:
								case bt_ifunc:
												if (tp2->type == bt_func || tp2->type == bt_ifunc || tp2->type == bt_pointer)
													return tp1;
												break;
                }
#ifdef CPLUSPLUS
				if (error == ERR_MISMATCH && prm_cplusplus) {
					int toerr = 0;
					TYP *tp3 = ambigcontext(tp1,&toerr);
					TYP *tp4 = ambigcontext(tp2,&toerr);
					if (!toerr)
						genmismatcherror(tp4,tp3);
				}
				else
#endif
        	generror( error,0,0 );
        return tp1;
}

int     isscalar(TYP *tp)
/*
 * this is misnamed... it checks for ANY basic numeric type
 */
{       return  tp->type == bt_char ||  tp->type == bt_bool || tp->type == bt_unsignedchar ||
                tp->type == bt_short || tp->type == bt_unsignedshort ||
                tp->type == bt_long || tp->type == bt_unsigned || tp->type == bt_enum ||
                        tp->type == bt_int || tp->type == bt_unsignedlong 
                        || tp->type == bt_unsignedlonglong || tp->type == bt_longlong
								|| tp->type == bt_float || tp->type == bt_double || tp->type == bt_longdouble;
}
void checknp(TYP *tp1,TYP*tp2,ENODE *ep1, ENODE *ep2)
/*
 * look for non-portable pointer conversions
 */
{

#ifdef CPLUSPLUS
	if (prm_cplusplus)
		return;
#endif
	if (tp1->type == bt_pointer || tp2->type == bt_pointer)
		if (tp1->type != tp2->type) 
			if ((isintconst(ep1->nodetype) && ep1->v.i != 0) || (isintconst(ep2->nodetype) && ep2->v.i != 0))
				generror(ERR_NONPORT,0,0);
}

int isunsignedresult(TYP *tp1, TYP *tp2, ENODE *ep1, ENODE *ep2)
{
	int t1 = tp1->type;
	int t2 = tp2->type;
  if ( t1 == bt_unsigned || t1 == bt_unsignedchar || t1 == bt_unsignedshort || t1 == bt_pointer || t1 == bt_unsignedlong
    	||t2 == bt_unsigned || t2 == bt_unsignedchar || t2 == bt_unsignedshort ||t2 == bt_pointer || t2 == bt_unsignedlong)
		return TRUE ;
	t1 = ep1->nodetype ;
	t2 = ep2-> nodetype ;
	if (t1 == en_lucon || t1 == en_iucon || t1 == en_cub || t1 == en_cuw || t1 == en_cul ||
			t2 == en_lucon || t2 == en_iucon || t2 == en_cub || t2 == en_cuw || t2 == en_cul)
		return TRUE ;
	return FALSE ;

}
TYP     *multops(ENODE **node)
/*
 *      multops parses the multiply priority operators. the syntax of
 *      this group is:
 *
 *              unary
 *              multop * unary
 *              multop / unary
 *              multop % unary
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
        int		      oper;
        tp1 = unary(&ep1);
        if( tp1 == 0 )
                return 0;
        while( lastst == star || lastst == divide || lastst == modop ) {
                oper = lastst;
                getsym();       /* move on to next unary op */
                tp2 = unary(&ep2);
								goodcode &= ~GF_ASSIGN;
                if( tp2 == 0 ) {
                        generror(ERR_IDEXPECT,0,0);
                        *node = ep1;
                        return tp1;
                        }
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
									TYP *tptr = mathoverload(oper,tp1,tp2,&ep1,&ep2);
									if (tptr) {
										*node = ep1;
								 		return tptr;
									}
								}
#endif
                switch( oper ) {
                        case star:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        ep1 = makenode(en_umul,ep1,ep2);
                                else
                                        ep1 = makenode(en_mul,ep1,ep2);
                                break;
                        case divide:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        ep1 = makenode(en_udiv,ep1,ep2);
                                else
                                        ep1 = makenode(en_div,ep1,ep2);
                                break;
                        case modop:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        ep1 = makenode(en_umod,ep1,ep2);
                                else
                                        ep1 = makenode(en_mod,ep1,ep2);
																floatcheck(ep1);
                                break;
                        }
                tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,FALSE,FALSE);
                }
        *node = ep1;
        return tp1;
}

TYP     *addops(ENODE **node)
/*
 *      addops handles the addition and subtraction operators.
 */
{       ENODE    *ep1, *ep2, *ep3;
        TYP             *tp1, *tp2;
        int             oper;
        tp1 = multops(&ep1);
        if( tp1 == 0 )
                return 0;
        while( lastst == plus || lastst == minus ) {
                oper = lastst;
                getsym();
                tp2 = multops(&ep2);
								goodcode &= ~GF_ASSIGN;
                if( tp2 == 0 ) {
                        generror(ERR_IDEXPECT,0,0);
                        *node = ep1;
                        return tp1;
                        }
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
									TYP *tptr = mathoverload(oper,tp1,tp2,&ep1,&ep2);
									if (tptr) {
										*node = ep1;
								 		return tptr;
									}
								}
#endif
                if( tp1->type == bt_pointer ) {
										if (tp2->type == bt_pointer) {
                			forcefit(&ep1,tp1,&ep2,tp2,TRUE,FALSE,FALSE);
                			ep1 = makenode( oper == plus ? en_add : en_sub,ep1,ep2);
											ep1->cflags = ep1->v.p[0]->cflags | ep2->cflags;
											if (tp1->btp->size == 0)
												generror(ERR_ZEROPTR,0,0);
											else
                                    if (tp1->btp->size > 1)
                                       ep1 = makenode(en_pdiv,ep1,makenode(en_icon,(char *)tp1->btp->size,0));
											ep1->cflags = ep1->v.p[0]->cflags;
			 							  tp1 = &stdint;
											continue;
										}
										else {
                        tp2 = forcefit(0,&stdint,&ep2,tp2,TRUE,FALSE,FALSE);
												if (tp1->btp->size == 0)
													generror(ERR_ZEROPTR,0,0);
                        ep3 = makenode(en_icon,(char *)tp1->btp->size,0);
                        ep2 = makenode(en_pmul,ep3,ep2);
												ep2->cflags = ep2->v.p[1]->cflags;
                        }
								}
                else if( tp2->type == bt_pointer ) {
                        tp1 = forcefit(0,tp2,&ep1,tp1,TRUE,FALSE,FALSE);
												if (tp2->btp->size == 0)
													generror(ERR_ZEROPTR,0,0);
                        ep3 = makenode(en_icon,(char *)tp2->btp->size,0);
                        ep1 = makenode(en_pmul,ep3,ep1);
												ep1->cflags = ep1->v.p[1]->cflags;
                        }
                tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,FALSE,FALSE);
                ep1 = makenode( oper == plus ? en_add : en_sub,ep1,ep2);
								ep1->cflags = ep1->v.p[1]->cflags | ep2->cflags;
                }
exit:
        *node = ep1;
        return tp1;
}

TYP     *shiftop(ENODE **node)
/*
 *      shiftop handles the shift operators << and >>.
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
        int             oper;
        tp1 = addops(&ep1);
        if( tp1 == 0)
                return 0;
        while( lastst == lshift || lastst == rshift) {
                oper = (lastst == lshift);
                getsym();
                tp2 = addops(&ep2);
								goodcode &= ~GF_ASSIGN;
                if( tp2 == 0 )
                        generror(ERR_IDEXPECT,0,0);
                else    {
//                        tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,FALSE,FALSE);
            ep2 = makenode(en_cl_reg,ep2,0) ;
												if (tp1->type == bt_unsigned ||
														tp1->type == bt_unsignedchar ||
                                          tp1->type == bt_unsignedshort || tp1->type == bt_unsignedlong)
                        	ep1 = makenode(oper ? en_lsh : en_rsh,ep1,ep2);
												else
                        	ep1 = makenode(oper ? en_alsh : en_arsh,ep1,ep2);
                        }
								floatcheck(ep1);
                }
        *node = ep1;
        return tp1;
}

TYP     *relation(ENODE **node)
/*
 *      relation handles the relational operators < <= > and >=.
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
        int             nt;
        tp1 = shiftop(&ep1);
        if( tp1 == 0 )
                return 0;
        for(;;) {
								int st = lastst;
								if (lastst != lt && lastst != gt && lastst != leq && lastst != geq)
							  		goto fini;
                getsym();
                tp2 = shiftop(&ep2);
								goodcode &= ~GF_ASSIGN;
                if( tp2 == 0 )
                        generror(ERR_IDEXPECT,0,0);
                else    {
#ifdef CPLUSPLUS
										if (prm_cplusplus) {
											TYP *tptr = mathoverload(st,tp1,tp2,&ep1,&ep2);
											if (tptr) {
												*node = ep1;
									 			return tptr;
											}
										}
#endif
                    switch( st ) {

                        case lt:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        nt = en_ult;
                                else
                                        nt = en_lt;
                                break;
                        case gt:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        nt = en_ugt;
                                else
                                        nt = en_gt;
                                break;
                        case leq:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        nt = en_ule;
                                else
                                        nt = en_le;
                                break;
                        case geq:
																if (isunsignedresult(tp1,tp2,ep1,ep2))
                                        nt = en_uge;
                                else
                                        nt = en_ge;
                                break;
                    }
										checknp(tp1,tp2,ep1,ep2);
                    tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,TRUE,FALSE);
										tp1 = &stdint;
                    ep1 = makenode(nt,ep1,ep2);
                }
				}
fini:   *node = ep1;
        return tp1;
}

TYP     *equalops(ENODE **node)
/*
 *      equalops handles the equality and inequality operators.
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
        int             oper;
        tp1 = relation(&ep1);
        if( tp1 == 0 )
                return 0;
        while( lastst == eq || lastst == neq ) {
                oper = lastst;
                getsym();
                tp2 = relation(&ep2);
								goodcode &= ~GF_ASSIGN;
								checknp(tp1,tp2,ep1,ep2);
                if( tp2 == 0 )
                        generror(ERR_IDEXPECT,0,0);
                else    
												{
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(oper,tp1,tp2,&ep1,&ep2);
													if (tptr) {
														*node = ep1;
											 			return tptr;
													}
												}
#endif
                        tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,TRUE,FALSE);
												tp1 = &stdint;
                        ep1 = makenode( oper == eq ? en_eq : en_ne,ep1,ep2);
                        }
                }
        *node = ep1;
        return tp1;
}

TYP     *binop(ENODE **node,TYP *(*xfunc)(),int nt,int sy)
/*
 *      binop is a common routine to handle all of the legwork and
 *      error checking for bitand, bitor, bitxor, andop, and orop.
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
        tp1 = (*xfunc)(&ep1);
        if( tp1 == 0 )
                return 0;
        while( lastst == sy ) {
                getsym();
                tp2 = (*xfunc)(&ep2);
								goodcode &= ~GF_ASSIGN;
                if( tp2 == 0 )
                        generror(ERR_IDEXPECT,0,0);
                else    
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													TYP *tptr = mathoverload(sy,tp1,tp2,&ep1,&ep2);
													if (tptr) {
														*node = ep1;
											 			return tptr;
													}
												}
#endif
												{
                        tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE,sy == lor || sy == land,FALSE);
                        ep1 = makenode(nt,ep1,ep2);
                        }
								if (sy != lor && sy != land)
									floatcheck(ep1);
                }
        *node = ep1;
        return tp1;
}

TYP     *bitand(ENODE **node)
/*
 *      the bitwise and operator...
 */
{       return binop(node,equalops,en_and,and);
}

TYP     *bitxor(ENODE **node)
{       return binop(node,bitand,en_xor,uparrow);
}

TYP     *bitor(ENODE **node)
{       return binop(node,bitxor,en_or,or);
}

TYP     *andop(ENODE **node)
{       return binop(node,bitor,en_land,land);
}

TYP     *orop(ENODE **node)
{       return binop(node,andop,en_lor,lor);
}

TYP     *conditional(ENODE **node)
/*
 *      this routine processes the hook operator.
 */
{       TYP             *tp1, *tp2, *tp3,*tpx;
        ENODE    *ep1, *ep2, *ep3;
        tp1 = orop(&ep1);       /* get condition */

        if( tp1 == 0 )
                return 0;
        if( lastst == hook ) {
								int gcode1,gcode2;
                getsym();
                if( (tp2 = conditional(&ep2)) == 0) {
                        generror(ERR_IDEXPECT,0,0);
												goodcode &= ~GF_ASSIGN;
                        goto cexit;
                        }
                needpunc(colon,0);
								gcode2 = goodcode;
								goodcode &=~GF_ASSIGN;
                if( (tp3 = conditional(&ep3)) == 0) {
                        generror(ERR_IDEXPECT,0,0);
												goodcode &= ~GF_ASSIGN;
                        goto cexit;
                        }
								gcode1 = gcode2 & goodcode;
								goodcode = (goodcode &~GF_ASSIGN) | gcode1;
								tpx = maketype(bt_cond, 0) ;
								if (!(tp2->type == tp3->type && tp2->type == bt_defunc))
                	tp1 = forcefit(&ep2,tp2,&ep3,tp3,TRUE,FALSE,FALSE);
								tpx->btp = tp1 ;
								tpx->lst.head = (SYM *) tp2 ;
								tpx->lst.tail = (SYM *) tp3 ;
                ep2 = makenode(en_void,ep2,ep3);
                ep1 = makenode(en_cond,ep1,ep2);
								tp1 = tpx ;
					 			if ((tp3->type == bt_defunc || tp3->type == bt_func) &&
														tp3->sp->parentclass)
													generror(ERR_MUSTCALLMEMBER,0,0);
					 			if ((tp2->type == bt_defunc || tp2->type == bt_func) &&
														tp2->sp->parentclass)
													generror(ERR_MUSTCALLMEMBER,0,0);
                       
               if (tp2->type == bt_void && tp2->type == bt_void)
                  goodcode |= GF_ASSIGN ;
               else
                  goodcode &=~GF_ASSIGN;
                }
cexit:
			  *node = ep1;
        return tp1;
}
TYP *FindMemberPointer ( TYP *tp1, TYP *tp2, ENODE **ep2)
{
   SYM *sp ;
   if (tp2->btp->type != bt_defunc)
      return tp2 ;
   sp = funcovermatch(tp2->btp->sp,tp1->btp,FALSE) ;
   if (sp && !(sp->value.classdata.cppflags & PF_STATIC)) {
      if ((sp->value.classdata.cppflags & PF_INLINE) && !(sp->value.classdata.cppflags & PF_INSTANTIATED)) {
         LIST *l = xalloc(sizeof(LIST)) ;
         l->data = sp ;
         l->link = instantiated_inlines ;
         instantiated_inlines = l ;
         sp->value.classdata.cppflags |= PF_INSTANTIATED ;
      }
      sp->extflag = TRUE ;
      *ep2 = makenode(en_napccon,(void *)sp,0) ;
      return tp1 ;
   }
   return tp2 ;
}
TYP			*autoasnop(ENODE **node, SYM *sp)
/*
 * 			Handle assignment operators during auto init of local vars
 */
{       ENODE    *ep1, *ep2;
        TYP             *tp1, *tp2;
				int needclosebr = FALSE;
				getsym();
        if( (tp1 = sp->tp) == 0 ) {
					tp1 = &stdmatch;
					*node = makenode(en_nacon,&undef,0);
					gensymerror(ERR_UNDEFINED,nm);
          tp1 = deref(&ep1,tp1);
          return tp1;       /* guard against untyped entries */
        }
        if( sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
          gensymerror(ERR_ILLCLASS2,sp->name);
				if (sp->storage_class == sc_auto)
        	ep1 = makenode(en_autocon,sp,0);
				else if (sp->storage_class == sc_autoreg)
        	ep1 = makenode(en_autoreg,sp,0);
				if (tp1)
					tp1->uflags |= UF_DEFINED | UF_USED | UF_ALTERED;
				if ((tp1->uflags & UF_CANASSIGN) && !(goodcode & GF_INLOOP))
					tp1->uflags |=  UF_ASSIGNED;
        if( tp1->val_flag == 0) {
          tp1 = deref(&ep1,tp1);
				}
				else {
					/* handle static-like assignment of structures and arrays */
					/* dynamic assignments of one struc to another are handled
					 * elsewhere */
					if (lastst == begin || lastst == sconst || lastst == lsconst) {
						SYM *sp1;
						backup(assign);
						global_flag++;
						sp1 = xalloc(sizeof(SYM));
						sp1->name = xalloc(strlen(sp->name)+7);
						strcpy(sp1->name,"$$INIT");
						strcat(sp1->name,sp->name);
						sp1->tp = cponetype(sp->tp);
						sp1->storage_class = sc_static;
						sp1->staticlabel = TRUE;
						sp1->value.i = nextlabel++;
						doinit(sp1);
						ep2 = makenode(en_labcon,(char *) sp1->value.i,0);

						ep1 = makenode(en_moveblock,ep1,ep2);
						ep1->size = sp1->tp->size;
						sp->tp = sp1->tp;
						*node = ep1;
						global_flag--;

						return sp->tp;
					}
				}
        if( tp1 == 0 )
                return 0;
				if (lastst == begin) {
					needclosebr = TRUE;
					getsym();
				}
        tp2 = asnop(&ep2,tp1);
        if( tp2 == 0) {
          generror(ERR_LVALUE,0,0);
					*node = makenode(en_nacon,&undef,0);
				}
        else    {
#ifdef CPLUSPLUS
					if (prm_cplusplus) {
						TYP *tp = mathoverload(pointsto,tp1,tp2,&ep1,&ep2);
						if (tp) {
							tp1 = tp;
							goto finit;
						}
					}
#endif
					if (isstructured(tp1)) {
						if (!checktypeassign(tp1,tp2)) {
             	generror(ERR_LVALUE,0,0);
							*node = makenode(en_nacon,&undef,0);
						}
						else if (!exactype(tp1,tp2)) {
							generror(ERR_ILLSTRUCT,0,0);
							*node = makenode(en_nacon,&undef,0);
						}else {
							int thiscall = 0;
							checknp(tp1,tp2,ep1,ep2);
#ifdef CPLUSPLUS
							if (ep2->nodetype == en_thiscall) {
								ep2 = ep2->v.p[0];
								thiscall = 1;
							}
#endif
							if (ep2->nodetype == en_fcallb || ep2->nodetype == en_pfcallb || ep2->nodetype == en_sfcallb)
								if (ep2->nodetype == en_pfcallb) 
									ep1 = makenode(en_pcallblock,ep1,ep2);
								else
									if (ep2->nodetype == en_sfcallb) 
										ep1 = makenode(en_scallblock,ep1,ep2);
									else
										ep1 = makenode(en_callblock,ep1,ep2);
							else {

								ep1 = makenode(en_moveblock,ep1,ep2);
							}
#ifdef CPLUSPLUS
							if (thiscall)
								ep1 = makenode(en_thiscall,ep1,0);
#endif
							ep1->size = tp1->size;
							*node = ep1;
						}
					}
          else    {
						if (tp1->type == bt_ref) {
							if (isintconst(ep2->nodetype) || isfloatconst(ep2->nodetype)) {
								if (!isscalar(tp1->btp))
									matchreflvalue(0,tp1,tp2);
							}
							else
								matchreflvalue(0,tp1,tp2);
							if (!isintconst(ep2->nodetype) && !isfloatconst(ep2->nodetype)) {
							 	while (castvalue(ep2))
							 		ep2 = ep2->v.p[0];
								if (lvalue(ep2))
									ep2 = ep2->v.p[0];
							}
							else {
								ENODE *node = dummyvar(tp1->size,tp1);
								deref(&node,tp1->btp);
								ep2 = makenode(en_refassign,node,ep2);
								gensymerror(ERR_TEMPINIT,sp->name);
							}
						}
						else if (tp1->val_flag) {
							generror(ERR_LVALUE,0,0);
							*node = makenode(en_nacon,&undef,0);
							return tp1;
						}
						
						checknp(tp1,tp2,ep1,ep2);
                  if (tp1->type == bt_memberptr) {
                     tp2 = FindMemberPointer(tp1,tp2,&ep2) ;
                     if (!exactype(tp1,tp2))
                        generror(ERR_MEMBERPTRMISMATCH,0,0);
                  } else if (tp1->type != bt_ref)
                     tp1 = forcefit(&ep1,tp1,&ep2,tp2,FALSE,TRUE,TRUE);
						else
							tp1 = tp1->btp;
#ifdef CPLUSPLUS
						checkConstClass(ep1);
#endif
    	      *node = makenode(en_assign,ep1,ep2);
					}
        }
finit:
				if (needclosebr)
					needpunc(end,0);
				return(tp1);
}
void asncombine(ENODE **node)
/*
 * a simple optimization which turns an equate into a functional equate
 * if possible.  Code gen proceeds a little more cleanly if this info
 * is known.
 */
{
	ENODE *var = (*node)->v.p[0];
	ENODE *exp = (*node)->v.p[1];
  ENODE *var2;
		int op = 0;
	if (!exp)
		return;
	var2 = exp->v.p[0];
		switch(exp->nodetype) {
         case en_uminus:
            if (equalnode(var,var2)) {
               op = en_asuminus ;
               break ;
            } else return ;
         case en_compl:
            if (equalnode(var,var2)) {
               op = en_ascompl ;
               break ;
            } else return ;
			case en_add: case en_addstruc:
				if (equalnode(var,var2)) {
					op = en_asadd;
					break;
				} else return;
			case en_sub:
				if (equalnode(var,var2)) {
					op = en_assub;
					break;
				} else return;
			case en_mul:
				if (equalnode(var,var2)) {
					op = en_asmul;
					break;
				} else return;
			case en_umul:
				if (equalnode(var,var2)) {
					op = en_asumul;
					break;
				} else return;
			case en_div:
				if (equalnode(var,var2)) {
					op = en_asdiv;
					break;
				} else return;
			case en_udiv:
				if (equalnode(var,var2)) {
					op = en_asudiv;
					break;
				} else return;
			case en_mod:
				if (equalnode(var,var2)) {
					op = en_asmod;
					break;
				} else return;
			case en_umod:
				if (equalnode(var,var2)) {
					op = en_asumod;
					break;
				} else return;
			case en_lsh:
				if (equalnode(var,var2)) {
					op = en_aslsh;
					break;
				} else return;
			case en_alsh:
				if (equalnode(var,var2)) {
					op = en_asalsh;
					break;
				} else return;
			case en_rsh:
				if (equalnode(var,var2)) {
					op = en_asrsh;
					break;
				} else return;
			case en_arsh:
				if (equalnode(var,var2)) {
					op = en_asarsh;
					break;
				} else return;
			case en_and:
				if (equalnode(var,var2)) {
					op = en_asand;
					break;
				} else return;
			case en_or:
				if (equalnode(var,var2)) {
					op = en_asor;
					break;
				} else return;
			case en_xor:
				if (equalnode(var,var2)) {
					op = en_asxor;
					break;
				} else return;
			default:
					return;
		}
		exp->nodetype = op;
		(*node) = exp;
}

/* This checks an assignment ENODE to see if we are trying to modify
 * a class member from within a const member function
 */
void 		checkConstClass(ENODE *node)
{
        if (declclass)
          if (currentfunc->tp->cflags & DF_CONST) {
            while (castvalue(node))
              node = node->v.p[0];
            if (lvalue(node)) {
              node = node->v.p[0];
              if (!lvalue(node))
                if (node->nodetype == en_addstruc) {
                  while (node && node->nodetype == en_addstruc)
                    node = node->v.p[1];
                  if (lvalue(node)) {
                    node=node->v.p[0];
                    if (node->nodetype == en_autocon && node->v.sp == thissp)
                      generror(ERR_MODCONS,0,0);
                  }
                }
            }
          }
}
TYP     *asnop(ENODE **node,TYP *tptr)
/*
 *      asnop handles the assignment operators.
 */
{       ENODE    *ep1, *ep2, *ep3;
        TYP             *tp1, *tp2,*oldastyp;
        int             op;
				oldastyp = asntyp;
				if (tptr) 
					asntyp = tptr;
				else
					asntyp = 0;
        tp1 = conditional(&ep1);
				lastsym = 0;
				if (!tptr)
					asntyp = tp1;
        if( tp1 == 0 )
                return 0;
        for(;;) {
								int st = lastst;
                switch( lastst ) {
                        case assign:
                                op = en_assign;
ascomm:                         getsym();
                                tp2 = asnop(&ep2,asntyp);
ascomm2:                        ep3 = ep1;
																if (tp1) {
																	tp1->uflags |= UF_DEFINED | UF_ALTERED;
																}
																goodcode |= GF_ASSIGN;
																if ((tp1->uflags & UF_CANASSIGN) && !(goodcode & GF_INLOOP))
																	tp1->uflags |=  UF_ASSIGNED;
															  if (ep3->cflags & DF_CONST)
																  generror(ERR_MODCONS,0,0);
#ifdef CPLUSPLUS
																if (prm_cplusplus) {
																	TYP *tp = mathoverload(st,tp1,tp2,&ep1,&ep2);
																	if (tp) {
																		tp1 = tp;
																		break;
																	}
																}
#endif
																if( tp2 == 0 || tp1 == 0)
                                        generror(ERR_LVALUE,0,0);
																else {
#ifdef CPLUSPLUS
					
																	  if (tp1->type == bt_memberptr) {
                                                         tp2 = FindMemberPointer(tp1,tp2,&ep2) ;
																			if (!exactype(tp1,tp2))
																				generror(ERR_MEMBERPTRMISMATCH,0,0);
																			if (op != en_assign) 
																				generror(ERR_NOASSIGNCOMPLEXMEMBERPTR,0,0);
                                      ep1 = makenode(en_assign,ep1,ep2);
																			break;
																		}
																		checkConstClass(ep1);
#endif
																		if (isstructured(tp1)) {
																				if (!checktypeassign(tp1,tp2)) {
                                        	generror(ERR_LVALUE,0,0);
																				} else if (!exactype(tp1,tp2)) {
																					generror(ERR_ILLSTRUCT,0,0);
																					*node = makenode(en_nacon,&undef,0);
																				}else {
																					if (op != en_asadd && op != en_assub)
																						checknp(tp1,tp2,ep1,ep2);
																					ep1 = makenode(en_moveblock,ep1,ep2);
																					ep1->size = tp1->size;
																				}
																		}
                                  else    {
																				if (!lvalue(ep1)) 
                                                               if (tp1->cflags & DF_CONST)
                                                                 generror(ERR_MODCONS,0,0);
                                                               else
                                                                 generror(ERR_LVALUE,0,0);
																				if (op != en_asadd && op != en_assub)
																					checknp(tp1,tp2,ep1,ep2);
                                        tp1 = forcefit(&ep1,tp1,&ep2,tp2,FALSE,FALSE,TRUE);
                                        ep1 = makenode(op,ep1,ep2);
                                        }
																}
  															if (op == en_assign) {
	  															asncombine(&ep1);
																	op = ep1->nodetype;
																}
		  													if (op == en_asmod || op == en_asumod ||
			  																op ==en_aslsh || op== en_asrsh ||
				  															op == en_asalsh || op== en_asarsh ||
					  														op == en_asand || op== en_asor || op == en_asxor)
						  										floatcheck(ep1);
                                break;
                        case asplus:
                                op = en_asadd;
		
ascomm3:												getsym();
																tp2 = asnop(&ep2,asntyp);
                                if( tp1->type == bt_pointer ) {
																				if (tp1->btp->size == 0)
																					generror(ERR_ZEROPTR,0,0);
                                        ep3 = makenode(en_icon,(char *)tp1->btp->size,0);
                                        ep2 = makenode(en_pmul,ep2,ep3);
																				tp2 = tp1;
                                        }
                                goto ascomm2;
                        case asminus:
                                op = en_assub;
                                goto ascomm3;
                        case astimes:
                                if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort|| tp1->type == bt_unsignedlong)
                                        op = en_asumul;
                                else
                                        op =en_asmul;
                                goto ascomm;
                        case asdivide:
                                if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort || tp1->type == bt_unsignedlong)
                                        op = en_asudiv;
                                else
                                        op =en_asdiv;
                                goto ascomm;
                        case asmodop:
                                if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort || tp1->type == bt_unsignedlong)
                                        op = en_asumod;
                                else
                                        op =en_asmod;
                                goto ascomm;
                        case aslshift:
														if (tp1->type == bt_unsigned ||
																tp1->type == bt_unsignedchar ||
                                                tp1->type == bt_unsignedshort ||
                                                tp1->type == bt_unsignedlong)
															op = en_aslsh;
														else
                              op = en_asalsh;
                                goto ascomm;
                        case asrshift:
														if (tp1->type == bt_unsigned ||
																tp1->type == bt_unsignedchar ||
                                                tp1->type == bt_unsignedshort ||
                                                tp1->type == bt_unsignedlong)
															op = en_asrsh;
														else
                              op = en_asarsh;
                                goto ascomm;
                        case asand:
                                op = en_asand;
                                goto ascomm;
                        case asor:
                                op = en_asor;
                                goto ascomm;
                        case asxor:
                                op = en_asxor;
                                goto ascomm;
                        default:
                                goto asexit;
                        }
                }
asexit: *node = ep1;
				asntyp = oldastyp;
        return tp1;
}
TYP     *exprnc(ENODE **node)
/*
 *      evaluate an expression where the comma operator is not legal.
 * e.g. a function argument
 */
{       TYP     *tp;
        tp = asnop(node,0);
        if( tp == 0 )
                *node = 0;
				else if ((*node)->nodetype == en_fcallb || (*node)->nodetype == en_pfcallb || (*node)->nodetype == en_sfcallb)
					*node = make_callblock(0,*node,tp,tp->size);
				if (tp && tp->type == bt_void)
					goodcode |= GF_ASSIGN;
        return tp;
}

TYP     *commaop(ENODE **node)
/*
 *      evaluate the comma operator. comma operators are kept as
 *      void nodes.
 */
{       TYP             *tp1;
        ENODE    *ep1, *ep2;
	int ocode;
        tp1 = asnop(&ep1,0);
        if( tp1 == 0 )
                return 0;
        if( lastst == comma ) {
								ocode = goodcode | ~GF_ASSIGN;
								goodcode &= ~GF_ASSIGN;
								getsym();
                tp1 = commaop(&ep2);
								goodcode &= ocode;
                if( tp1 == 0 ) {
                        generror(ERR_IDEXPECT,0,0);
                        goto coexit;
                        }
                ep1 = makenode(en_void,ep1,ep2);
                }
coexit: *node = ep1;
        return tp1;
}

TYP     *expression(ENODE **node, int tocheck)
/*
 *      evaluate an expression where all operators are legal.
 */
{       TYP     *tp;
        tp = commaop(node);
        if( tp == 0 )
                *node = 0;
				else if ((*node)->nodetype == en_fcallb || (*node)->nodetype == en_pfcallb || (*node)->nodetype == en_sfcallb)
					*node = make_callblock(0,*node,tp,tp->size);
				if (tp && tp->type == bt_void)
					goodcode |= GF_ASSIGN;
        return tp;
}
