#include "all.h" static char* skip(char *s) { while(isspace(*s)) s++; return s; } static char* token(char **ps) { char *s; char *t; s = skip(*ps); if(*s == '\0') return nil; t = s; while(*t && !isspace(*t)) t++; if(*t){ *t++ = '\0'; t = skip(t); } *ps = t; return s; } static char* arg(char **ps) { char *s; char *t; s = skip(*ps); if(*s == '\0') return nil; t = s; while(*t != ',' && *t != '\0') t++; if(*t){ *t++ = '\0'; t = skip(t); } *ps = t; return s; } static char* strchrp(char *s, int c) { int np; for(np=0; np>=0 && *s; s++){ if(np==0 && *s==c) return s; if(*s=='(') np++; if(*s==')') np--; } return nil; } typedef struct T T; struct T { char *s; int n; }; static int findnum(T *t, int nt, char *s) { int i; for(i=0; iop = EINDIRECT; ee->arg[0] = e; return ee; } ee = emalloc(sizeof(*ee)); ee->con = 0xDADADA; /* make sure we use 2-byte immediates for unknown constants */ if(t = strchrp(s, '+')){ ee->op = EADD; Twoargs: *t++ = '\0'; e = _parseexpr(&s); if(e==nil || *skip(s) != '\0') return nil; ee->arg[0] = e; e = _parseexpr(&t); if(e==nil) return nil; ee->arg[1] = e; *ps = t; return e; } if(t = strchrp(s, '-')){ ee->op = ESUB; goto Twoargs; } if(t = strchrp(s, '*')){ ee->op = EMUL; goto Twoargs; } x = strtol(s, &t, 0); if(t != s){ *ps = t; ee->op = ECONST; ee->con = x; return ee; } t = name(&s); if(t == nil) return nil; *ps = s; if((x = regname(t)) >= 0){ ee->op = EREG; if(x >= NREG){ ee->sz = 8; ee->reg = x-NREG; }else{ ee->sz = 16; ee->reg = x; } return ee; } ee->op = ENAME; ee->s = t; return ee; } Expr* parseexpr(char *s) { Expr *e; e = _parseexpr(&s); if(e==nil || *skip(s) != '\0') return nil; return e; } Inst* parseinst(char *s) { char *t, *tt; Inst *i; int p; Expr *e; i = emalloc(sizeof(Inst)); t = token(&s); if(t == nil) return nil; if(t[strlen(t)-1] == ':'){ i->op = OLABEL; t[strlen(t)-1] = '\0'; i->label = t; return i; } while((p = findprefix(t)) > 0){ if(i->npref >= nelem(i->pref)) parseerror("too many prefixes"); i->pref[i->npref++] = p; t = token(&s); } if(t == nil) parseerror("prefixes with no instruction"); if((i->op = isopcode(t)) < 0) parseerror("unrecognized opcode '%s'", t); while(t = arg(&s)){ if(i->narg >= nelem(i->arg)) parseerror("too many arguments"); tt = estrdup(t); if((e = parseexpr(t)) == nil) parseerror("cannot parse argument '%s'", tt); free(tt); i->arg[i->narg++] = e; } return i; } int instfmt(Fmt *fmt) { int j; Inst *i; i = va_arg(fmt->args, Inst*); if(i == nil) return fmtstrcpy(fmt, ""); if(i->op==OLABEL) return fmtprint(fmt, "%s:", i->label); for(j=0; jnpref; j++) fmtprint(fmt, "%s ", prefixstr(i->pref[j])); fmtprint(fmt, "%s", opname(i->op)); for(j=0; jnarg; j++){ if(j==0) fmtprint(fmt, " "); else fmtprint(fmt, ", "); fmtprint(fmt, "%E", i->arg[j]); } return 0; } int exprfmt(Fmt *fmt) { Expr *e; e = va_arg(fmt->args, Expr*); if(e == nil) return fmtprint(fmt, ""); switch(e->op){ default: return fmtprint(fmt, "", e->op); case EREG: return fmtstrcpy(fmt, regstr(e->reg, e->sz)); case ENAME: return fmtstrcpy(fmt, e->s); case EINDIRECT: return fmtprint(fmt, "*(%E)", e->arg[0]); case EADD: return fmtprint(fmt, "(%E+%E)", e->arg[0], e->arg[1]); case ESUB: return fmtprint(fmt, "(%E-%E)", e->arg[0], e->arg[1]); case EMUL: return fmtprint(fmt, "(%E*%E)", e->arg[0], e->arg[1]); case ECONST: if(e->con > -10 && e->con < 10) return fmtprint(fmt, "%d", e->con); return fmtprint(fmt, "%#x", e->con); } }