slas/asmpp.c

422 lines
17 KiB
C

#include "asmpp.h"
#include <stdlib.h>
#include <stdio.h>
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;
}