#include "asmpp.h" #include #include static void asmpp_mapdelete(asmdata_map_t* map, char* name, void* poo) { } asmpp_t* asmpp_new(asmpp_systemf_t outputf, void* udata) { asmpp_t* pp = malloc(sizeof(asmpp_t)); if (pp == NULL) { return NULL; } pp->outputf = outputf; pp->udata = udata; pp->defs = asmdata_map_new(543, &asmpp_mapdelete); if (pp->defs == NULL) { free(pp); return NULL; } pp->macros = asmdata_map_new(543, &asmpp_mapdelete); if (pp->macros == NULL) { free(pp); return NULL; } pp->context = NULL; return pp; } void asmpp_delete(asmpp_t* pp) { if (pp == NULL) { return; } asmdata_map_delete(pp->defs); asmdata_map_delete(pp->macros); free(pp); } const char* asmpp_contexttypename(asmpp_t* pp, int type) { switch (type) { case ASMPP_CONTEXT_OUTER: return "OUTER"; case ASMPP_CONTEXT_MACRO_EXPAND: return "MACRO_EXPAND"; case ASMPP_CONTEXT_MACRO_COLLECT: return "MACRO_COLLECT"; case ASMPP_CONTEXT_IF_EXPAND: return "IF_EXPAND"; case ASMPP_CONTEXT_IF_PARSEONLY: return "IF_PARSEONLY"; default: "Invalid"; } } asmpp_context_t* asmpp_enter(asmpp_t* pp, int type, asmpp_macro_t* macro) { //printf("ENTER CONTEXT %s(#%i) %s\n", asmpp_contexttypename(pp, type), type, macro == NULL ? "(not a macro)" : macro->proto->instrcopy); asmpp_context_t* c = malloc(sizeof(asmpp_context_t)); if (c == NULL) { return NULL; } c->type = type; c->macro = macro; c->locals = NULL; c->ifvalue = 0; c->next = pp->context; pp->context = c; return c; } void asmpp_dumpctx(asmpp_t* pp, asmpp_context_t* ctx) { printf("Context %i %s @%p\n", ctx->type, ctx->macro == NULL ? "(not a macro)" : ctx->macro->proto->instrcopy, ctx); } void asmpp_dumpctxs(asmpp_t* pp) { asmpp_context_t* ctx = pp->context; while (ctx != NULL) { asmpp_dumpctx(pp, ctx); ctx = ctx->next; } } void asmpp_exit(asmpp_t* pp, asmpp_context_t* context) { if (context != pp->context) { printf("WARNING: Trying to exit from wrong context\n"); asmpp_dumpctx(pp, context); printf("--- STACK: ---\n"); asmpp_dumpctxs(pp); return; } //printf("EXIT CONTEXT %i %s\n", context->type, context->macro == NULL ? "(not a macro)" : context->macro->proto->instrcopy); pp->context = context->next; if (context->locals != NULL) { asmdata_map_delete(context->locals); } free(context); } asmpp_macro_t* asmpp_quickmacro(asmpp_t* pp, asmln_t* proto, asmpp_systemf_t systemf) { asmpp_macro_t* macro = malloc(sizeof(asmpp_macro_t)); if (macro == NULL) { return NULL; } macro->proto = proto; macro->systemf = systemf; macro->lines = NULL; macro->next = NULL; asmpp_macro_t* oldmacro = asmdata_map_get(pp->macros, proto->instrcopy); macro->next = oldmacro; asmdata_map_set(pp->macros, proto->instrcopy, macro); return macro; } asmpp_def_t* asmpp_allocdef(asmpp_t* pp, int t, char* str, asmlnx_t* x) { asmpp_def_t* d = malloc(sizeof(asmpp_def_t)); if (d == NULL) { return NULL; } d->t = t; d->value = str; d->x = x; return d; } asmpp_def_t* asmpp_finddef(asmpp_t* pp, char* name) { asmpp_context_t* ctx = pp->context; if (ctx != NULL && ctx->locals != NULL) { asmpp_def_t* localresult = asmdata_map_get(ctx->locals, name); if (localresult != NULL) { return localresult; } } return asmdata_map_get(pp->defs, name); } asmpp_macro_t* asmpp_findmacro(asmpp_t* pp, char* name, int nparams) { asmpp_macro_t* firstm = asmdata_map_get(pp->macros, name); asmpp_macro_t* m = firstm; while (m != NULL) { if (m->proto->nparams == nparams) { return m; } m = m->next; } return NULL; } char* asmdata_strdup_(const char* str); char* asmpp_strdupnull_(char* str) { return (str == NULL) ? NULL : asmdata_strdup_(str); } /*int asmpp_copyxln_param(asmpp_t* pp, int* paramtp, char** strp, asmlnx_t** xp, bool expandparams) { int t = *paramtp; if (t == ASMT_TOKENTYPE_NAME) { asmpp_def_t* def = asmpp_finddef(pp, *strp); if (def != NULL) { *paramtp = def->t; *strp = asmpp_strdupnull_(def->value); } } *strp = asmpp_strdupnull_(*strp); // NOTE: This must handle NULLs! }*/ #define ASMPP_COPYXLN_EXPAND(dstt,dstc,dstx,srct,srcc,srcx,xp) \ do { \ bool _done = false; \ if ((xp) && (srct) == ASMT_TOKENTYPE_NAME) { \ asmpp_def_t* _def = asmpp_finddef(pp, srcc); \ if (_def != NULL) { \ _done = true; \ dstt = _def->t; \ dstc = asmpp_strdupnull_(_def->value); \ dstx = asmpp_copyxln_x(pp,_def->x,xp); \ } \ } \ if (!_done) { \ dstt = srct; \ dstc = asmpp_strdupnull_(srcc); \ dstx = asmpp_copyxln_x(pp,srcx,xp); \ } \ } while (0) asmlnx_t* asmpp_copyxln_x(asmpp_t* pp, asmlnx_t* x, bool expandparams); asmlnx_t* asmpp_copyxln_x(asmpp_t* pp, asmlnx_t* x, bool expandparams) { if (x == NULL) { return NULL; } asmlnx_t* result = calloc(sizeof(asmlnx_t),1); if (result == NULL) { return NULL; } ASMPP_COPYXLN_EXPAND(result->lhstype,result->lhscopy,result->lhsx,x->lhstype,x->lhscopy,x->lhsx,expandparams); //printf("Converted '%s' to '%s'\n", x->lhscopy, result->lhscopy); result->opcopy = asmpp_strdupnull_(x->opcopy); ASMPP_COPYXLN_EXPAND(result->rhstype,result->rhscopy,result->rhsx,x->rhstype,x->rhscopy,x->rhsx,expandparams); //printf("Converted '%s' to '%s'\n", x->lhscopy, result->lhscopy); return result; } asmln_t* asmpp_copyxln(asmpp_t* pp, asmln_t* ln, bool expandparams) { asmln_t* xln = malloc(sizeof(asmln_t)); xln->labelcopy = asmpp_strdupnull_(ln->labelcopy); xln->instrcopy = asmpp_strdupnull_(ln->instrcopy); xln->nparams = ln->nparams; xln->commentcopy = asmpp_strdupnull_(ln->commentcopy); xln->errorcopy = asmpp_strdupnull_(ln->errorcopy); int i; for (i = 0; i < xln->nparams; i++) { ASMPP_COPYXLN_EXPAND(xln->paramtype[i],xln->paramcopy[i],xln->paramx[i],ln->paramtype[i],ln->paramcopy[i],ln->paramx[i],expandparams); } return xln; } bool asmdata_streq_(const char* a, const char* b); /* Returns true unless compilation is disabled by an #if or equivalent context. */ bool asmpp_ifcompiling(asmpp_t* pp) { asmpp_context_t* ctx = pp->context; while (ctx != NULL) { if (ctx->type == ASMPP_CONTEXT_IF_EXPAND && ctx->ifvalue == 0) { return false; } ctx = ctx->next; } return true; } int asmpp_expand(asmpp_t* pp, asmln_t* ln) { if (pp->context != NULL && pp->context->type == ASMPP_CONTEXT_MACRO_COLLECT) { //printf("GOT MACRO LINE %s\n", ln->instrcopy); if (asmdata_streq_(ln->instrcopy, "%endmacro")) { asmpp_exit(pp, pp->context); return 0; } asmpp_lines_t* ll = pp->context->macro->lines; while (ll != NULL && ll->next != NULL) { ll = ll->next; } //printf("Found end\n"); asmpp_lines_t* nl = malloc(sizeof(asmpp_lines_t)); if (nl == NULL) { return -1; } nl->line = asmpp_copyxln(pp, ln, false); nl->next = NULL; if (ll != NULL) { ll->next = nl; } else { pp->context->macro->lines = nl; } //printf("Done\n"); return 0; } if (asmdata_streq_(ln->instrcopy, "%endif")) { asmpp_exit(pp, pp->context); return 0; } else if (!asmpp_ifcompiling(pp) && !asmdata_streq_(ln->instrcopy, "%else") && !asmdata_streq_(ln->instrcopy, "%elseif")) { if (asmdata_streq_(ln->instrcopy, "%if")) { asmpp_enter(pp, ASMPP_CONTEXT_IF_PARSEONLY, NULL); } return 0; } else if (asmdata_streq_(ln->labelcopy, "%macro")) { asmpp_macro_t* mac = asmpp_quickmacro(pp, asmpp_copyxln(pp, ln, false), NULL); //printf("Got macro '%s'\n", ln->instrcopy); asmpp_enter(pp, ASMPP_CONTEXT_MACRO_COLLECT, mac); return 0; } else if (asmdata_streq_(ln->labelcopy, "%def")) { asmln_t* defln = asmpp_copyxln(pp, ln, true); asmpp_def_t* def = asmpp_allocdef(pp, defln->paramtype[0], defln->paramcopy[0], defln->paramx[0]); asmdata_map_set(pp->defs, defln->instrcopy, def); return 0; } //dump_asmln(stdout, ln); asmln_t* xln = asmpp_copyxln(pp, ln, true); //dump_asmln(stdout, xln); if (asmdata_streq_(xln->instrcopy, "%if")) { uint64_t val; char* err; int sig; if (asmpp_calc(pp, xln->paramtype[0], xln->paramcopy[0], xln->paramx[0], &val, &err, &sig)) { //printf("Got if with value %llu\n", val); } else { printf("Calculation of the if factor failed: %s\n", err == NULL ? "(error string was not set)" : err); } asmpp_enter(pp, ASMPP_CONTEXT_IF_EXPAND, NULL); pp->context->ifvalue = val; if (pp->context->next != NULL) { pp->context->locals = pp->context->next->locals; } return 0; } else if (asmdata_streq_(xln->instrcopy, "%elseif")) { uint64_t val; char* err; int sig; if (pp->context->ifvalue != 0) { return 0; } else if (asmpp_calc(pp, xln->paramtype[0], xln->paramcopy[0], xln->paramx[0], &val, &err, &sig)) { //printf("Got if with value %llu\n", val); } else { printf("Calculation of the if factor failed: %s\n", err == NULL ? "(error string was not set)" : err); } pp->context->ifvalue = val; return 0; } else if (asmdata_streq_(xln->instrcopy, "%else")) { pp->context->ifvalue = (pp->context->ifvalue == 0) ? 1 : 0; return 0; } asmpp_macro_t* m = (xln->instrcopy == NULL) ? NULL : asmpp_findmacro(pp, xln->instrcopy, xln->nparams); int nexpanded = 0; if (m != NULL) { asmpp_context_t* ctx = asmpp_enter(pp, ASMPP_CONTEXT_MACRO_EXPAND, m); if (m->systemf != NULL) { asmpp_systemf_t sysf = m->systemf; nexpanded = sysf(pp, xln); } else { ctx->locals = asmdata_map_new(23, &asmpp_mapdelete); int argi; for (argi = 0; argi < m->proto->nparams; argi++) { if (m->proto->paramtype[argi] == ASMT_TOKENTYPE_OPENBR /*&& m->proto->paramx[argi]->lhstype == ASMT_TOKENTYPE_NAME && m->proto->paramx[argi]->rhstype == ASMT_TOKENTYPE_NAME && xln->paramtype[argi] == ASMT_TOKENTYPE_OPENBR*/) { asmpp_def_t* deflhs = asmpp_allocdef(pp, xln->paramx[argi]->lhstype, xln->paramx[argi]->lhscopy, xln->paramx[argi]->lhsx); asmpp_def_t* defop = asmpp_allocdef(pp, ASMT_TOKENTYPE_NAME, xln->paramx[argi]->opcopy, NULL); asmpp_def_t* defrhs = asmpp_allocdef(pp, xln->paramx[argi]->rhstype, xln->paramx[argi]->rhscopy, xln->paramx[argi]->rhsx); asmdata_map_set(ctx->locals, m->proto->paramx[argi]->lhscopy, deflhs); //printf("Mapped '%s' to '%s'\n", m->proto->paramx[argi]->lhscopy, deflhs->value); asmdata_map_set(ctx->locals, m->proto->paramx[argi]->opcopy, defop); asmdata_map_set(ctx->locals, m->proto->paramx[argi]->rhscopy, defrhs); } else { asmpp_def_t* def = asmpp_allocdef(pp, xln->paramtype[argi], xln->paramcopy[argi], xln->paramx[argi]); asmdata_map_set(ctx->locals, m->proto->paramcopy[argi] == NULL ? "?" : m->proto->paramcopy[argi], def); } } asmpp_lines_t* l = m->lines; while (l != NULL) { nexpanded += asmpp_expand(pp, l->line); l = l->next; } } asmpp_exit(pp, ctx); } else { asmpp_systemf_t outputf = pp->outputf; nexpanded = outputf(pp, xln); if (nexpanded < 0) { return -1; //printf("TODO: exit cleanly?\n"); //exit(-1); } } asmln_delete(xln); return nexpanded; } bool asmpp_binop(asmpp_t* pp, uint64_t lhsresult, int lhssig, char* op, uint64_t rhsresult, int rhssig, uint64_t* resultp, char** errp, int* signp) { if (asmdata_streq_(op, "&&")) { if (lhsresult && rhsresult) { return true; } else { return false; } } else if (asmdata_streq_(op, "||")) { if (lhsresult || rhsresult) { return true; } else { return false; } } else { *errp = "Unknown binary operator"; return false; } } long long asmdata_atoll_(const char* a); bool asmpp_calc(asmpp_t* pp, int t, char* str, asmlnx_t* x, uint64_t* resultp, char** errp, int* sigp) { char* err = NULL; int sig = 0; uint64_t result = 0; bool calculated = false; switch (t) { case ASMT_TOKENTYPE_NUMBER: result = asmdata_atoll_(str); // This handles hex/binary, TODO: foats printf("Number '%s' -> %d (0x%x 0b%b)\n", str, result, result, result); calculated = true; break; case ASMT_TOKENTYPE_OPENBR: uint64_t lhsresult; char* lhserror; int lhssig; bool lhscalc = asmpp_calc(pp, x->lhstype, x->lhscopy, x->lhsx, &lhsresult, &lhserror, &lhssig); if (!lhscalc) { err = lhserror; goto retfromcalc; } uint64_t rhsresult; char* rhserror; int rhssig; bool rhscalc = asmpp_calc(pp, x->rhstype, x->rhscopy, x->rhsx, &rhsresult, &rhserror, &rhssig); if (!rhscalc) { err = rhserror; goto retfromcalc; } calculated = asmpp_binop(pp, lhsresult, lhssig, x->opcopy, rhsresult, rhssig, &result, &err, &sig); break; default: calculated = false; } retfromcalc: if (resultp != NULL) { *resultp = result; } if (errp != NULL) { *errp = err; } if (sigp != NULL) { *sigp = sig; } return calculated; }