Zapple-II/z80as/as3.c

261 lines
4.3 KiB
C

/*
* 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();
}