Mercurial > hg-old > index.cgi
diff lwasm/lwasm.c @ 346:a82c55070624
Added expression parsing infrastructure and misc fixes
author | lost@starbug |
---|---|
date | Sat, 27 Mar 2010 19:04:03 -0600 |
parents | 7416c3f9c321 |
children | 1649bc7bda5a |
line wrap: on
line diff
--- a/lwasm/lwasm.c Thu Mar 25 23:17:54 2010 -0600 +++ b/lwasm/lwasm.c Sat Mar 27 19:04:03 2010 -0600 @@ -25,6 +25,7 @@ #include <stdio.h> #include <stdarg.h> +#include <string.h> #include <lw_expr.h> #include <lw_alloc.h> @@ -32,12 +33,12 @@ #include "lwasm.h" -lw_expr_t lwasm_evaluate_var(char *var) +lw_expr_t lwasm_evaluate_var(char *var, void *priv) { return NULL; } -lw_expr_t lwasm_evaluate_special(int t, void *ptr) +lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv) { switch (t) { @@ -49,6 +50,15 @@ return lw_expr_build(lw_expr_type_int, cl -> len); } break; + + case lwasm_expr_lineaddr: + { + line_t *cl = ptr; + if (cl -> addr) + return lw_expr_copy(cl -> addr); + else + return NULL; + } } return NULL; } @@ -85,3 +95,339 @@ as -> nextcontext++; return r; } + +void lwasm_emit(line_t *cl, int byte) +{ + if (cl -> outputl == cl -> outputbl) + { + cl -> output = lw_realloc(cl -> output, cl -> outputbl + 8); + cl -> outputbl += 8; + } + cl -> output[cl -> outputl++] = byte & 0xff; +} + +void lwasm_emitop(line_t *cl, int opc) +{ + if (opc > 0x100) + lwasm_emit(cl, opc >> 8); + lwasm_emit(cl, opc); +} + +lw_expr_t lwasm_parse_term(char **p, void *priv) +{ + asmstate_t *as = priv; + int val; + + if (!**p) + return NULL; + + if (**p == '*' || ( + **p == '.' + && !((*p)[1] >= 'A' && (*p)[1] <= 'Z') + && !((*p)[1] >= 'a' && (*p)[1] <= 'z') + && !((*p)[1] >= '0' && (*p)[1] <= '9') + )) + { + // special "symbol" for current line addr (*, .) + (*p)++; + return lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, as -> cl); + } + + // branch points + if (**p == '<') + { + (*p)++; + return lw_expr_build(lw_expr_type_special, lwasm_expr_prevbp, as -> cl); + } + if (**p == '>') + { + (*p)++; + return lw_expr_build(lw_expr_type_special, lwasm_expr_nextbp, as -> cl); + } + + // double ascii constant + if (**p == '"') + { + int v; + (*p)++; + if (!**p) + return NULL; + if (!*((*p)+1)) + return NULL; + v = (unsigned char)**p << 8 | (unsigned char)*((*p)+1); + (*p) += 2; + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '\'') + { + int v; + + (*p)++; + if (!**p) + return NULL; + + v = (unsigned char)**p; + (*p)++; + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '&') + { + // decimal constant + int v = 0; + (*p)++; + + if (!strchr("0123456789", **p)) + return NULL; + + while (**p && strchr("0123456789", **p)) + { + val = val * 10 + (**p - '0'); + (*p)++; + } + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '%') + { + // binary constant + int v = 0; + (*p)++; + + if (**p != '0' && **p != '1') + return NULL; + + while (**p && (**p == '0' || **p == '1')) + { + val = val * 2 + (**p - '0'); + (*p)++; + } + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '$') + { + // hexadecimal constant + int v = 0, v2; + (*p)++; + + if (!strchr("0123456789abcdefABCDEF", **p)) + return NULL; + + while (**p && strchr("0123456789abcdefABCDEF", **p)) + { + v2 = toupper(**p) - '0'; + if (v2 > 9) + v2 -= 7; + val = val * 16 + v2; + (*p)++; + } + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '0' && (*((*p)+1) == 'x' || *((*p)+1) == 'X')) + { + // hexadecimal constant, C style + int v = 0, v2; + (*p)+=2; + + if (!strchr("0123456789abcdefABCDEF", **p)) + return NULL; + + while (**p && strchr("0123456789abcdefABCDEF", **p)) + { + v2 = toupper(**p) - '0'; + if (v2 > 9) + v2 -= 7; + val = val * 16 + v2; + (*p)++; + } + return lw_expr_build(lw_expr_type_int, v); + } + + if (**p == '@' && (*((*p)+1) >= '0' && *((*p)+1) <= '7')) + { + // octal constant + int v = 0; + (*p)++; + + if (!strchr("01234567", **p)) + return NULL; + + while (**p && strchr("01234567", **p)) + { + val = val * 8 + (**p - '0'); + (*p)++; + } + return lw_expr_build(lw_expr_type_int, v); + } + + + // symbol or bare decimal or suffix constant here + do + { + int havedol = 0; + int l = 0; + + while ((*p)[l] && strchr(SYMCHARS, (*p)[l])) + { + if ((*p)[l] == '$') + havedol = 1; + l++; + } + if (l == 0) + return NULL; + + if (havedol || **p < '0' || **p > '9') + { + // have a symbol here + char *sym; + lw_expr_t term; + + sym = lw_strndup(*p, l); + (*p) += l; + term = lw_expr_build(lw_expr_type_var, sym); + lw_free(sym); + return term; + } + } while (0); + + if (!**p) + return NULL; + + // we have a numeric constant here, either decimal or postfix base notation + { + int decval = 0, binval = 0, hexval = 0, octval = 0; + int valtype = 15; // 1 = bin, 2 = oct, 4 = dec, 8 = hex + int bindone = 0; + int val; + int dval; + + while (1) + { + if (!**p || !strchr("0123456789ABCDEFabcdefqhoQHO", **p)) + { + // we can legally be bin or decimal here + if (bindone) + { + // just finished a binary value + val = binval; + break; + } + else if (valtype & 4) + { + val = decval; + break; + } + else + { + // bad value + return NULL; + } + } + + dval = toupper(**p); + (*p)++; + + if (bindone) + { + // any characters past "B" means it is not binary + bindone = 0; + valtype &= 14; + } + + switch (dval) + { + case 'Q': + case 'O': + if (valtype & 2) + { + val = octval; + valtype = -1; + break; + } + else + { + return NULL; + } + /* can't get here */ + + case 'H': + if (valtype & 8) + { + val = hexval; + valtype = -1; + break; + } + else + { + return NULL; + } + /* can't get here */ + + case 'B': + // this is a bit of a sticky one since B may be a + // hex number instead of the end of a binary number + // so it falls through to the digit case + if (valtype & 1) + { + // could still be binary of hex + bindone = 1; + valtype = 9; + } + /* fall through intented */ + + default: + // digit + dval -= '0'; + if (dval > 9) + dval -= 7; + if (valtype & 8) + hexval = hexval * 16 + dval; + if (valtype & 4) + { + if (dval > 9) + valtype &= 11; + else + decval = decval * 10 + dval; + } + if (valtype & 2) + { + if (dval > 7) + valtype &= 13; + else + octval = octval * 8 + dval; + } + if (valtype & 1) + { + if (dval > 1) + valtype &= 14; + else + binval = binval * 2 + dval; + } + } + if (valtype == -1) + break; + + // return if no more valid types + if (valtype == 0) + return NULL; + + val = decval; // in case we fall through + } + + // get here if we have a value + return lw_expr_build(lw_expr_type_int, val); + } + // can't get here +} + +lw_expr_t lwasm_parse_expr(asmstate_t *as, char **p) +{ + lw_expr_t e; + + e = lw_expr_parse(p, as); + + return e; +}