DVX_GUI/apps/dvxbasic/compiler/codegen.c

320 lines
8 KiB
C

// codegen.c -- DVX BASIC p-code emitter implementation
#include "codegen.h"
#include "symtab.h"
#include "opcodes.h"
#include <stdlib.h>
#include <string.h>
#include <strings.h>
// ============================================================
// basAddData
// ============================================================
bool basAddData(BasCodeGenT *cg, BasValueT val) {
if (cg->dataCount >= BAS_MAX_CONSTANTS) {
return false;
}
cg->dataPool[cg->dataCount++] = basValCopy(val);
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;
}
}
if (cg->constCount >= BAS_MAX_CONSTANTS) {
return 0;
}
uint16_t idx = (uint16_t)cg->constCount;
cg->constants[cg->constCount++] = basStringNew(text, len);
return idx;
}
// ============================================================
// 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;
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->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]);
}
cg->constCount = 0;
cg->dataCount = 0;
cg->codeLen = 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) {
if (cg->codeLen < BAS_MAX_CODE) {
cg->code[cg->codeLen++] = b;
}
}
// ============================================================
// basEmit16
// ============================================================
void basEmit16(BasCodeGenT *cg, int16_t v) {
if (cg->codeLen + 2 <= BAS_MAX_CODE) {
memcpy(&cg->code[cg->codeLen], &v, 2);
cg->codeLen += 2;
}
}
// ============================================================
// basEmitDouble
// ============================================================
void basEmitDouble(BasCodeGenT *cg, double v) {
if (cg->codeLen + (int32_t)sizeof(double) <= BAS_MAX_CODE) {
memcpy(&cg->code[cg->codeLen], &v, sizeof(double));
cg->codeLen += (int32_t)sizeof(double);
}
}
// ============================================================
// basEmitFloat
// ============================================================
void basEmitFloat(BasCodeGenT *cg, float v) {
if (cg->codeLen + (int32_t)sizeof(float) <= BAS_MAX_CODE) {
memcpy(&cg->code[cg->codeLen], &v, sizeof(float));
cg->codeLen += (int32_t)sizeof(float);
}
}
// ============================================================
// basEmitU16
// ============================================================
void basEmitU16(BasCodeGenT *cg, uint16_t v) {
if (cg->codeLen + 2 <= BAS_MAX_CODE) {
memcpy(&cg->code[cg->codeLen], &v, 2);
cg->codeLen += 2;
}
}
// ============================================================
// 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;
}
// ============================================================
// basModuleFree
// ============================================================
void basModuleFree(BasModuleT *mod) {
if (!mod) {
return;
}
free(mod->code);
if (mod->constants) {
for (int32_t i = 0; i < mod->constCount; i++) {
basStringUnref(mod->constants[i]);
}
free(mod->constants);
}
if (mod->dataPool) {
for (int32_t i = 0; i < mod->dataCount; i++) {
basValRelease(&mod->dataPool[i]);
}
free(mod->dataPool);
}
free(mod->procs);
free(mod);
}
// ============================================================
// basPatch16
// ============================================================
void basPatch16(BasCodeGenT *cg, int32_t pos, int16_t val) {
if (pos >= 0 && pos + 2 <= cg->codeLen) {
memcpy(&cg->code[pos], &val, 2);
}
}