385 lines
10 KiB
C
385 lines
10 KiB
C
// codegen.c -- DVX BASIC p-code emitter implementation
|
|
|
|
#include "codegen.h"
|
|
#include "symtab.h"
|
|
#include "opcodes.h"
|
|
#include "thirdparty/stb_ds_wrap.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
|
|
// ============================================================
|
|
// basAddData
|
|
// ============================================================
|
|
|
|
bool basAddData(BasCodeGenT *cg, BasValueT val) {
|
|
BasValueT copy = basValCopy(val);
|
|
arrput(cg->dataPool, copy);
|
|
cg->dataCount = (int32_t)arrlen(cg->dataPool);
|
|
return true;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basAddConstant
|
|
// ============================================================
|
|
|
|
uint16_t basAddConstant(BasCodeGenT *cg, const char *text, int32_t len) {
|
|
// Check if this string is already in the pool
|
|
for (int32_t i = 0; i < cg->constCount; i++) {
|
|
if (cg->constants[i]->len == len && memcmp(cg->constants[i]->data, text, len) == 0) {
|
|
return (uint16_t)i;
|
|
}
|
|
}
|
|
|
|
uint16_t idx = (uint16_t)cg->constCount;
|
|
BasStringT *s = basStringNew(text, len);
|
|
arrput(cg->constants, s);
|
|
cg->constCount = (int32_t)arrlen(cg->constants);
|
|
return idx;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodeGenAddDebugVar
|
|
// ============================================================
|
|
|
|
void basCodeGenAddDebugVar(BasCodeGenT *cg, const char *name, uint8_t scope, uint8_t dataType, int32_t index, int32_t procIndex, const char *formName) {
|
|
BasDebugVarT dv;
|
|
memset(&dv, 0, sizeof(dv));
|
|
snprintf(dv.name, BAS_MAX_PROC_NAME, "%s", name);
|
|
dv.scope = scope;
|
|
dv.dataType = dataType;
|
|
dv.index = index;
|
|
dv.procIndex = procIndex;
|
|
|
|
if (formName && formName[0]) {
|
|
snprintf(dv.formName, BAS_MAX_PROC_NAME, "%s", formName);
|
|
}
|
|
arrput(cg->debugVars, dv);
|
|
cg->debugVarCount = (int32_t)arrlen(cg->debugVars);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodeGenBuildModule
|
|
// ============================================================
|
|
|
|
BasModuleT *basCodeGenBuildModule(BasCodeGenT *cg) {
|
|
BasModuleT *mod = (BasModuleT *)calloc(1, sizeof(BasModuleT));
|
|
|
|
if (!mod) {
|
|
return NULL;
|
|
}
|
|
|
|
// Copy code
|
|
mod->code = (uint8_t *)malloc(cg->codeLen);
|
|
|
|
if (!mod->code) {
|
|
free(mod);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(mod->code, cg->code, cg->codeLen);
|
|
mod->codeLen = cg->codeLen;
|
|
|
|
// Copy constant pool (share string refs)
|
|
if (cg->constCount > 0) {
|
|
mod->constants = (BasStringT **)malloc(cg->constCount * sizeof(BasStringT *));
|
|
|
|
if (!mod->constants) {
|
|
free(mod->code);
|
|
free(mod);
|
|
return NULL;
|
|
}
|
|
|
|
for (int32_t i = 0; i < cg->constCount; i++) {
|
|
mod->constants[i] = basStringRef(cg->constants[i]);
|
|
}
|
|
}
|
|
|
|
mod->constCount = cg->constCount;
|
|
mod->globalCount = cg->globalCount;
|
|
mod->entryPoint = 0;
|
|
|
|
// Copy data pool
|
|
if (cg->dataCount > 0) {
|
|
mod->dataPool = (BasValueT *)malloc(cg->dataCount * sizeof(BasValueT));
|
|
|
|
if (!mod->dataPool) {
|
|
free(mod->constants);
|
|
free(mod->code);
|
|
free(mod);
|
|
return NULL;
|
|
}
|
|
|
|
for (int32_t i = 0; i < cg->dataCount; i++) {
|
|
mod->dataPool[i] = basValCopy(cg->dataPool[i]);
|
|
}
|
|
}
|
|
|
|
mod->dataCount = cg->dataCount;
|
|
|
|
// Copy form variable info
|
|
if (cg->formVarInfoCount > 0) {
|
|
mod->formVarInfo = (BasFormVarInfoT *)malloc(cg->formVarInfoCount * sizeof(BasFormVarInfoT));
|
|
|
|
if (mod->formVarInfo) {
|
|
memcpy(mod->formVarInfo, cg->formVarInfo, cg->formVarInfoCount * sizeof(BasFormVarInfoT));
|
|
}
|
|
|
|
mod->formVarInfoCount = cg->formVarInfoCount;
|
|
}
|
|
|
|
// Copy debug variable info
|
|
if (cg->debugVarCount > 0) {
|
|
mod->debugVars = (BasDebugVarT *)malloc(cg->debugVarCount * sizeof(BasDebugVarT));
|
|
|
|
if (mod->debugVars) {
|
|
memcpy(mod->debugVars, cg->debugVars, cg->debugVarCount * sizeof(BasDebugVarT));
|
|
}
|
|
|
|
mod->debugVarCount = cg->debugVarCount;
|
|
}
|
|
|
|
// Copy UDT type definitions for debugger
|
|
if (cg->debugUdtDefCount > 0) {
|
|
mod->debugUdtDefs = (BasDebugUdtDefT *)malloc(cg->debugUdtDefCount * sizeof(BasDebugUdtDefT));
|
|
|
|
if (mod->debugUdtDefs) {
|
|
for (int32_t i = 0; i < cg->debugUdtDefCount; i++) {
|
|
mod->debugUdtDefs[i] = cg->debugUdtDefs[i];
|
|
mod->debugUdtDefs[i].fields = NULL;
|
|
|
|
if (cg->debugUdtDefs[i].fieldCount > 0 && cg->debugUdtDefs[i].fields) {
|
|
mod->debugUdtDefs[i].fields = (BasDebugFieldT *)malloc(
|
|
cg->debugUdtDefs[i].fieldCount * sizeof(BasDebugFieldT));
|
|
|
|
if (mod->debugUdtDefs[i].fields) {
|
|
memcpy(mod->debugUdtDefs[i].fields, cg->debugUdtDefs[i].fields,
|
|
cg->debugUdtDefs[i].fieldCount * sizeof(BasDebugFieldT));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mod->debugUdtDefCount = cg->debugUdtDefCount;
|
|
}
|
|
|
|
return mod;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodeGenBuildModuleWithProcs
|
|
// ============================================================
|
|
|
|
BasModuleT *basCodeGenBuildModuleWithProcs(BasCodeGenT *cg, void *symtab) {
|
|
BasModuleT *mod = basCodeGenBuildModule(cg);
|
|
|
|
if (!mod || !symtab) {
|
|
return mod;
|
|
}
|
|
|
|
BasSymTabT *tab = (BasSymTabT *)symtab;
|
|
|
|
// Count SUB/FUNCTION entries
|
|
int32_t procCount = 0;
|
|
|
|
for (int32_t i = 0; i < tab->count; i++) {
|
|
BasSymbolT *s = &tab->symbols[i];
|
|
|
|
if ((s->kind == SYM_SUB || s->kind == SYM_FUNCTION) && s->isDefined && !s->isExtern) {
|
|
procCount++;
|
|
}
|
|
}
|
|
|
|
if (procCount == 0) {
|
|
return mod;
|
|
}
|
|
|
|
mod->procs = (BasProcEntryT *)malloc(procCount * sizeof(BasProcEntryT));
|
|
|
|
if (!mod->procs) {
|
|
return mod;
|
|
}
|
|
|
|
int32_t idx = 0;
|
|
|
|
for (int32_t i = 0; i < tab->count; i++) {
|
|
BasSymbolT *s = &tab->symbols[i];
|
|
|
|
if ((s->kind == SYM_SUB || s->kind == SYM_FUNCTION) && s->isDefined && !s->isExtern) {
|
|
BasProcEntryT *p = &mod->procs[idx++];
|
|
strncpy(p->name, s->name, BAS_MAX_PROC_NAME - 1);
|
|
p->name[BAS_MAX_PROC_NAME - 1] = '\0';
|
|
p->codeAddr = s->codeAddr;
|
|
p->paramCount = s->paramCount;
|
|
p->localCount = s->localCount;
|
|
p->returnType = s->dataType;
|
|
p->isFunction = (s->kind == SYM_FUNCTION);
|
|
}
|
|
}
|
|
|
|
mod->procCount = idx;
|
|
return mod;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodeGenFree
|
|
// ============================================================
|
|
|
|
void basCodeGenFree(BasCodeGenT *cg) {
|
|
for (int32_t i = 0; i < cg->constCount; i++) {
|
|
basStringUnref(cg->constants[i]);
|
|
}
|
|
|
|
for (int32_t i = 0; i < cg->dataCount; i++) {
|
|
basValRelease(&cg->dataPool[i]);
|
|
}
|
|
|
|
arrfree(cg->code);
|
|
arrfree(cg->constants);
|
|
arrfree(cg->dataPool);
|
|
arrfree(cg->formVarInfo);
|
|
arrfree(cg->debugVars);
|
|
|
|
for (int32_t i = 0; i < cg->debugUdtDefCount; i++) {
|
|
free(cg->debugUdtDefs[i].fields);
|
|
}
|
|
|
|
arrfree(cg->debugUdtDefs);
|
|
cg->code = NULL;
|
|
cg->constants = NULL;
|
|
cg->dataPool = NULL;
|
|
cg->formVarInfo = NULL;
|
|
cg->debugVars = NULL;
|
|
cg->debugUdtDefs = NULL;
|
|
cg->constCount = 0;
|
|
cg->dataCount = 0;
|
|
cg->codeLen = 0;
|
|
cg->formVarInfoCount = 0;
|
|
cg->debugVarCount = 0;
|
|
cg->debugUdtDefCount = 0;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodeGenInit
|
|
// ============================================================
|
|
|
|
void basCodeGenInit(BasCodeGenT *cg) {
|
|
memset(cg, 0, sizeof(*cg));
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basCodePos
|
|
// ============================================================
|
|
|
|
int32_t basCodePos(const BasCodeGenT *cg) {
|
|
return cg->codeLen;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basEmit8
|
|
// ============================================================
|
|
|
|
void basEmit8(BasCodeGenT *cg, uint8_t b) {
|
|
arrput(cg->code, b);
|
|
cg->codeLen = (int32_t)arrlen(cg->code);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basEmit16
|
|
// ============================================================
|
|
|
|
void basEmit16(BasCodeGenT *cg, int16_t v) {
|
|
uint8_t buf[2];
|
|
memcpy(buf, &v, 2);
|
|
arrput(cg->code, buf[0]);
|
|
arrput(cg->code, buf[1]);
|
|
cg->codeLen = (int32_t)arrlen(cg->code);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basEmitDouble
|
|
// ============================================================
|
|
|
|
void basEmitDouble(BasCodeGenT *cg, double v) {
|
|
uint8_t buf[sizeof(double)];
|
|
memcpy(buf, &v, sizeof(double));
|
|
|
|
for (int32_t i = 0; i < (int32_t)sizeof(double); i++) {
|
|
arrput(cg->code, buf[i]);
|
|
}
|
|
|
|
cg->codeLen = (int32_t)arrlen(cg->code);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basEmitFloat
|
|
// ============================================================
|
|
|
|
void basEmitFloat(BasCodeGenT *cg, float v) {
|
|
uint8_t buf[sizeof(float)];
|
|
memcpy(buf, &v, sizeof(float));
|
|
|
|
for (int32_t i = 0; i < (int32_t)sizeof(float); i++) {
|
|
arrput(cg->code, buf[i]);
|
|
}
|
|
|
|
cg->codeLen = (int32_t)arrlen(cg->code);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basEmitU16
|
|
// ============================================================
|
|
|
|
void basEmitU16(BasCodeGenT *cg, uint16_t v) {
|
|
uint8_t buf[2];
|
|
memcpy(buf, &v, 2);
|
|
arrput(cg->code, buf[0]);
|
|
arrput(cg->code, buf[1]);
|
|
cg->codeLen = (int32_t)arrlen(cg->code);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basModuleFindProc
|
|
// ============================================================
|
|
|
|
const BasProcEntryT *basModuleFindProc(const BasModuleT *mod, const char *name) {
|
|
if (!mod || !mod->procs || !name) {
|
|
return NULL;
|
|
}
|
|
|
|
for (int32_t i = 0; i < mod->procCount; i++) {
|
|
if (strcasecmp(mod->procs[i].name, name) == 0) {
|
|
return &mod->procs[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
// basPatch16
|
|
// ============================================================
|
|
|
|
void basPatch16(BasCodeGenT *cg, int32_t pos, int16_t val) {
|
|
if (pos >= 0 && pos + 2 <= cg->codeLen) {
|
|
memcpy(&cg->code[pos], &val, 2);
|
|
}
|
|
}
|