home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug103.arc
/
MAC3.C
< prev
next >
Wrap
Text File
|
1979-12-31
|
10KB
|
343 lines
/*
** MAC3.C -- Small-Mac Assembler -- Part 3: Expression Analyzer
**
** Copyright 1985 J. E. Hendrix
**
*/
#include <stdio.h>
#include "mac.h"
#include "rel.h"
#include "ext.h"
#define NOCCARGC /* no argument count passing */
#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 about 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 ptr */
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 <oper> abs */
else { /* abs <oper> rel */
if(oper == PLUS) {*t |= PREL; return (ok);}
return (NO);
}
}
else { /* rel <oper> abs */
if(tr == ABS) {
switch(oper) {
case PLUS: case MINUS:
*t |= PREL;
return (ok);
}
return (NO);
}
else { /* rel <oper> rel */
if(*t & XRBIT) return (NO);
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 a 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);
}