/* ** MAC3.C -- Small-Mac Assembler -- Part 3: Expression Analyzer ** ** Copyright 1985 J. E. Hendrix ** ** */ #include #include "mac.h" #include "rel.h" #include "ext.h" #define NOCCARGC /* no argument countpassing */ #define OR 1 /* | */ #define XOR 2 /* ^ */ #define AND 3 /* & */ #define EQ 4 /* == */ #define NE 5 /* != */ #define LE 6 /* <= */ #define GE 7 /* >= */ #define LT 8 /* < */ #define GT 9 /* > */ #define RSH 10 /* >> */ #define LSH 11 /* << */ #define PLUS 12 /* + */ #define MINUS 13 /* - */ #define MULT 14 /* * */ #define DIV 15 /* / */ #define MOD 16 /* % */ #define CPL 17 /* ~ */ #define NOT 18 /* ! */ #define LPN 19 /* ( */ #define RPN 20 /* ) */ #define LOC 21 /* $ */ #define SYM 22 /* symbol */ #define NUM 23 /* number */ #define EOE 24 /* end of expr */ int number, /* value of numeric token */ iloc, /* instruction location */ ct; /* current token */ int /* operators by precedence level */ l1ops[] = {OR, NULL}, l2ops[] = {XOR, NULL}, l3ops[] = {AND, NULL}, l4ops[] = {EQ, NE, NULL}, l5ops[] = {LE, GE, LT, GT, NULL}, l6ops[] = {LSH, RSH, NULL}, l7ops[] = {PLUS, MINUS, NULL}, l8ops[] = {MULT, DIV, MOD, NULL}; /* ** evaluate the next expression at ep ** caller must set ep */ expr(value, type) int *value, *type; { ct = NULL; /* no current token */ if(token(EOE)) { *value = 0; *type = ABS; /* null expression */ return; } if(!level1(value, type) || ct != EOE) experr(); } level1(v, t) int *v, *t; {return (down(l1ops, level2, v, t));} level2(v, t) int *v, *t; {return (down(l2ops, level3, v, t));} level3(v, t) int *v, *t; {return (down(l3ops, level4, v, t));} level4(v, t) int *v, *t; {return (down(l4ops, level5, v, t));} level5(v, t) int *v, *t; {return (down(l5ops, level6, v, t));} level6(v, t) int *v, *t; {return (down(l6ops, level7, v, t));} level7(v, t) int *v, *t; {return (down(l7ops, level8, v, t));} level8(v, t) int *v, *t; {return (down(l8ops, unary, v, t));} unary(v, t) int *v, *t; { if(token(CPL)) { /* ~ */ if(!unary(v, t)) return (NO); *v = ~*v; goto check; } else if(token(NOT)) { /* ! */ if(!unary(v, t)) return (NO); *v = !*v; goto check; } else if(token(MINUS)) { /* - */ if(!unary(v, t)) return (NO); *v = -*v; check: if(*t & RELBITS) relerr(); /* can't be relocatable */ *t &= ~RELBITS; /* force ABS */ return (YES); /* lie baout it */ } else return (primary(v, t)); } primary(v, t) int *v, *t; { int ok; if(token(LPN)) { /* ( */ ok = level1(v, t); if(token(RPN)) return(ok); return (NO); } *t = ABS; *v = 0; /* defaults */ if(token(NUM)) { /* number */ *v = number; return (YES); } else if(token(LOC)) { /* $ */ *v = iloc; *t = PREL; return (YES); } else { if(token(SYM)) { /* symbol */ if(stfind()) { *t = stptr[STFLAG]; if(!(stptr[STFLAG] & XRBIT)) { if(gotxr) rederr(); *v = getint(stptr + STVALUE); } else goto doxr; /* ext ref */ } else if(gotxr) { /* define new ext ref */ addsym(); /* symbol */ *t = XRBIT|ABS; /* 1st ext ref is ABS 0 */ doxr: prior = getint(stptr + STVALUE); /* save prior prtr */ putint(stptr + STVALUE, loc); /* this becomes prev */ stptr[STFLAG] |= XRBIT|PREL; /* ext ref is relative */ } else underr(); /* undefined */ return (YES); } } return (NO); } /* ** drop to a lower level */ down(ops, level, v, t) int *ops, (*level)(), *v, *t; { int *op; if(!(*level)(v, t)) return (NO); op = --ops; while(*++op) { if(token(*op)) { if(!down2(*op, level, v, t)) return (NO); if(token(EOE)) return (YES); op = ops; } } return (YES); } /* ** binary drop to a lower level */ down2(oper, level, v, t) int oper, (*level)(), *v, *t; { int ok, vr, tr, tl; ok = (*level)(&vr, &tr); *v = binary(*v, oper, vr); /* apply operator */ tl = *t & RELBITS; *t = (*t | tr) & ~RELBITS; /* merge flag bits & default to ABS */ tr &= RELBITS; if(tl == ABS) { if(tr == ABS) return (ok); /* abs abs */ else { /* abs rel */ if(oper == PLUS) {*t |= PREL; return (ok);} return (NO); } } else { /* rel abs */ if(tr == ABS) { switch(oper) { case PLUS: case MINUS: *t |= PREL; return (ok); } return (NO); } else { /* rel rel */ switch(oper) { case MINUS: case EQ: case LT: case LE: case NE: case GT: case GE: return (ok); } return (NO); } } } /* ** apply a binary operator */ binary(left, oper, right) int left, oper, right; { switch(oper) { case OR: return (left | right); case XOR: return (left ^ right); case AND: return (left & right); case EQ: return (left == right); case NE: return (left != right); case LE: return (left <= right); case GE: return (left >= right); case LT: return (left < right); case GT: return (left > right); case RSH: return (left >> right); case LSH: return (left << right); case PLUS: return (left + right); case MINUS: return (left - right); case MULT: return (left * right); case DIV: return (left / right); case MOD: return (left % right); } return (NULL); } /* ** scan for next token */ token(want) int want; { int len; if(ct) return (found(want, ct)); /* already have token */ while(isspace(*ep)) ++ep; switch(*ep++) { case '|': return (found(want, OR)); case '^': return (found(want, XOR)); case '&': return (found(want, AND)); case '+': return (found(want, PLUS)); case '-': return (found(want, MINUS)); case '*': return (found(want, MULT)); case '/': return (found(want, DIV)); case '%': return (found(want, MOD)); case '~': return (found(want, CPL)); case '(': return (found(want, LPN)); case ')': return (found(want, RPN)); case '$': return (found(want, LOC)); case ',': return (found(want, EOE)); case '!': if(*ep++ == '=') return (found(want, NE)); --ep; return (found(want, NOT)); case '<': if(*ep++ == '=') return (found(want, LE)); --ep; if(*ep++ == '<') return (found(want, LSH)); --ep; return (found(want, LT)); case '>': if(*ep++ == '=') return (found(want, GE)); --ep; if(*ep++ == '>') return (found(want, RSH)); --ep; return (found(want, GT)); case '=': if(*ep++ == '=') return (found(want, EQ)); --ep; } --ep; ep = getsym(ep, YES); if(stsym[0]) {return (found(want, SYM));} if(len = getnum(ep)) {ep += len; return (found(want, NUM));} if(atend(*ep)) return (found(want, EOE)); return (NO); } /* ** what was found? */ found(want, have) int want, have; { ct = have; /* new current token */ if(ct == want) { /* was it sought */ if(ct != EOE) ct = NULL; /* yes, pass it by */ return (YES); /* caller has a hit */ } return (NO); /* sorry, no hit */ } /* ** get hex, dec,or oct number as binary value in number ** return length of field processed, else zero */ getnum(at) char *at; { int bump, len; char *end, *cp; cp = at; if((*cp == '\'' || *cp == '"') && *cp == cp[2]) { /* quoted char */ number = cp[1] & 255; return (3); } switch(*cp) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': end = cp; bump = 1; while(YES) { switch(toupper(*end)) { default: if(isxdigit(*end)) {++end; continue;} bump = 0; len = utoi(cp, &number); break; case 'Q': case 'O': len = otoi(cp, &number); break; case 'H': len = xtoi(cp, &number); break; } break; } if(len != (end - cp)) numerr(); /* bad number */ return ((end - at) + bump); } return (0); } /* ** get a symbol into stsym */ getsym(at, ref) char *at; int ref; { int j; j = badsym = gotep = gotxr = gotlabel = 0; if(!isdigit(*at)) { while(YES) { switch(toupper(*at)) { case '#': if(ref) {gotxr = YES; if(*++at == '#') ++at; break;} default: if(ref) break; badsym = YES; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': case '.': case '$': case '?': case '@': if(j < MAXLAB) stsym[j++] = toupper(*at); ++at; continue; case ':': gotlabel = YES; if(*++at == ':') {gotep = YES; ++at;} case ' ': case '\t': case '\n': case ',': case NULL: case COMMENT: } while(isspace(*at)) ++at; break; } } stsym[j] = NULL; if(stsym[0] && !gotlabel) gotnam = YES; else gotnam = NO; return (at); }