/* File: eval.c * * Contains: eval, dofunc, setmth * * This is the entry point and heart of the expression evaluator. * Entry into the module is that 'pnt1' point to the front of the * expression, and 'pnt2' point to the back of the expression. */ #include "asm.h" extern int prtyes; static EVAL arstk[100]; /* argument stack */ static unsigned char fstk[20]; /* function stack */ static int arcnt = 0; /* argument pointer */ static unsigned char ebflag; /* evaluator flag 1 */ static unsigned char edflag; /* evaluator flag 2 */ static unsigned char efunc; /* function save */ static unsigned char fcnt; /* function counter */ static unsigned char evlast; /*. ************************************************************************* * * * eval * * ---- * * * * * * * * * ************************************************************************* */ void eval(epoint) register unsigned char *epoint; { register unsigned char *cptr; #if DEBUG if (passno == 2) printf("eval: evaluate *%s*\n",epoint); #endif arcnt = 0; evalue = 0; ebflag = 0; edflag = 0; evlast = 0; fcnt = 0; for(;;) { epoint = skipsp(epoint); cptr = epoint; #if DEBUG if (passno == 2) printf("eval:*%s*\n",epoint); if (passno == 2) printf("eval: errbuf=*%c*\n",errbuf[0]); #endif if (digit(cptr)) { #if DEBUG printf("eval: digit\n"); #endif epoint = plit(epoint); pushon(evalue); evlast = 1; } else if (epoint[0] == LOCAL && epoint[1] == LOCAL) { #if DEBUG printf("eval: local label\n"); #endif epoint = plocal(epoint); pushon(evalue); evlast = 1; } else if (*cptr != '$' && alpha(cptr)) { #if DEBUG printf("eval: symbol\n"); #endif epoint = psymb(epoint); pushon(evalue); evlast = 1; } else if (*cptr == MLOCAL) { #if DEBUG printf("eval: macro label\n"); #endif epoint = pmlocal(epoint); pushon(evalue); evlast = 1; } else if (*cptr == '$') { if (alpha(epoint + 1)) { #if DEBUG printf("eval: symbol\n"); #endif epoint = psymb(epoint); pushon(evalue); evlast = 1; } else { #if DEBUG printf("current location: %x\n",adrefc[mode]); #endif edflag = 0; if (is_off(AFASEG)) { #if DEBUG > 1 printf("eval: $ - RLREL set because AFASEG is off\n"); printf("eval: aflags = %lx\n",aflags); #endif edflag |= RLREL; } ++epoint; pushon(adrefc[mode]); evlast = 1; } } else if (*cptr == '.') { #if DEBUG printf("multi function\n"); #endif epoint = pmcf(++epoint); dofunc(); } else if (*cptr == SQUOTE) { #if DEBUG printf("single quote\n"); #endif epoint = pasc(++epoint); pushon(evalue); evlast = 1; } else if (*cptr == LPAREN) { #if DEBUG printf("left paren\n"); #endif ++epoint; pufu(LBTOK); evlast = 0; } else if (*cptr == RPAREN) { #if DEBUG printf("right paren\n"); #endif ++epoint; for(;;) { if (pofu() == ERR) break; if (efunc == LBTOK) break; func(efunc); } evlast = 1; } else { if ((*cptr < ' ' && *cptr != HT) || *cptr == ',' || *cptr == ';' || *cptr == '%') { #if DEBUG > 1 if (passno == 2) printf("eval: break with *%x*\n",*cptr); if (passno == 2) printf("eval: cptr <= ' ' %d\n",(*cptr <= ' ')); if (passno == 2) printf("eval: cptr == ',' %d\n",(*cptr == ',')); if (passno == 2) printf("eval: cptr == ';' %d\n",(*cptr == ';')); if (passno == 2) printf("eval: cptr == '%%' %d\n",(*cptr == '%')); if (passno == 2) printf("eval: errbuf=*%c*\n",errbuf[0]); #endif break; } epoint = pscf(epoint); dofunc(); continue; } } #if DEBUG printf("pop and do functions\n"); #endif while(pofu() != ERR) { if (efunc == LBTOK) eror('B'); else func(efunc); } popoff(); if (arcnt != 0) { #if DEBUG > 1 printf("eval: 'S' arcnt(%d) != 0\n",arcnt); #endif eror('S'); } if (ebflag & EVOVFL) eror('A'); if (ebflag & EVVALU) { #if DEBUG > 1 printf("eval: EVVALU set\n"); #endif eror('r'); } setmth(); #if DEBUG printf("evaluator value: %x\n", evalue); printf("eval: error = *%c*\n",errbuf[0]); #endif evalue &= (unsigned) 0xffff; } /*. ************************************************************************* * * * dofunc * * ------ * * * * do a function * * * * * * * ************************************************************************* */ void dofunc() { unsigned char token; #if DEBUG printf("dofunc\n"); #endif token = efunc; if (token == PLUTOK && evlast) token = DIPTOK; else if (token == MINTOK && evlast) token = DIMTOK; else if (token == EXPTOK && evlast) { #if DEBUG printf("dofunc: 'S' token == EXPTOK and evlast is non zero\n"); #endif eror('S'); return; } for(;;) { if (pofu() == ERR) { if (*errbuf == 'O') errbuf[0] = SPACE; pufu(token); evlast = 0; return; } if ((token & 7) <= (efunc & 7)) func(efunc); else { pufu(efunc); pufu(token); evlast = 0; return; } } } /*. ************************************************************************* * * * setmth * * ------ * * * * set the math flags according to what happened in eval * * * * * * * ************************************************************************* */ void setmth() { #if DEBUG printf("setmth\n"); #endif if (edflag & RLEXT) mathfg |= MFEXT; else if (edflag & RLREL) mathfg |= MFSYRL; if(edflag & RLDSEG) mathfg |= MFDSEG; if (edflag & RLHIGH || edflag & RLLOW) hilow |= (edflag & RLHIGH) ? O4MSB : O4LSB; } /*. ************************************************************************* * * * pasc * * ---- * * * * This routine handles the single and double character * * quoted strings used in LD instructions and DEFB/W instructions. * * * * * * * ************************************************************************* */ unsigned char *pasc(pnt1) register unsigned char *pnt1; { unsigned char c; #if DEBUG printf("pasc\n"); #endif evalue = 0; edflag = 0; if (*pnt1 == SQUOTE && *(pnt1 + 1) == SQUOTE) { evalue = SQUOTE; pnt1 += 2; } if (*pnt1 == SQUOTE) return(++pnt1); c = *pnt1++; if (*pnt1 == SQUOTE) { evalue = c; return(++pnt1); } evalue = (c << 8) + *pnt1++; if (*pnt1 != SQUOTE) dnops(); else ++pnt1; return(pnt1); } /* * These are the value parsers for the expression evaluator. */ static unsigned char *pntx; /*. ************************************************************************* * * * plit * * ---- * * * * * * * * * ************************************************************************* */ unsigned char *plit(pnt) register unsigned char *pnt; { register unsigned char *pnt1; #if DEBUG printf("plit: %s\n", pnt); #endif edflag = 0; ebflag = 0; pntx = pnt; pnt1 = pnt; while(hexdg(*pnt1)) ++pnt1; --pnt1; switch(*pnt1) { case 'h': case 'H': return(math(16)); case 'b': return(math(1)); case 'o': case 'O': case 'q': case 'Q': return(math(8)); case 'd': return(math(10)); } if (plchg) return(math(radix)); switch(*pnt1) { case 'B': return(math(1)); case 'D': return(math(10)); default: return(math(radix)); } } /*. ************************************************************************* * * * hexdg * * * * * * * * * ************************************************************************* */ /* determine if valid hex xdigit */ int hexdg(p) unsigned char p; { if (xdigit(p, 16) != ERR) return(1); p = (p >= 'A' && p <= 'Z') ? p + ' ' : p; if (p == 'h' || p == 'o' || p == 'q') return(1); return(0); } /*. ************************************************************************* * * * math * * ---- * * * * math portion of literals * * * * * * * ************************************************************************* */ unsigned char *math(base) unsigned char base; { unsigned char max, add; int c; #if DEBUG printf("math\n"); #endif max = (base == 1) ? base : base - 1; add = (base == 1) ? base + 1 : base; evalue = 0; edflag = 0; ebflag = 0; while((c = xdigit(*pntx++, base)) >= 0) { if (c > max) { #if DEBUG printf("math:digit excessed radix\n"); #endif eror('r'); return(pntx); } evalue = (evalue * add) + c; } c = *--pntx; if (radix == 16) if ((c == 'd') || (c == 'b')) return(++pntx); c = ((c >= 'A') && (c <= 'Z')) ? c + ' ' : c; if ((c == 'b') || (c == 'd') || (c == 'h') || (c == 'o') || (c == 'q')) ++pntx; return(pntx); } /*. ************************************************************************* * * * xdigit * * ------ * * * * return binary value for supplied radix * * * * * * * ************************************************************************* */ int xdigit(c, r) unsigned char c, r; { if (r == 16) { c = (c >= 'A' && c <= 'Z') ? c + ' ' : c; if (c >= 'a' && c <= 'f') return (c - 'a' + 10); } if (c >= '0' && c <= '9') return (c - '0'); return (ERR); } /* * This is the symbol lookup routine for the expression evaluator. */ extern unsigned char nargs; extern unsigned char nmac; static unsigned char local; /*. ************************************************************************* * * * psymb * * ----- * * * * * * * * * ************************************************************************* */ unsigned char *psymb(pnt) register unsigned char *pnt; { #if DEBUG if (passno == 2) printf("psymb: %s\n", pnt); #endif local = 0; edflag = 0; pnt = gsym(pnt, symbuf); prosym(symbuf); return(pnt); } /*. ************************************************************************* * * * plocal * * ------ * * * * * * * * * ************************************************************************* */ unsigned char *plocal(pnt) register unsigned char *pnt; { int x; unsigned char buff[MAXLTH]; local = 1; edflag = 0; if (pnt[0] == LOCAL && pnt[1] == LOCAL) pnt += 2; pnt = gsym(pnt, symbuf); (void) sprintf(buff, "%u", locnum); x = slenth - len(buff); symbuf[x] = 0; (void) strcat(symbuf,buff); prosym(symbuf); return(pnt); } /*. ************************************************************************* * * * pmlocal * * ------- * * * * * * * * * ************************************************************************* */ unsigned char *pmlocal(pnt) register unsigned char *pnt; { unsigned char buff[MAXLTH]; int x; local = 1; edflag = 0; if (pnt[0] == MLOCAL) ++pnt; pnt = gsym(pnt, symbuf); (void) sprintf(buff, "%u", mlocnum); x = slenth - len(buff); symbuf[x] = 0; (void) strcat(symbuf,buff); prosym(symbuf); return(pnt); } /*. ************************************************************************* * * * prosym * * * * * * * * * ************************************************************************* */ void prosym(sptr) register unsigned char *sptr; { register SYM *fp; #if DEBUG print("prosym: lookup *%s*\n",sptr); #endif if (ortkbf[0] == CONDTK) { if (ortkbf[1] == IFDEF || ortkbf[1] == IFNDEF) { if (fp = loc_symbol(sptr)) { fp->s_flag2 &= ~PNOREF; evalue = 1; if (passno == 1 && !refflg && print_con) reff_symbol(fp,0); } else evalue = 0; return; } } if (match(sptr, "narg", 1)) { if (ortkbf[0] == CONDTK) ortkbf[1] = SPECIALIF; evalue = nargs & 0xff; return; } if ((fp = loc_symbol(sptr)) == 0) { #if DEBUG if (passno == 2) printf("prosym:can't find *%s*\n",sptr); #endif eror('U'); evalue = 0; return; } if ((fp->s_flag1 & SYMUDF) && ((fp->s_flag1 & SYMEXT) == 0)) { eror('U'); evalue = 0; return; } if (fp->s_flag1 & SYMSEC) turn_on(AFUSPR); fp->s_flag2 &= ~PNOREF; psave = fp->s_psect; evalue = fp->s_value; if (fp->s_flag2 & SYDSEG) { edflag |= RLEXT; (void) movbuf(sptr, o4extb, slenth, -1); evalue = 0; turn_on(AFDSEG); edflag |= RLDSEG; goto done; } if (psave != pdef) { evalue = 0; if (!(fp->s_flag1 & SYMEXT)) { #if DEBUG printf("prosym:SYMEXT not set\n"); #endif eror('U'); return; } } if (fp->s_flag1 & SYMREL && is_off(AFASEG)) { #if DEBUG printf("prosym: RLREL set because of SYMREL set in s_flag1 and\n"); printf(" AFASEG is off\n"); #endif edflag |= RLREL; } if (fp->s_flag1 & SYMEXT) { #if DEBUG printf("prosym: RLREL and RLEXT set because SYMEXT set in s_flag1\n"); #endif edflag |= RLEXT; (void) movbuf(sptr, o4extb, slenth, -1); } done: lglob = fp->s_flag1; if ((local == 0 || prtyes) && !false_condit) { if (ortkbf[0] == CONDTK) { if (print_con) reff_symbol(fp,0); } else reff_symbol(fp,0); } } /* * These routines will push/pop functions or values off the * function or arithmetic stack for the various handlers in * the expression evaluator. */ /*. ************************************************************************* * * * pufu * * ---- * * * * push a function onto the function stack * * * * * * * ************************************************************************* */ void pufu(token) unsigned char token; { #if DEBUG printf("pufu: %x\n", token); #endif if (fcnt >= MAXFSK) { eror('O'); return; } fstk[fcnt++] = token; } /*. ************************************************************************* * * * pofu * * ---- * * * * pop a function from the function stack * * * * * * * ************************************************************************* */ int pofu() { if (!fcnt) return(ERR); efunc = fstk[--fcnt]; fstk[fcnt] = 0; #if DEBUG printf("pofu: %x\n", efunc); #endif return(0); } /*. ************************************************************************* * * * pushon * * ------ * * * * push an argument onto the arithmetic stack * * * * * * * ************************************************************************* */ void pushon(value) short value; { register EVAL *sp; #if DEBUG printf("pushon: %x\n", value); #endif sp = &arstk[arcnt++]; sp->e_value = value; sp->e_relo = edflag; } /*. ************************************************************************* * * * popoff * * * * pop an argument off the arithmetic stack * * * * * * * ************************************************************************* */ void popoff() { register EVAL *sp; if (arcnt == 0) { eror('O'); return; } sp = &arstk[--arcnt]; evalue = sp->e_value; edflag = sp->e_relo; #if DEBUG if (edflag) printf("popoff: edflag=%d\n",edflag); printf("popoff: %x\n", evalue); #endif } /* * These are the function handlers for the expression evaluator. */ /*. ************************************************************************* * * * func * * * * lookup a function and perform it * * * * * * * ************************************************************************* */ void func(token) unsigned char token; { #if DEBUG printf("func: %x\n", token); #endif if (!fcnt) parflg = 0; if (token == RESTOK) ebflag &= ~EVOVFL; else if (token < MINTOK) one_value(token,0); else if (token < DIPTOK) one_value(token,1); else if (token < ASKTOK) two_values(token,0); else if (token < EQTOK) two_values(token,1); else if (token < LBTOK) two_values(token,2); else dnops(); } /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ void one_value(token,flag) unsigned char token; register int flag; { short short1; unsigned short unshort1; register EVAL *ep; /* * pop one short arithmetic stack */ if (arcnt < 1) { eror('O'); return; } ep = &arstk[arcnt - 1]; unshort1 = ep->e_value; if (flag == 1) if (ep->e_relo) ebflag |= EVVALU; if (token == MINTOK) ep->e_value = 0 - ep->e_value; else if (token == NOTTOK) ep->e_value ^= -1; else if (token == HGHTOK) { if (ep->e_relo & RLREL || ep->e_relo & RLEXT) ep->e_relo |= RLHIGH; hladdr = ep->e_value; ep->e_value = (ep->e_value >> 8) & BYTMSK; } else if (token == LOWTOK) { if (ep->e_relo & RLREL || ep->e_relo & RLEXT) ep->e_relo |= RLLOW; hladdr = ep->e_value; ep->e_value &= BYTMSK; } else if (token == ABSTOK) ep->e_value = (unshort1 >= 0x8000) ? -unshort1 : unshort1; else if (token == SGNTOK) { if (unshort1 >= 0x8000) ep->e_value = -1; else if (unshort1 == 0) ep->e_value = 0; else ep->e_value = 1; } else if (token == BITTOK) { if (ep->e_value < 0) ep->e_value = ~ep->e_value; if (ep->e_value >= 8) { eror('r'); return; } short1 = 1 << ep->e_value; ep->e_value = short1; } } /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ void two_values(token,flag) unsigned char token; register int flag; { short short1, short3; unsigned short unshort1, unshort2; long long1; unsigned char relo_flag1; register EVAL *ep; /* * pop two shorts arithmetic stack */ if (arcnt < 2) { eror('O'); return; } ep = &arstk[--arcnt]; short1 = ep->e_value; relo_flag1 = ep->e_relo; ep--; if (flag == 1) { if (relo_flag1 || ep->e_relo) ebflag |= EVVALU; } else if (flag == 2) { if (relsam(relo_flag1,ep->e_relo) == 0) ebflag |= EVVALU; } if (token == DIPTOK) { if (relo_flag1 || ep->e_relo) { if (relo_flag1) { if (ep->e_relo) ebflag |= EVVALU; else ep->e_relo = relo_flag1; } } long1 = (short1 + ep->e_value) & 0xffffL; ep->e_value = (short) long1; } else if (token == DIMTOK) { if (ep->e_relo) { if (ep->e_relo ==0) ep->e_relo = relo_flag1; else if (relo_flag1 == 0) ; else { relmat(relo_flag1, ep->e_relo); ep->e_relo = 0; } } ep->e_value -= short1; } else if (token == SHRTOK) ep->e_value = ep->e_value >> short1; else if (token == SHLTOK) ep->e_value = ep->e_value << short1; else if (token == ANDTOK) ep->e_value &= short1; else if (token == ORTOK) ep->e_value |= short1; else if (token == XORTOK) ep->e_value ^= short1; else if (token == EQTOK) ep->e_value = (short1 == ep->e_value) ? -1 : 0; else if (token == RRTOK) { while(short1--) { short3 = ep->e_value & 1; ep->e_value = (ep->e_value & 0xffffL) >> 1; if (short3) ep->e_value += 0x8000; } } else if (token == RLTOK) { long1 = (long) ep->e_value; while(short1--) { long1 = (long1 & 0xffffL) << 1; if (long1 > 0xffffL) long1 -= 0xffffL; } ep->e_value = (short) long1; } else if (token == GTTOK) ep->e_value = (ep->e_value > short1) ? -1 : 0; else if (token == GETOK) ep->e_value = (ep->e_value >= short1) ? -1 : 0; else if (token == LTTOK) ep->e_value = (ep->e_value < short1) ? -1 : 0; else if (token == LETOK) ep->e_value = (ep->e_value <= short1) ? -1 : 0; else if (token == UGTTOK) { unshort1 = short1; unshort2 = ep->e_value; ep->e_value = (unshort2 > unshort1) ? -1 : 0; } else if (token == UGETOK) { unshort1 = short1; unshort2 = ep->e_value; ep->e_value = (unshort2 >= unshort1) ? -1 : 0; } else if (token == ULTTOK) { unshort1 = short1; unshort2 = ep->e_value; ep->e_value = (unshort2 < unshort1) ? -1 : 0; } else if (token == ULETOK) { unshort1 = short1; unshort2 = ep->e_value; ep->e_value = (unshort2 <= unshort1) ? -1 : 0; } else if (token == EXPTOK) { if (short1 == 0) { ep->e_value = 1; return; } if (short1 < 0) { ep->e_value = 0; return; } while(--short1) two_values(ASKTOK,0); } else if (token == ASKTOK) { long1 = short1 * ep->e_value; if (long1 > 0xffffL) ebflag |= EVOVFL; ep->e_value = (short) long1; } else if (token == DIVTOK) { if (short1 == 0) { eror('Z'); ep->e_value = 0; return; } long1 = (ep->e_value / short1) & 0xffffL; ep->e_value = (short) long1; } else if (token == MODTOK) { if (short1 == 0) { eror('Z'); ep->e_value = 0; return; } ep->e_value = ep->e_value % short1; } } /* check that relocatability is the same for both argsuments */ int relsam(relo1, relo2) unsigned char relo1, relo2; { if ((relo1 == relo2) && (!(relo2 & RLEXT))) return(1); else { #if DEBUG printf("relsam returns no because relo1=%x relo2=%x\n",relo1,relo2); #endif return(0); } } /* error if relocatability of both arguments are not the same */ void relmat(relo1, relo2) unsigned char relo1, relo2; { if (relsam(relo1, relo2) == 0) { ebflag |= EVVALU; #if DEBUG printf("relmat: EVVALU because of return from relsam was 0\n"); #endif } } /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ MATH mfunclst[] = { "or", ORTOK, "eq", EQTOK, "gt", GTTOK, "ge", GETOK, "lt", LTTOK, "le", LETOK, "rr", RRTOK, "rl", RLTOK, "not", NOTTOK, "low", LOWTOK, "lsb", LOWTOK, "msb", HGHTOK, "res", RESTOK, "mod", MODTOK, "shr", SHRTOK, "shl", SHLTOK, "and", ANDTOK, "xor", XORTOK, "ugt", UGTTOK, "uge", UGETOK, "ult", ULTTOK, "ule", ULETOK, "abs", ABSTOK, "sgn", SGNTOK, "bit", BITTOK, "high", HGHTOK, 0 }; /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ SMATH sfunclst[] = { "+", PLUTOK, "-", MINTOK, "*", ASKTOK, "/", DIVTOK, "&", ANDTOK, "=", EQTOK, ">", GTTOK, "<", LTTOK, "^", EXPTOK, 0 }; /* * These routines are used by the expression evaluator to look up * arithmetic functions and return the tokens for those functions. */ /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ unsigned char *pmcf(pnt) register unsigned char *pnt; { register MATH *sp; register unsigned char *pnt1; #if DEBUG printf("pmcf\n"); #endif if (!alpha(pnt)) { #if DEBUG printf("pmcf: 'S' non-alpha char (%c) detected\n",*pnt); #endif eror('S'); return(pnt); } pnt1 = gsym(pnt, symbuf); if (*pnt1 != '.') { #if DEBUG printf("pmcf: 'S' next char (%c) not == '.'\n",*pnt1); #endif eror('S'); return(++pnt); } ++pnt1; sp = mfunclst; while(sp->m_name[0]) { if (match(sp->m_name, symbuf, 1)) { efunc = sp->m_token; return(pnt1); } ++sp; } #if DEBUG printf("pmcf: 'S' failure to make a match\n"); #endif eror('S'); return(++pnt); } unsigned char *pscf(pnt) register unsigned char *pnt; { register SMATH *sp; unsigned char c; #if DEBUG printf("pscf\n"); #endif if ((c = *pnt) == '*' && pnt[1] == '*') { efunc = EXPTOK; return(pnt += 2); } sp = sfunclst; while(sp->sm_name[0]) { if (sp->sm_name[0] == c) { efunc = sp->sm_token; return(++pnt); } ++sp; } #if DEBUG printf("pscf: 'S' failure to make a match\n"); #endif eror('S'); return(++pnt); }