/* * Z-80 assembler. * Read in expressions in * address fields. */ #include "as.h" #define LOPRI 0 #define ADDPRI 1 #define MULPRI 2 #define HIPRI 3 /* * Read in an address * descriptor, and fill in * the supplied "ADDR" structure * with the mode and value. * Exits directly to "qerr" if * there is no address field or * if the syntax is bad. */ getaddr(ap) register ADDR *ap; { register int reg; register int c; if ((c=getnb()) != '(') { unget(c); expr1(ap, LOPRI, 0); return; } expr1(ap, LOPRI, 1); if (getnb() != ')') qerr(); reg = ap->a_type&TMREG; switch (ap->a_type&TMMODE) { case TBR: if (reg != C) aerr(); ap->a_type |= TMINDIR; break; case TSR: case TCC: aerr(); break; case TUSER: ap->a_type |= TMINDIR; break; case TWR: if (reg == HL) ap->a_type = TBR|M; else if (reg==IX || reg==IY) ap->a_type = TBR|reg; else if (reg==AF || reg==AFPRIME) aerr(); else ap->a_type |= TMINDIR; } } /* * Expression reader, * real work, part I. Read * operators and resolve types. * The "lpri" is the firewall operator * priority, which stops the scan. * The "paren" argument is true if * the expression is in parentheses. */ expr1(ap, lpri, paren) register ADDR *ap; { register int c; register int opri; ADDR right; expr2(ap); while ((c=getnb())=='+' || c=='-' || c=='*' || c=='/') { opri = ADDPRI; if (c=='*' || c=='/') opri = MULPRI; if (opri <= lpri) break; expr1(&right, opri, paren); switch (c) { case '+': if ((ap->a_type&TMMODE) != TUSER) istuser(&right); else ap->a_type = right.a_type; isokaors(ap, paren); ap->a_value += right.a_value; break; case '-': istuser(&right); isokaors(ap, paren); ap->a_value -= right.a_value; break; case '*': istuser(ap); istuser(&right); ap->a_value *= right.a_value; break; case '/': istuser(ap); istuser(&right); ap->a_value /= right.a_value; } } unget(c); } /* * Expression reader, * real work, part II. Read * in terminals. */ expr2(ap) register ADDR *ap; { register int c; register SYM *sp; register int mode; char id[NCPS]; c = getnb(); if (c == '[') { expr1(ap, LOPRI); if (getnb() != ']') qerr(); return; } if (c == '-') { expr1(ap, HIPRI); istuser(ap); ap->a_value = -ap->a_value; return; } if (c == '~') { expr1(ap, HIPRI); istuser(ap); ap->a_value = ~ap->a_value; return; } if (c == '\'') { ap->a_type = TUSER; ap->a_value = get(); while ((c=get()) != '\'') { if (c == '\n') qerr(); ap->a_value = (ap->a_value<<8) + c; } return; } if (c>='0' && c<='9') { expr3(ap, c); return; } if (isalpha(c)) { getid(id, c); if ((sp=lookup(id, uhash, 0)) == NULL && (sp=lookup(id, phash, 0)) == NULL) sp = lookup(id, uhash, 1); mode = sp->s_type&TMMODE; if (mode==TBR || mode==TWR || mode==TSR || mode==TCC) { ap->a_type = mode|sp->s_value; ap->a_value = 0; return; } if (mode == TNEW) uerr(id); ap->a_type = TUSER; ap->a_value = sp->s_value; return; } qerr(); } /* * Read in a constant. The argument * "c" is the first character of the constant, * and has already been validated. The number is * gathered up (stopping on non alphanumeric). * The radix is determined, and the number is * converted to binary. */ expr3(ap, c) register ADDR *ap; register int c; { register char *np1; register char *np2; register int radix; register VALUE value; char num[40]; np1 = &num[0]; do { if (isupper(c)) c = tolower(c); *np1++ = c; c = *ip++; } while (isalnum(c)); --ip; switch (*--np1) { case 'h': radix = 16; break; case 'o': case 'q': radix = 8; break; case 'b': radix = 2; break; default: radix = 10; ++np1; } np2 = &num[0]; value = 0; while (np2 < np1) { if ((c = *np2++)>='0' && c<='9') c -= '0'; else if (c>='a' && c<='f') c -= 'a'-10; else err('n'); if (c >= radix) err('n'); value = radix*value + c; } ap->a_type = TUSER; ap->a_value = value; } /* * Make sure that the * mode and register fields of * the type of the "ADDR" pointed to * by "ap" can participate in an addition * or a subtraction. */ isokaors(ap, paren) register ADDR *ap; { register int mode; register int reg; mode = ap->a_type&TMMODE; if (mode == TUSER) return; if (mode==TWR && paren!=0) { reg = ap->a_type&TMREG; if (reg==IX || reg==IY) return; } aerr(); }