/* * EXP.C * * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. * * Handle expression evaluation and addressing mode decode. * * NOTE! If you use the string field in an expression you must clear * the SYM_MACRO and SYM_STRING bits in the flags before calling * freesymbollist()! */ #include "asm.h" /* * evaluate an expression. Figure out the addressing mode: * * implied * #val immediate * val zero page or absolute * val,x zero,x or absolute,x * val,y zero,y or absolute,y * (val) indirect * (val,x) zero indirect x * (val),y zero indirect y * * exp, exp,.. LIST of expressions * * an absolute may be returned as zero page * a relative may be returned as zero page or absolute * * unary: - ~ ! < > * binary: (^)(* / %)(+ -)(>> <<)(& |)(`)(&& ||)(== != < > <= >=) * * values: symbol, octal, decimal, $hex, %binary, 'c "str" * */ #define MAXOPS 32 #define MAXARGS 64 ubyte Argflags[MAXARGS]; long Argstack[MAXARGS]; ubyte *Argstring[MAXARGS]; short Oppri[MAXOPS]; void (*Opdis[MAXOPS]) ARGS((long, long, long, long)); uword Argi, Opi, Lastwasop; uword Argibase, Opibase; SYMBOL * eval(str) register char *str; { register SYMBOL *base, *cur; uword oldargibase = Argibase; uword oldopibase = Opibase; uword scr; Argibase = Argi; Opibase = Opi; Lastwasop = 1; base = cur = allocsymbol(); while (*str) { if (Xdebug) printf("char '%c'\n", *str); switch(*str) { case ' ': case '\n': ++str; break; case '~': if (Lastwasop) doop(op_invert, 128); else asmerr(0,0); ++str; break; case '*': doop(op_mult, 20); ++str; break; case '/': doop(op_div, 20); ++str; break; case '%': if (Lastwasop) { str = (char *)pushbin(str+1); } else { doop(op_mod, 20); ++str; } break; case '?': /* 10 */ doop(op_question, 10); ++str; break; case '+': /* 19 */ doop(op_add, 19); ++str; break; case '-': /* 19: - (or - unary) */ if (Lastwasop) { doop(op_negate, 128); } else { doop(op_sub, 19); } ++str; break; case '>': /* 18: >> << 17: > >= <= < */ if (Lastwasop) { doop(op_takemsb, 128); ++str; break; } if (str[1] == '>') { doop(op_shiftright, 18); ++str; } else if (str[1] == '=') { doop(op_greatereq, 17); ++str; } else { doop(op_greater, 17); } ++str; break; case '<': if (Lastwasop) { doop(op_takelsb, 128); ++str; break; } if (str[1] == '<') { doop(op_shiftleft, 18); ++str; } else if (str[1] == '=') { doop(op_smallereq, 17); ++str; } else { doop(op_smaller, 17); } ++str; break; case '=': /* 16: == (= same as ==) */ if (str[1] == '=') ++str; doop(op_eqeq, 16); ++str; break; case '!': /* 16: != */ if (Lastwasop) { doop(op_not, 128); } else { doop(op_noteq, 16); ++str; } ++str; break; case '&': /* 15: & 12: && */ if (str[1] == '&') { doop(op_andand, 12); ++str; } else { doop(op_and, 15); } ++str; break; case '^': /* 14: ^ */ doop(op_xor, 14); ++str; break; case '|': /* 13: | 11: || */ if (str[1] == '|') { doop(op_oror, 11); ++str; } else { doop(op_or, 13); } ++str; break; case '[': /* eventually an argument */ if (Opi == MAXOPS) puts("too many ops"); else Oppri[Opi++] = 0; ++str; break; case ']': while(Opi != Opibase && Oppri[Opi-1]) evaltop(); if (Opi != Opibase) --Opi; ++str; if (Argi == Argibase) { puts("']' error, no arg on stack"); break; } if (*str == 'd') { /* STRING CONVERSION */ char buf[32]; ++str; if (Argflags[Argi-1] == 0) { sprintf(buf,"%ld",Argstack[Argi-1]); Argstring[Argi-1] = (ubyte *)strcpy(malloc(strlen(buf)+1),buf); } } break; case '#': cur->addrmode = AM_IMM8; ++str; break; case '(': cur->addrmode = AM_INDWORD; ++str; break; case ')': if (cur->addrmode == AM_INDWORD && str[1] == ',' && (str[2]|0x20) == 'y') { cur->addrmode = AM_INDBYTEY; str += 2; } ++str; break; case ',': while(Opi != Opibase) evaltop(); Lastwasop = 1; scr = str[1]|0x20; /* to lower case */ if (cur->addrmode == AM_INDWORD && scr == 'x' && !alphanum(str[2])) { cur->addrmode = AM_INDBYTEX; ++str; } else if (scr == 'x' && !alphanum(str[2])) { cur->addrmode = AM_0X; ++str; } else if (scr == 'y' && !alphanum(str[2])) { cur->addrmode = AM_0Y; ++str; } else { register SYMBOL *new = allocsymbol(); cur->next = new; --Argi; if (Argi < Argibase) asmerr(0,0); if (Argi > Argibase) asmerr(0,0); cur->value = Argstack[Argi]; cur->flags = Argflags[Argi]; if (cur->string= (ubyte *)Argstring[Argi]) { cur->flags |= SYM_STRING; if (Xdebug) printf("STRING: %s\n", cur->string); } cur = new; } ++str; break; case '$': str = (char *)pushhex(str+1); break; case '\'': str = (char *)pushchar(str+1); break; case '\"': str = (char *)pushstr(str+1); break; default: if (*str == '0') str = (char *)pushoct(str); else { if (*str > '0' && *str <= '9') str = (char *)pushdec(str); else str = (char *)pushsymbol(str); } break; } } while(Opi != Opibase) evaltop(); if (Argi != Argibase) { --Argi; cur->value = Argstack[Argi]; cur->flags = Argflags[Argi]; if (cur->string= (ubyte *)Argstring[Argi]) { cur->flags |= SYM_STRING; if (Xdebug) printf("STRING: %s\n", cur->string); } if (base->addrmode == 0) base->addrmode = AM_BYTEADR; } if (Argi != Argibase || Opi != Opibase) asmerr(0,0); Argi = Argibase; Opi = Opibase; Argibase = oldargibase; Opibase = oldopibase; return(base); } int alphanum(c) int c; { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')); } void evaltop() { if (Xdebug) printf("evaltop @(A,O) %d %d\n", Argi, Opi); if (Opi <= Opibase) { asmerr(0,0); Opi = Opibase; return; } --Opi; if (Oppri[Opi] == 128) { if (Argi < Argibase + 1) { asmerr(0,0); Argi = Argibase; return; } --Argi; (*Opdis[Opi])(Argstack[Argi], Argflags[Argi], 0, 0); } else { if (Argi < Argibase + 2) { asmerr(0,0); Argi = Argibase; return; } Argi -= 2; (*Opdis[Opi])(Argstack[Argi], Argstack[Argi+1], Argflags[Argi], Argflags[Argi+1]); } } void stackarg(val, flags, ptr1) long val; int flags; ubyte *ptr1; { ubyte *str = NULL; if (Xdebug) printf("stackarg %ld (@%d)\n", val, Argi); Lastwasop = 0; if (flags & SYM_STRING) { register ubyte *ptr = ptr1; register ubyte *new; register uword len; val = len = 0; while (*ptr && *ptr != '\"') { val = (val << 8) | *ptr; ++ptr; ++len; } new = malloc(len + 1); BMov(ptr1, new, len); new[len] = 0; flags &= ~SYM_STRING; str = new; } Argstack[Argi] = val; Argstring[Argi] = str; Argflags[Argi] = flags; if (++Argi == MAXARGS) { puts("stackarg: maxargs stacked"); Argi = Argibase; } while (Opi != Opibase && Oppri[Opi-1] == 128) evaltop(); } void doop(func, pri) void (*func) ARGS((long, long, long, long)); int pri; { if (Xdebug) puts("doop"); Lastwasop = 1; if (Opi == Opibase || pri == 128) { if (Xdebug) printf("doop @ %d unary\n", Opi); Opdis[Opi] = func; Oppri[Opi] = pri; ++Opi; return; } while (Opi != Opibase && Oppri[Opi-1] && pri <= Oppri[Opi-1]) evaltop(); if (Xdebug) printf("doop @ %d\n", Opi); Opdis[Opi] = func; Oppri[Opi] = pri; ++Opi; if (Opi == MAXOPS) { puts("doop: too many operators"); Opi = Opibase; } return; } void op_takelsb(v1, f1, x1, x2) long v1; long f1; long x1, x2; { stackarg(v1 & 0xFFL, f1, NULL); } void op_takemsb(v1, f1, x1, x2) long v1; long f1; long x1, x2; { stackarg((v1 >> 8) & 0xFF, f1, NULL); } void op_negate(v1, f1, x1, x2) long v1; long f1; long x1, x2; { stackarg(-v1, f1, NULL); } void op_invert(v1, f1, x1, x2) long v1; long f1; long x1, x2; { stackarg(~v1, f1, NULL); } void op_not(v1, f1, x1, x2) long v1; long f1; long x1, x2; { stackarg((long)!v1, f1, NULL); } void op_mult(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1 * v2, f1|f2, NULL); } void op_div(v1, v2, f1, f2) long v1, v2; long f1, f2; { if (f1|f2) { stackarg(0L, f1|f2, NULL); return; } if (v2 == 0) { puts("division by zero"); stackarg(0L, 0, NULL); } else { stackarg(v1 / v2, 0, NULL); } } void op_mod(v1, v2, f1, f2) long v1, v2; long f1, f2; { if (f1|f2) { stackarg(0L, f1|f2, NULL); return; } if (v2 == 0) stackarg(v1, 0, NULL); else stackarg(v1 % v2, 0, NULL); } void op_question(v1, v2, f1, f2) long v1, v2; long f1, f2; { if (f1) stackarg(0L, f1, NULL); else stackarg((long)((v1) ? v2 : 0), ((v1) ? f2 : 0), NULL); } void op_add(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1 + v2, f1|f2, NULL); } void op_sub(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1 - v2, f1|f2, NULL); } void op_shiftright(v1, v2, f1, f2) long v1, v2; long f1, f2; { if (f1|f2) stackarg(0L, f1|f2, NULL); else stackarg((long)(v1 >> v2), 0, NULL); } void op_shiftleft(v1, v2, f1, f2) long v1, v2; long f1, f2; { if (f1|f2) stackarg(0L, f1|f2, NULL); else stackarg((long)(v1 << v2), 0, NULL); } void op_greater(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 > v2), f1|f2, NULL); } void op_greatereq(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 >= v2), f1|f2, NULL); } void op_smaller(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 < v2), f1|f2, NULL); } void op_smallereq(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 <= v2), f1|f2, NULL); } void op_eqeq(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 == v2), f1|f2, NULL); } void op_noteq(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg((long)(v1 != v2), f1|f2, NULL); } void op_andand(v1, v2, f1, f2) long v1, v2; long f1, f2; { if ((!f1 && !v1) || (!f2 && !v2)) { stackarg(0L, 0, NULL); return; } stackarg(1L, f1|f2, NULL); } void op_oror(v1, v2, f1, f2) long v1, v2; long f1, f2; { if ((!f1 && v1) || (!f2 && v2)) { stackarg(1L, 0, NULL); return; } stackarg(0L, f1|f2, NULL); } void op_xor(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1^v2, f1|f2, NULL); } void op_and(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1&v2, f1|f2, NULL); } void op_or(v1, v2, f1, f2) long v1, v2; long f1, f2; { stackarg(v1|v2, f1|f2, NULL); } ubyte * pushchar(str) ubyte *str; { if (*str) { stackarg((long)*str, 0, NULL); ++str; } else { stackarg((long)' ', 0, NULL); } return((ubyte *)str); } ubyte * pushhex(str) ubyte *str; { register long val = 0; for (;; ++str) { if (*str >= '0' && *str <= '9') { val = (val << 4) + (*str - '0'); continue; } if ((*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) { val = (val << 4) + ((*str&0x1F) + 9); continue; } break; } stackarg(val, 0, NULL); return((ubyte *)str); } ubyte * pushoct(str) ubyte *str; { register long val = 0; while (*str >= '0' && *str <= '7') { val = (val << 3) + (*str - '0'); ++str; } stackarg(val, 0, NULL); return((ubyte *)str); } ubyte * pushdec(str) ubyte *str; { register long val = 0; while (*str >= '0' && *str <= '9') { val = (val * 10) + (*str - '0'); ++str; } stackarg(val, 0, NULL); return((ubyte *)str); } ubyte * pushbin(str) ubyte *str; { register long val = 0; while (*str == '0' || *str == '1') { val = (val << 1) | (*str - '0'); ++str; } stackarg(val, 0, NULL); return((ubyte *)str); } ubyte * pushstr(str) ubyte *str; { stackarg(0L, SYM_STRING, str); while (*str && *str != '\"') ++str; if (*str == '\"') ++str; return((ubyte *)str); } ubyte * pushsymbol(str) ubyte *str; { register SYMBOL *sym; register ubyte *ptr; ubyte macro = 0; for (ptr = str; *ptr == '_' || *ptr == '.' || (*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9'); ++ptr ); if (ptr == str) { asmerr(9,0); printf("char = '%c' %d (-1: %d)\n", *str, *str, *(str-1)); if (F_listfile) fprintf(FI_listfile, "char = '%c' code %d\n", *str, *str); return((ubyte *)str+1); } if (sym = findsymbol(str, ptr - str)) { if (sym->flags & SYM_UNKNOWN) ++Redo_eval; if (sym->flags & SYM_MACRO) { macro = 1; sym = eval(sym->string); } if (sym->flags & SYM_STRING) stackarg(0L, SYM_STRING, sym->string); else stackarg(sym->value, sym->flags & SYM_UNKNOWN, NULL); sym->flags |= SYM_REF|SYM_MASREF; if (macro) freesymbollist(sym); } else { stackarg(0L, SYM_UNKNOWN, NULL); sym = createsymbol(str, ptr - str); sym->flags = SYM_REF|SYM_MASREF|SYM_UNKNOWN; ++Redo_eval; } return(ptr); }