home *** CD-ROM | disk | FTP | other *** search
- /*
- * 68K/386 32-bit C compiler.
- *
- * copyright (c) 1996, 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 sources are distributed along with any executables derived from them.
- *
- * The author is not responsible for damages, either direct or consequential,
- * that may arise from use of this software.
- *
- * v1.5 August 1996
- * David Lindauer, gclind01@starbase.spd.louisville.edu
- *
- * Credits to Mathew Brandt for original K&R C compiler
- *
- */
- #include <stdio.h>
- #include "expr.h"
- #include "c.h"
- #include "gen.h"
- #include "cglbdec.h"
- #include "list.h"
- /* Default types */
- TYP stdint = { bt_long, 0, UF_DEFINED | UF_USED,0, 0,-1, -1, 4, {0, 0}, 0, 0,0 };
- TYP stdfloat = { bt_float, 0, UF_DEFINED | UF_USED,0, 0,-1, -1, 8, {0, 0}, 0, 0,0 };
- TYP stddouble = { bt_double, 0, 0,0,0, -1, -1, 8, {0, 0}, 0, 0,0 };
- TYP stduns = { bt_unsigned, 0, 0,0, 0,-1, -1, 4, {0, 0}, 0, 0,0 };
- TYP stdvoid = { bt_matchall, 0, 0 ,0, 0,-1, -1, 4, {0, 0}, 0, 0,0 };
- TYP stdmatch = { bt_matchall, 0, UF_DEFINED | UF_USED,0, 0,-1, -1, 4, {0, 0}, &stdvoid, 0,0 };
- TYP stdchar = {bt_char, 0, 0,0,0,-1, -1, 1, {0, 0}, 0, 0,0 };
- TYP stdstring = {bt_pointer, 0, 0,0,0,-1, -1, 4, {0, 0}, &stdchar, 0,0};
- TYP stdfunc = {bt_func, 1, UF_DEFINED | UF_USED,0,0,-1, -1, 0, {0, 0}, &stdint, 0,0};
- TYP stdlongdouble = {bt_longdouble,0,0,0,0,-1,-1,LDBLSIZE,{0,0},0,0,0 };
- extern TYP *head; /* shared with decl */
- extern TABLE tagtable;
- extern char declid[100];
- extern int goodcode;
- extern int prm_cplusplus;
-
- int skm_closepa[] = { closepa, comma, semicolon, end, 0 };
- int skm_closebr[] = { closebr, comma, openbr, semicolon, end, 0 };
- static SYM *lastsym;
- static int globaldref = 0;
- static char regname[] = "processor reg" ;
- static char *nm = 0;
- static char undefname[] = { "UNDEFGEN" } ;
- static TYP *asntyp = 0;
- /*
- * expression evaluation
- *
- * this set of routines builds a parse tree for an expression.
- * no code is generated for the expressions during the build,
- * this is the job of the codegen module. for most purposes
- * expression() is the routine to call. it will allow all of
- * the C operators. for the case where the comma operator is
- * not valid (function parameters for instance) call exprnc().
- *
- * each of the routines returns a pointer to a describing type
- * structure. each routine also takes one parameter which is a
- * pointer to an expression node by reference (address of pointer).
- * the completed expression is returned in this pointer. all
- * routines return either a pointer to a valid type or NULL if
- * the hierarchy of the next operator is too low or the next
- * symbol is not part of an expression.
- */
-
- void exprini(void)
- {
- globaldref = 0;
- asntyp = 0;
- }
- 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 = 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;
- 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_short:
- case bt_enum:
- *node = makenode(en_w_ref,*node,0);
- break;
- case bt_unsigned:
- *node = makenode(en_ul_ref,*node,0);
- break;
- case bt_long:
- case bt_matchall:
- case bt_pointer:
- case bt_ptrfunc:
- case bt_ref:
- *node = makenode(en_l_ref,*node,0);
- break;
- default:
- generror(ERR_DEREF,0,0);
- break;
- }
- (*node)->cflags = onode->cflags;
- return tp;
- }
-
- TYP *nameref(ENODE **node)
- /*
- * nameref will build an expression tree that references an
- * identifier. if the identifier is not in the global or
- * local symbol table then a look-ahead to the next character
- * is done and if it indicates a function call the identifier
- * is coerced to an external function name. non-value references
- * generate an additional level of indirection.
- *
- * nameref now handles primary function parameter gathering
- * primary will still do it as well, in case the function name is
- * put in parenthesis...
- */
- { SYM *sp;
- TYP *tp,*tp1;
- ENODE *pnode=0;
- int fn = FALSE;
- char buf[100];
- strcpy(buf,lastid);
- getsym();
- if (lastst == openpa) {
- fn = TRUE;
- getsym();
- tp1 = gatherparms(&pnode);
- sp = funcovermatch(buf,tp1);
- if (sp)
- tp1->sname = nm = sp->name;
- else
- if (prm_cplusplus)
- tp1->sname = nm = cppmangle(buf,tp1);
- else
- tp1->sname = nm = litlate(buf);
- }
- else {
- nm = litlate(buf);
- sp = gsearch(nm);
- }
- if( sp == 0 ) {
- if (fn) {
- if (prm_cplusplus)
- gensymerror(ERR_NOFUNCMATCH,nm);
- else
- gensymerror(ERR_NOPROTO,nm);
- ++global_flag;
- sp = xalloc(sizeof(SYM));
- sp->name = litlate(nm);
- sp->tp = &stdfunc;
- #ifdef i386
- sp->storage_class = sc_externalfunc;
- #else
- sp->storage_class = sc_external;
- #endif
- sp->extflag = TRUE;
- insert(sp,&gsyms);
- --global_flag;
- *node = makenode(en_nacon,sp->name,0);
- parmlist(&pnode,tp1,0);
- tp = &stdint;
- *node = makenode(en_fcall,*node,pnode);
- goodcode |= GF_ASSIGN;
- }
- else {
- if (prm_cplusplus && asntyp && asntyp->type == bt_ptrfunc) {
- sp = funcovermatch(lastid,asntyp);
- if (sp)
- goto foundsp;
- }
- sp = xalloc(sizeof(SYM));
- sp->name = nm;
- sp->tp = tp = &stdmatch;
- sp->storage_class = sc_external;
- insert(sp,&lsyms);
- *node = makenode(en_nacon,undefname,0);
- gensymerror(ERR_UNDEFINED,nm);
- tp = deref(node,tp);
- }
- }
- else {
- foundsp:
- sp->tp->uflags |= UF_USED;
- if( (tp = sp->tp) == 0 ) {
- tp = &stdmatch;
- *node = makenode(en_nacon,undefname,0);
- gensymerror(ERR_UNDEFINED,nm);
- tp = deref(node,tp);
- return tp; /* guard against untyped entries */
- }
- switch( sp->storage_class ) {
- case sc_static:
- case sc_global:
- case sc_external:
- case sc_externalfunc:
- case sc_abs:
- sp->extflag = TRUE;
- if (fn) {
- if (sp->tp->type == bt_ptrfunc)
- *node = makenode(en_nacon,sp->name,0);
- else
- *node = makenode(en_napccon,sp->name,0);
- isfunc:
- if (sp->tp->type != bt_ptrfunc && sp->tp->type != bt_func && sp->tp->type != bt_ifunc)
- generror(ERR_MISMATCH,0,0);
- if (sp->tp->type == bt_ptrfunc)
- tp = deref(node,tp);
- if (prm_cplusplus && !strcmp(buf,"main"))
- generror(ERR_NOMAIN,0,0);
- parmlist(&pnode,tp1,sp->tp);
- tp = tp->btp;
- if (sp->intflag)
- *node = makenode(en_intcall,*node,pnode);
- else
- if (tp->type == bt_union || tp->type == bt_struct) {
- *node = makenode(en_fcallb,*node,pnode);
- (*node)->size = tp->size;
- }
- else
- *node = makenode(en_fcall,*node,pnode);
- if (tp)
- (*node)->cflags = tp->cflags;
- goodcode |= GF_ASSIGN;
- }
- else
- if (sp->absflag)
- *node = makenode(en_absacon,(char *)sp->addr,0);
- else
- if (sp->tp->type == bt_func || sp->tp->type == bt_ifunc) {
- fn = TRUE;
- *node = makenode(en_napccon,sp->name,0);
- }
- else
- *node = makenode(en_nacon,sp->name,0);
- break;
- case sc_const:
- *node = makenode(en_icon,(char *)sp->value.i,0);
- break;
- default: /* auto and any errors */
- if( sp->storage_class != sc_auto && sp->storage_class != sc_autoreg) {
- gensymerror(ERR_ILLCLASS2,sp->name);
- tp = 0;
- }
- else {
- if (sp->storage_class == sc_auto)
- *node = makenode(en_autocon,(char *)sp->value.i,0);
- else if (sp->storage_class == sc_autoreg)
- *node = makenode(en_autoreg,(char *)sp->value.i,0);
- if (fn)
- goto isfunc;
- }
- break;
- }
- (*node)->cflags = tp->cflags;
- if(!fn && tp && tp->val_flag == 0)
- tp = deref(node,tp);
- if (tp->type == bt_ref) {
- tp = tp->btp;
- tp = deref(node,tp);
- }
-
- }
- lastsym = sp;
- return tp;
- }
-
- void promote_type(TYP *typ, ENODE **node)
- /*
- * Type promotion for casts and function args
- */
- {
- switch (typ->type) {
- 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_long:
- *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;
- default:
- *node = makenode(en_cp,*node,0);
- break;
- }
- (*node)->cflags = typ->cflags;
- }
- TYP *gatherparms( ENODE **node)
- {
- ENODE *ep1 = 0,*ep2=0,**ep3 = &ep1;
- TABLE tbl;
- SYM **t = &tbl.head,*newt;
- TYP *tp;
- int ogc = goodcode;
- tbl.tail = tbl.head = 0;
- goodcode |= DF_FUNCPARMS;
- if (lastst == closepa) {
- if (prm_cplusplus)
- tbl.head=tbl.tail=(SYM *)-1;
- else
- 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;
- 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();
- }
- needpunc(closepa,skm_closepa);
- tp = maketype(bt_func,0);
- tp->btp = &stdint;
- tp->lst = tbl;
- tp->bits = -1;
- tp->startbit = -1;
- tp->uflags = UF_DEFINED | UF_USED;
- goodcode = ogc;
- *node = ep1;
- return tp;
- }
- void checkparmconst(TYP *tp, TYP *tpi)
- {
- if (tpi->type != bt_pointer && tpi->type != bt_ref)
- return;
- 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)))
- generror(ERR_MODCONS,0,0);
- tp = tp->btp;
- tpi = tpi->btp;
- }
- if ((tp->cflags & DF_CONST) && (!tpi || !(tpi->cflags & DF_CONST)))
- generror(ERR_MODCONS,0,0);
- }
- void parmlist(ENODE **node, TYP *tpi, TYP *tp)
- /*
- * parmlist will build a list of parameter expressions in
- * a function call and return a pointer to the last expression
- * parsed. since parameters are generally pushed from right
- * to left we get just what we asked for... parmlist also checks
- * types if there was a prototype and sticks the result type as the
- * first element of the paramter list
- */
- { ENODE *ep1=0,*ep2=0,*ep3=*node;
- SYM *spi=tpi->lst.head,*sp=0;
- TYP *tp2;
- int matching = FALSE;
- if (tp)
- sp=tp->lst.head;
- if (tp && !sp)
- gensymerror(ERR_NOPROTO,tpi->sname);
-
- if (!prm_cplusplus && sp && sp->tp->type != bt_ellipse)
- matching = TRUE;
- while (TRUE) {
- ep2 = ep3->v.p[0];
- ep3 = ep3->v.p[1];
- if (!spi || spi == (SYM *)-1){
- if (sp == (SYM *) -1)
- break;
- if (sp && sp->tp->type != bt_ellipse)
- if (!sp->defalt)
- genfuncerror(ERR_CALLLENSHORT,tpi->sname,0);
- else
- while (sp) {
- if (sp->tp->val_flag && (sp->tp->type == bt_struct || sp->tp->type == bt_union)) {
- ep1 = makenode(en_stackblock,sp->defalt,ep1);
- sp->defalt->size = sp->tp->size;
- }
- else
- ep1 = makenode(en_void,sp->defalt,ep1);
- sp = sp->next;
- }
- break;
- }
- else if (matching) {
- if (!sp || sp == (SYM *)-1) {
- genfuncerror(ERR_CALLLENLONG,tpi->sname,0);
- break;
- }
- else {
- checkparmconst(spi->tp,sp->tp);
- if (!checktype(spi->tp,sp->tp))
- if (isscalar(sp->tp) && isscalar(spi->tp))
- promote_type(sp->tp,&ep2);
- else
- if (sp->tp->type == bt_pointer) {
- if (ep2->nodetype == en_icon) {
- if (ep2->v.i != 0)
- generror(ERR_NONPORT,0,0);
- }
- else if (spi->tp->type != bt_pointer)
- genfuncerror(ERR_CALLMISMATCH,tpi->sname,sp->name);
- }
- else genfuncerror(ERR_CALLMISMATCH,tpi->sname,sp->name);
- }
- }
- if (sp && sp->tp->type == bt_ref) {
- if (lvalue(ep2)) {
- while (castvalue(ep2))
- ep2 = ep2->v.p[0];
- ep2 = ep2->v.p[0];
- }
- else {
- ENODE *x;
- tp2 = sp->tp->btp;
- genfuncerror(ERR_TEMPUSED,tpi->sname,sp->name);
- lc_auto += tp2->size+3;
- lc_auto &= 0xfffffffcL;
- x = makenode(en_autocon,(char *)-lc_auto,0);
- ep2 = makenode(en_refassign,x,ep2);
- }
- }
- spi = spi->next;
- if (sp) {
- sp = sp->next;
- if (sp->tp->type == bt_ellipse)
- matching = FALSE;
- }
- if (sp && sp->tp->val_flag && (sp->tp->type == bt_struct || tp->type == bt_union)) {
- ep1 = makenode(en_stackblock,ep2,ep1);
- ep2->size = tp->size;
- }
- else
- ep1 = makenode(en_void,ep2,ep1);
- }
- if (tp)
- 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_doubleref:
- case en_longdoubleref:
- case en_floatref:
- case en_cld:
- case en_cd:
- case en_cf:
- return 1;
- case en_labcon: case en_nalabcon: case en_trapcall:
- case en_nacon: case en_autocon: case en_autoreg:
- 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_cul:
- case en_cp:
- case en_icon:
- case en_bits:
- case en_ub_ref:
- case en_cub:
- case en_b_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_fcallb:
- case en_callblock:
- return(floatrecurse(node->v.p[1]));
- case en_not: case en_compl:
- case en_uminus:
- case en_ainc: case en_adec:
- 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_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_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_asrsh:
- return(floatrecurse(node->v.p[0]) || floatrecurse(node->v.p[1]));
- case en_void: case en_cond:
- 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_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_struct: case kw_union:
- 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 = search(lastid,&lsyms);
- if (sp && sp->storage_class == sc_type)
- return 1 ;
- return 0;
- }
-
- 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
- * string
- * ( expression )
- * primary[ expression ]
- * primary.id
- * primary->id
- * primary( parameter list )
- * (* expression)( parameter list )
- * (typecast)primary
- * (typecast)(unary)
- */
- { ENODE *pnode, *qnode, *rnode;
- SYM *sp;
- TYP *tptr,*tp1,*tp2;
- int flag = 0;
- int gcode,gdf;
- switch( lastst ) {
- /* This trap thing should be in stmt.c */
- case kw__trap:
- getsym();
- if (needpunc(openpa,0)) {
- long num = intexpr(0);
- if (num > 15 || num < 0)
- generror(ERR_INVTRAP,0,0);
- if (lastst == comma)
- getsym();
- tptr = gatherparms(&pnode);
- parmlist(&pnode,tptr,0);
- pnode = makenode(en_trapcall,makenode(en_icon,(char *)num,0),pnode);
- }
- *node = pnode;
- return &stdint;
-
- #ifdef i386
- case kw__EAX:
- case kw__EDX:
- case kw__ECX:
- case kw__EBX:
- case kw__ESP:
- case kw__EBP:
- case kw__ESI:
- case kw__EDI:
- tptr = xalloc(sizeof(TYP));
- *tptr = stduns;
- tptr->sname = regname;
- pnode = makenode(en_regref,(char *)(1024+lastst-kw__EAX),0);
- pnode = makenode(en_ul_ref,pnode,0);
- *node = pnode;
- getsym();
- return tptr;
- #else
- 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__A0:
- case kw__A1:
- case kw__A2:
- case kw__A3:
- case kw__A4:
- case kw__A5:
- case kw__A6:
- case kw__A7:
- tptr = xalloc(sizeof(TYP));
- *tptr = stduns;
- tptr->sname = regname;
- pnode = makenode(en_regref,(char *)(1024+lastst-kw__D0),0);
- pnode = makenode(en_ul_ref,pnode,0);
- *node = pnode;
- getsym();
- return tptr;
- case kw__FP0:
- case kw__FP1:
- case kw__FP2:
- case kw__FP3:
- case kw__FP4:
- case kw__FP5:
- case kw__FP6:
- case kw__FP7:
- tptr = xalloc(sizeof(TYP));
- *tptr = stdlongdouble;
- tptr->sname = regname;
- pnode = makenode(en_regref,(char *)(2560+lastst-kw__D0),0);
- pnode = makenode(en_longdoubleref,pnode,0);
- *node = pnode;
- getsym();
- return tptr;
- #endif
- case id:
- tptr = nameref(&pnode);
- break;
- case iconst:
- tptr = &stdint;
- pnode = makenode(en_icon,(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 sconst:
- tptr = &stdstring;
- pnode = makenode(en_labcon,(char *)stringlit(laststr),0);
- getsym();
- *node = pnode;
- return tptr;
- case openpa:
- getsym();
- if (lastst == star) {
- gcode = goodcode;
- goodcode &= ~(GF_AND | GF_SUPERAND);
- getsym();
- gdf = globaldref;
- globaldref = 1;
- tptr = expression(&pnode);
- globaldref = gdf;
- goodcode = gcode;
- if (needpunc(closepa, skm_closepa)) {
- if (tptr->type == bt_ptrfunc) {
- if (needpunc(openpa,skm_closepa)) {
- goodcode |= GF_ASSIGN;
- tp1 = gatherparms(&qnode);
- tp1->sname = tptr->sname;
- parmlist(&qnode,tp1,tptr);
- if (tptr->cflags & DF_INT)
- pnode = makenode(en_intcall,pnode,qnode);
- else
- if (tptr->type == bt_union || tptr->type == bt_struct) {
- pnode = makenode(en_fcallb,pnode,qnode);
- pnode->size = tptr->size;
- }
- else
- pnode = makenode(en_fcall,pnode,qnode);
- pnode->cflags = tptr->btp->cflags;
- tptr = tptr->btp;
- break;
- }
- }
- else {
- break;
- }
- }
- goodcode |= GF_ASSIGN;
- *node = pnode;
- return tptr;
- }
- else
- castcont:
- if( !castbegin(lastst) ) {
- gcode = goodcode;
- goodcode &= ~(GF_AND | GF_SUPERAND);
- gdf = globaldref;
- globaldref = 0;
- tptr = expression(&pnode);
- globaldref = gdf;
- goodcode = gcode & ~GF_ASSIGN;
- needpuncexp(closepa,skm_closepa);
- goto contfor;
- }
- else { /* cast operator */
- int flags = 0;
- while (lastst == kw_const || lastst == kw_volatile) {
- if (lastst == kw_const)
- flags |= DF_CONST;
- else
- flags |= DF_VOL;
- getsym();
- }
- declid[0] = 0;
- decl(0,flags); /* do cast declaration */
- decl1();
- tptr = head;
- if (needpunc(closepa, 0)) {
- gcode = goodcode;
- goodcode &= ~(GF_AND | GF_SUPERAND);
- gdf = globaldref;
- globaldref = 0;
- if( (unary(&pnode)) == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- tptr = 0;
- }
- globaldref = gdf;
- goodcode = gcode;
- pnode->cflags = tptr->cflags;
- if (tptr) {
- promote_type(tptr, &pnode);
- }
- }
- else
- return(0);
- }
- *node = pnode;
- return tptr;
- default:
- return 0;
- }
- contfor:
- for(;;) {
- switch( lastst ) {
- case openbr: /* build a subscript reference */
- flag = 1;
- if( tptr->type != bt_pointer )
- generrorexp(ERR_NOPOINTER,0,skm_closebr);
- else
- tptr = tptr->btp;
- getsym();
- qnode = makenode(en_icon,(char *)tptr->size,0);
- gcode = goodcode;
- goodcode &= ~(GF_AND | GF_SUPERAND);
- gdf = globaldref;
- globaldref = 0;
- tp2 = expression(&rnode);
- globaldref = gdf;
- goodcode = gcode & ~GF_ASSIGN;
- 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,qnode,pnode);
- pnode->cflags = tptr->cflags;
- if( tptr->val_flag == 0 )
- tptr = deref(&pnode,tptr);
- needpuncexp(closebr,skm_closebr);
- break;
- case pointsto:
- if( tptr->type != bt_pointer ) {
- generror(ERR_NOPOINTER,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_l_ref,pnode,0);
- pnode->cflags = tptr->cflags;
- }
-
- /*
- * fall through to dot operation
- */
- case dot:
- getsym(); /* past -> or . */
- if( lastst != id )
- generror(ERR_IDEXPECT,0,0);
- else {
- sp = search(nm=litlate(lastid),&tptr->lst);
- if( sp == 0 ) {
- tptr = &stdmatch;
- pnode = makenode(en_nacon,undefname,0);
- gensymerror(ERR_UNDEFINED,nm);
- getsym();
- while (lastst == pointsto || lastst == dot) {
- getsym();
- getsym();
- }
- }
- else {
-
- tp2 = sp->tp;
- if (pnode->nodetype == en_fcallb) {
- lc_auto+=pnode->size+3;
- lc_auto &= 0xfffffffcL;
- qnode = makenode(en_autocon,(char *)-lc_auto,0);
- pnode = makenode(en_callblock,qnode,pnode);
- }
- qnode = makenode(en_icon,(char *)sp->value.i,0);
- pnode = makenode(en_add,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;
- case openpa: /* function reference */
- flag = 1;
- if( tptr->type != bt_func &&
- tptr->type != bt_ifunc && tptr->type != bt_ptrfunc) {
- gensymerrorexp(ERR_NOFUNC,nm);
- expskim(skm_closepa);
- }
- else {
- if (prm_cplusplus && !strcmp(nm,"main"))
- generror(ERR_NOMAIN,0,0);
- sp=gsearch(tptr->sname);
- getsym();
- tp1 =gatherparms(&qnode);
- parmlist(&qnode,tp1,tptr);
- tptr = tptr->btp;
- if (sp->intflag)
- pnode = makenode(en_intcall,pnode,qnode);
- else
- if (tptr->type == bt_union || tptr->type == bt_struct) {
- pnode = makenode(en_fcallb,pnode,qnode);
- pnode->size = tptr->size;
- }
- else
- pnode = makenode(en_fcall,pnode,qnode);
- if (tptr)
- pnode->cflags = tptr->cflags;
- }
- goodcode |= GF_ASSIGN;
- break;
- default:
- goto fini;
- }
- }
- fini: *node = pnode;
- if (!flag && !(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) {
- 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 != asand) {
- gensymerror(ERR_SYMUNDEF,lastsym->name);
- lastsym->tp->uflags |= UF_DEFINED;
- }
- lastsym->tp->uflags &= ~UF_ASSIGNED;
- }
- return tptr;
- }
-
- int castvalue(ENODE *node)
- {
- switch(node->nodetype) {
- case en_cb: case en_cub: case en_bits:
- case en_cw: case en_cuw:
- case en_cl: case en_cul:
- case en_cf: case en_cd: case en_cp: case en_cld:
- return 1;
- }
- return 0;
- }
- int lvalue(ENODE *node)
- /*
- * this function returns true if the node passed is an lvalue.
- * this can be qualified by the fact that an lvalue must have
- * one of the dereference operators as it's top node.
- */
- {
- if (!prm_cplusplus) {
- while (castvalue(node))
- node = node->v.p[0];
- }
- switch( node->nodetype ) {
- 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:
- return 1;
- case en_bits:
- 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
- * primary++
- * primary--
- * !unary
- * ~unary
- * &unary
- * ++unary
- * --unary
- * -unary
- * *unary
- * sizeof(typecast)
- *
- */
- { TYP *tp,*tp1;
- ENODE *ep1, *ep2;
- int flag, i,gdf;
- flag = 0;
- switch( lastst ) {
- case autodec:
- flag = 1;
- /* fall through to common increment */
- case autoinc:
- getsym();
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- if( tp == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- return 0;
- }
- goodcode |= GF_ASSIGN;
- if( lvalue(ep1)) {
- 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(flag ? en_assub : en_asadd,ep1,ep2);
- }
- else {
- generror(ERR_LVALUE,0,0);
- return(0);
- }
- break;
- case minus:
- getsym();
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- goodcode &= ~GF_ASSIGN;
- if( tp == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- return 0;
- }
- ep1 = makenode(en_uminus,ep1,0);
- break;
- case not:
- getsym();
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- goodcode &= ~GF_ASSIGN;
- if( tp == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- return 0;
- }
- ep1 = makenode(en_not,ep1,0);
- break;
- case compl:
- getsym();
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- goodcode &= ~GF_ASSIGN;
- if( tp == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- return 0;
- }
- floatcheck(ep1);
- ep1 = makenode(en_compl,ep1,0);
- break;
- case star:
- getsym();
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- 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);
- break;
- case and:
- getsym();
- if (!(goodcode & GF_INFUNCPARMS))
- goodcode |= GF_AND;
- gdf = globaldref;
- globaldref = 0;
- tp = unary(&ep1);
- globaldref = gdf;
- goodcode &= ~GF_AND;
- goodcode &= ~GF_ASSIGN;
- if( tp == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- return 0;
- }
- else
- if (tp->startbit != -1)
- generror(ERR_BFADDR,0,0);
- else if (tp->cflags & DF_AUTOREG)
- gensymerror(ERR_NOANDREG,tp->sname);
- else if (tp->type == bt_pointer && tp->val_flag && !(goodcode & GF_SUPERAND))
- generror(ERR_SUPERAND,0,0);
-
- if( lvalue(ep1)) {
- ep1 = ep1->v.p[0];
- if (ep1->nodetype == en_regref)
- gensymerror(ERR_NOANDREG,tp->sname);
- }
- tp1 = xalloc(sizeof(TYP));
- tp1->size = 4;
- tp1->type = bt_pointer;
- tp1->btp = tp;
- tp1->val_flag = 0;
- tp1->lst.head = 0;
- tp1->sname = 0;
- tp = tp1;
- break;
- case kw_sizeof:
- getsym();
- needpunc(openpa,0);
- if (castbegin(lastst))
- {
- int flags = 0;
- while (lastst == kw_const || lastst == kw_volatile) {
- if (lastst == kw_const)
- flags |= DF_CONST;
- else
- flags |= DF_VOL;
- getsym();
- }
- decl(0,flags);
- decl1();
- }
- else {
- SYM *sp;
- if (lastst == id) {
- ENODE *node = 0;
- if ((sp = search(nm,&tagtable)) != 0) {
- head = sp->tp;
- getsym();
- }
- else
- head = primary(&node);
- }
- else {
- if (lastst == kw_enum) {
- getsym();
- if (lastst == id) {
- if ((sp = search(nm,&tagtable)) != 0) {
- head = sp->tp;
- getsym();
- goto sizeofnorm;
- }
- }
- }
- generror(ERR_SZTYPE,0,skm_closepa);
- ep1 = makenode(en_icon,(char *) 1, 0);
- tp = &stdint;
- break;
- }
- }
- sizeofnorm:
- if( head != 0 ) {
- ep1 = makenode(en_icon,(char *)head->size,0);
- }
- else {
- generror(ERR_IDEXPECT,0,0);
- ep1 = makenode(en_icon,(char *)1,0);
- }
- goodcode &= ~GF_ASSIGN;
- tp = &stdint;
- needpunc(closepa,0);
- break;
- default:
- tp = primary(&ep1);
- if( tp != 0 ) {
- if( tp->type == bt_pointer )
- i = tp->btp->size;
- else
- i = 1;
- if( lastst == autoinc) {
- if (i == 0)
- generror(ERR_ZEROPTR,0,0);
- if( lvalue(ep1) ) {
- if (ep1->cflags & DF_CONST)
- generror(ERR_MODCONS,0,0);
- ep1 = makenode(en_ainc,ep1,(char *)i);
- goodcode |= GF_ASSIGN;
- }
- else
- generror(ERR_LVALUE,0,0);
- getsym();
- }
- else if( lastst == autodec ) {
- if (i == 0)
- generror(ERR_ZEROPTR,0,0);
- if( lvalue(ep1) ) {
- if (ep1->cflags & DF_CONST)
- generror(ERR_MODCONS,0,0);
- ep1 = makenode(en_adec,ep1,(char *)i);
- goodcode |= GF_ASSIGN;
- }
- else
- generror(ERR_LVALUE,0,0);
- getsym();
- }
- }
- break;
- }
- if (globaldref) {
- globaldref = 0;
- if (tp->type != bt_ptrfunc) {
- 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;
- }
- TYP *maxsize(TYP *tp1, TYP *tp2)
- {
- if (tp1->type > tp2->type)
- return tp1;
- return tp2;
- }
- TYP *forcefit(ENODE **node1,TYP *tp1,ENODE **node2,TYP *tp2, int max)
- /*
- * forcefit will coerce the nodes passed into compatable
- * types and return the type of the resulting expression.
- */
- { int error = ERR_MISMATCH;
- TYP *tp3;
- switch( tp1->type ) {
- case bt_long:
- if ((*node1)->nodetype == en_icon) {
- if (isscalar(tp2) || (!prm_cplusplus && tp2->type == bt_pointer))
- return tp2;
- if (tp2->type != bt_matchall)
- break;
- }
- case bt_matchall:
- if( tp2->type == bt_matchall)
- return(&stdint);
- else if( tp2->type == bt_pointer)
- return tp2;
- 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_pointer)
- return tp1;
- if (!prm_cplusplus && isscalar(tp2))
- if (max)
- return(maxsize(tp1,tp2));
- else
- return(tp1);
- break;
- case bt_unsignedshort:
- case bt_short:
- if ((*node2)->nodetype == en_icon) {
- if (!max && ((*node2)->v.i < -65536L || ((*node2)->v.i > 65535L))) {
- error = ERR_LOSTCONV;
- break;
- }
- return tp1;
- }
- else
- if (!max && (tp2->type == bt_long || tp2->type == bt_unsigned || (!prm_cplusplus && tp2->type == bt_pointer))) {
- error = ERR_LOSTCONV;
- break;
- }
- if (isscalar(tp2))
- if (max)
- return(maxsize(tp1,tp2));
- else
- return(tp1);
- break;
- case bt_char:
- case bt_unsignedchar:
- if ((*node2)->nodetype == en_icon) {
- if (!max && ((*node2)->v.i < -256 || ((*node2)->v.i > 255))) {
- error = ERR_LOSTCONV;
- break;
- }
- return tp1;
- }
- 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 (isscalar(tp2))
- if (max)
- return(maxsize(tp1,tp2));
- else
- return(tp1);
- break;
- case bt_float:
- case bt_double:
- case bt_longdouble:
- if (isscalar(tp2))
- return(tp1);
- break;
- case bt_unsigned:
- if ((*node1)->nodetype == en_icon) {
- if (isscalar(tp2) || (!prm_cplusplus && tp2->type == bt_pointer))
- return tp2;
- break;
- }
- if( !prm_cplusplus && tp2->type == bt_pointer )
- return tp2;
- if (isscalar(tp2))
- return(tp1);
- break;
- case bt_ptrfunc:
- if (!prm_cplusplus && (tp2->type == bt_short || tp2->type == bt_unsignedshort
- || tp2->type == bt_char || tp2->type == bt_unsignedchar)) {
- error = ERR_SHORTPOINTER;
- break;
- }
- if (tp2->type == bt_pointer)
- tp3 = tp2->btp;
- else
- tp3 = tp2;
- if (tp3->type == bt_func || tp3->type == bt_ifunc || tp3->type == bt_ptrfunc
- || (!prm_cplusplus && tp2->type == bt_pointer))
- return(tp1);
- break;
- case bt_func:
- case bt_ifunc:
- if (tp2->type == bt_func || tp2->type == bt_ifunc)
- return tp1;
- break;
- }
- if (error == ERR_MISMATCH && prm_cplusplus)
- genmismatcherror(tp2,tp1);
- else
- generror( error,0,0 );
- return tp1;
- }
-
- int isscalar(TYP *tp)
- /*
- * this function returns true when the type of the argument is
- * one of char, short, unsigned, or long. Also float or double
- * ( so much for scalar! )
- */
- { return tp->type == bt_char || 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_float || tp->type == bt_double || tp->type == bt_longdouble;
- }
- void checknp(TYP *tp1,TYP*tp2,ENODE *ep1, ENODE *ep2)
- {
-
- if (prm_cplusplus)
- return;
- if (tp1->type == bt_pointer || tp2->type == bt_pointer)
- if (tp1->type != tp2->type)
- if ((ep1->nodetype != en_icon || ep1->v.i != 0) && (ep2->nodetype != en_icon || ep2->v.i != 0))
- generror(ERR_NONPORT,0,0);
- }
- 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;
- }
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE);
- switch( oper ) {
- case star:
- if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- ep1 = makenode(en_umul,ep1,ep2);
- else
- ep1 = makenode(en_mul,ep1,ep2);
- break;
- case divide:
- if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- ep1 = makenode(en_udiv,ep1,ep2);
- else
- ep1 = makenode(en_div,ep1,ep2);
- break;
- case modop:
- if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- ep1 = makenode(en_umod,ep1,ep2);
- else
- ep1 = makenode(en_mod,ep1,ep2);
- floatcheck(ep1);
- break;
- }
- }
- *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 == plus);
- getsym();
- tp2 = multops(&ep2);
- goodcode &= ~GF_ASSIGN;
- if( tp2 == 0 ) {
- generror(ERR_IDEXPECT,0,0);
- *node = ep1;
- return tp1;
- }
- if( tp1->type == bt_pointer ) {
- if (tp2->type == bt_pointer) {
- forcefit(&ep1,tp1,&ep2,tp2,TRUE);
- ep1 = makenode( oper ? en_add : en_sub,ep1,ep2);
- ep1->cflags = ep1->v.p[0]->cflags | ep2->cflags;
- if (!checktypeassign(tp1,tp2))
- generror(ERR_MISMATCH,0,0);
- else
- 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;
- goto exit;
- }
- else {
- tp2 = forcefit(0,&stdint,&ep2,tp2,TRUE);
- 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,&stdint,&ep1,tp1,TRUE);
- 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);
- ep1 = makenode( oper ? 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);
- if (tp1->type == bt_unsigned ||
- tp1->type == bt_unsignedchar ||
- tp1->type == bt_unsignedshort)
- 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(;;) {
- switch( lastst ) {
-
- case lt:
- if( tp1->type == bt_unsigned || tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- nt = en_ult;
- else
- nt = en_lt;
- break;
- case gt:
- if( tp1->type == bt_unsigned || tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- nt = en_ugt;
- else
- nt = en_gt;
- break;
- case leq:
- if( tp1->type == bt_unsigned || tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- nt = en_ule;
- else
- nt = en_le;
- break;
- case geq:
- if( tp1->type == bt_unsigned || tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- nt = en_uge;
- else
- nt = en_ge;
- break;
- default:
- goto fini;
- }
- getsym();
- tp2 = shiftop(&ep2);
- goodcode &= ~GF_ASSIGN;
- if( tp2 == 0 )
- generror(ERR_IDEXPECT,0,0);
- else {
- checknp(tp1,tp2,ep1,ep2);
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE);
- 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 == eq);
- getsym();
- tp2 = relation(&ep2);
- goodcode &= ~GF_ASSIGN;
- checknp(tp1,tp2,ep1,ep2);
- if( tp2 == 0 )
- generror(ERR_IDEXPECT,0,0);
- else {
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE);
- ep1 = makenode( oper ? 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 {
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,TRUE);
- ep1 = makenode(nt,ep1,ep2);
- }
- 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;
- ENODE *ep1, *ep2, *ep3;
- tp1 = orop(&ep1); /* get condition */
- if( tp1 == 0 )
- return 0;
- if( lastst == hook ) {
- getsym();
- if( (tp2 = conditional(&ep2)) == 0) {
- generror(ERR_IDEXPECT,0,0);
- goodcode &= ~GF_ASSIGN;
- goto cexit;
- }
- needpunc(colon,0);
- if( (tp3 = conditional(&ep3)) == 0) {
- generror(ERR_IDEXPECT,0,0);
- goodcode &= ~GF_ASSIGN;
- goto cexit;
- }
- goodcode &= ~GF_ASSIGN;
- tp1 = forcefit(&ep2,tp2,&ep3,tp3,TRUE);
- ep2 = makenode(en_void,ep2,ep3);
- ep1 = makenode(en_cond,ep1,ep2);
- }
- cexit: *node = ep1;
- return tp1;
- }
- TYP *autoasnop(ENODE **node, SYM *sp)
- /*
- * Handle assignment operators during auto init of local vars
- */
- { ENODE *ep1, *ep2;
- TYP *tp1, *tp2;
-
- if( (tp1 = sp->tp) == 0 ) {
- tp1 = &stdmatch;
- *node = makenode(en_nacon,undefname,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,(char *)sp->value.i,0);
- else if (sp->storage_class == sc_autoreg)
- ep1 = makenode(en_autoreg,(char *)sp->value.i,0);
- if (tp1) {
- tp1->uflags |= UF_DEFINED | UF_USED;
- }
- if ((tp1->uflags & UF_CANASSIGN) && !(goodcode & GF_INLOOP))
- tp1->uflags |= UF_ASSIGNED;
- if( tp1->val_flag == 0)
- tp1 = deref(&ep1,tp1);
- if( tp1 == 0 )
- return 0;
- tp2 = asnop(&ep2,tp1);
- if( tp2 == 0)
- generror(ERR_LVALUE,0,0);
- else {
- if (!lvalue(ep1)) {
- if (!checktypeassign(tp1,tp2))
- generror(ERR_LVALUE,0,0);
- else {
- checknp(tp1,tp2,ep1,ep2);
- if (ep2->nodetype == en_fcallb)
- ep1 = makenode(en_callblock,ep1,ep2);
- else
- ep1 = makenode(en_moveblock,ep1,ep2);
- ep1->size = tp1->size;
- *node = ep1;
- }
- }
- else {
- if (tp1->type == bt_ref) {
- if (lvalue(ep2)) {
- while (castvalue(ep2))
- ep2 = ep2->v.p[0];
- ep2 = ep2->v.p[0];
- tp1 = tp1->btp;
- }
- else {
- ENODE *x;
- int q = (tp1->size+3) & 0xfffffffcL;
- tp1 = tp1->btp;
- gensymerror(ERR_TEMPINIT,sp->name);
- lc_auto += q;
- x = makenode(en_autocon,(char *)(sp->value.i-q),0);
- ep2 = makenode(en_refassign,x,ep2);
- }
- }
- checknp(tp1,tp2,ep1,ep2);
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,FALSE);
- *node = makenode(en_assign,ep1,ep2);
- }
- }
- return(tp1);
- }
- void asncombine(ENODE **node)
- {
- ENODE *var = (*node)->v.p[0];
- ENODE *exp = (*node)->v.p[1];
- ENODE *var2 = exp->v.p[0];
- if (equalnode(var,var2)) {
- int op = 0;
- switch(exp->nodetype) {
- case en_add:
- op = en_asadd;
- break;
- case en_sub:
- op = en_assub;
- break;
- case en_mul:
- op = en_asmul;
- break;
- case en_umul:
- op = en_asumul;
- break;
- case en_div:
- op = en_asdiv;
- break;
- case en_udiv:
- op = en_asudiv;
- break;
- case en_mod:
- op = en_asmod;
- break;
- case en_umod:
- op = en_asumod;
- break;
- case en_lsh:
- op = en_aslsh;
- break;
- case en_alsh:
- op = en_asalsh;
- break;
- case en_rsh:
- op = en_asrsh;
- break;
- case en_arsh:
- op = en_asarsh;
- break;
- case en_and:
- op = en_asand;
- break;
- case en_or:
- op = en_asor;
- break;
- default:
- return;
- }
- exp->nodetype = op;
- (*node) = exp;
- }
- }
- 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);
- if (!tptr)
- asntyp = tp1;
- if( tp1 == 0 )
- return 0;
- for(;;) {
- switch( lastst ) {
- case assign:
- op = en_assign;
- ascomm: getsym();
- tp2 = asnop(&ep2,asntyp);
- ascomm2: ep3 = ep1;
- if (tp1) {
- tp1->uflags |= UF_DEFINED;
- }
- goodcode |= GF_ASSIGN;
- if ((tp1->uflags & UF_CANASSIGN) && !(goodcode & GF_INLOOP))
- tp1->uflags |= UF_ASSIGNED;
- if( tp2 == 0 || tp1 == 0)
- generror(ERR_LVALUE,0,0);
- else {
- if (!lvalue(ep1)) {
- if (!checktypeassign(tp1,tp2)) {
- generror(ERR_LVALUE,0,0);
- }
- else {
- if (op != en_asadd && op != en_assub)
- checknp(tp1,tp2,ep1,ep2);
- if (ep2->nodetype == en_fcallb)
- ep1 = makenode(en_callblock,ep1,ep2);
- else
- ep1 = makenode(en_moveblock,ep1,ep2);
- ep1->size = tp1->size;
- }
- }
- else {
- if (op != en_asadd && op != en_assub)
- checknp(tp1,tp2,ep1,ep2);
- tp1 = forcefit(&ep1,tp1,&ep2,tp2,FALSE);
- ep1 = makenode(op,ep1,ep2);
- }
- }
- if (ep3->cflags & DF_CONST)
- generror(ERR_MODCONS,0,0);
- if (op == en_assign)
- asncombine(&ep1);
- else 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)
- 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)
- op = en_asumul;
- else
- op =en_asmul;
- goto ascomm;
- case asdivide:
- if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- op = en_asudiv;
- else
- op =en_asdiv;
- goto ascomm;
- case asmodop:
- if( tp1->type == bt_unsigned ||tp1->type == bt_unsignedchar || tp1->type == bt_unsignedshort)
- op = en_asumod;
- else
- op =en_asmod;
- goto ascomm;
- case aslshift:
- if (tp1->type == bt_unsigned ||
- tp1->type == bt_unsignedchar ||
- tp1->type == bt_unsignedshort)
- op = en_aslsh;
- else
- op = en_asalsh;
- goto ascomm;
- case asrshift:
- if (tp1->type == bt_unsigned ||
- tp1->type == bt_unsignedchar ||
- tp1->type == bt_unsignedshort)
- op = en_asrsh;
- else
- op = en_asarsh;
- goto ascomm;
- case asand:
- op = en_asand;
- goto ascomm;
- case asor:
- op = en_asor;
- 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.
- */
- { TYP *tp;
- tp = asnop(node,0);
- if( tp == 0 )
- *node = 0;
- else if ((*node)->nodetype == en_fcallb) {
- ENODE *ep1;
- lc_auto+=tp->size+3;
- lc_auto &= 0xfffffffcL;
- ep1 = makenode(en_autocon,(char *)-lc_auto,0);
- (*node) = makenode(en_callblock,ep1,(*node));
- }
- return tp;
- }
-
- TYP *commaop(ENODE **node)
- /*
- * evaluate the comma operator. comma operators are kept as
- * void nodes.
- */
- { TYP *tp1;
- ENODE *ep1, *ep2;
- tp1 = asnop(&ep1,0);
- if( tp1 == 0 )
- return 0;
- if( lastst == comma ) {
- getsym();
- tp1 = commaop(&ep2);
- goodcode &= ~GF_ASSIGN;
- 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)
- /*
- * evaluate an expression where all operators are legal.
- */
- { TYP *tp;
- tp = commaop(node);
- if( tp == 0 )
- *node = 0;
- else if ((*node)->nodetype == en_fcallb) {
- ENODE *ep1;
- lc_auto+=tp->size+3;
- lc_auto &= 0xfffffffcL;
- ep1 = makenode(en_autocon,(char *)-lc_auto,0);
- (*node) = makenode(en_callblock,ep1,(*node));
- }
- return tp;
- }