306 lines
7.6 KiB
C++
306 lines
7.6 KiB
C++
#include "Compiler.h"
|
|
#include "Scanner.h"
|
|
#include "Parser.h"
|
|
#include "InterCodeGenerator.h"
|
|
#include "InterCode.h"
|
|
#include "ByteCodeGenerator.h"
|
|
#include "NativeCodeGenerator.h"
|
|
#include "Emulator.h"
|
|
#include <stdio.h>
|
|
|
|
Compiler::Compiler(void)
|
|
: mByteCodeFunctions(nullptr)
|
|
{
|
|
mErrors = new Errors();
|
|
mCompilationUnits = new CompilationUnits(mErrors);
|
|
mPreprocessor = new Preprocessor(mErrors);
|
|
mByteCodeGenerator = new ByteCodeGenerator();
|
|
mInterCodeGenerator = new InterCodeGenerator(mErrors);
|
|
mInterCodeModule = new InterCodeModule();
|
|
}
|
|
|
|
Compiler::~Compiler(void)
|
|
{
|
|
|
|
}
|
|
|
|
bool Compiler::ParseSource(void)
|
|
{
|
|
CompilationUnit* cunit;
|
|
while (mErrors->mErrorCount == 0 && (cunit = mCompilationUnits->PendingUnit()))
|
|
{
|
|
if (mPreprocessor->OpenSource(cunit->mFileName, true))
|
|
{
|
|
Scanner* scanner = new Scanner(mErrors, mPreprocessor);
|
|
Parser* parser = new Parser(mErrors, scanner, mCompilationUnits);
|
|
|
|
parser->Parse();
|
|
}
|
|
else
|
|
mErrors->Error(cunit->mLocation, "Could not open source file", cunit->mFileName);
|
|
}
|
|
|
|
return mErrors->mErrorCount == 0;
|
|
}
|
|
|
|
bool Compiler::GenerateCode(void)
|
|
{
|
|
Location loc;
|
|
|
|
Declaration* dcrtstart = mCompilationUnits->mStartup;
|
|
if (!dcrtstart)
|
|
{
|
|
mErrors->Error(loc, "Runtime startup not found");
|
|
return false;
|
|
}
|
|
|
|
mInterCodeGenerator->TranslateAssembler(mInterCodeModule, dcrtstart->mValue);
|
|
|
|
if (mErrors->mErrorCount != 0)
|
|
return false;
|
|
|
|
mByteCodeGenerator->WriteBasicHeader();
|
|
|
|
mInterCodeModule->UseGlobal(dcrtstart->mVarIndex);
|
|
|
|
InterVariable& vmain(mInterCodeModule->mGlobalVars[dcrtstart->mVarIndex]);
|
|
vmain.mAddr = mByteCodeGenerator->AddGlobal(vmain.mIndex, vmain.mIdent, vmain.mSize, vmain.mData, vmain.mAssembler);
|
|
vmain.mPlaced = true;
|
|
mByteCodeGenerator->SetBasicEntry(dcrtstart->mVarIndex);
|
|
|
|
mByteCodeGenerator->mProgEnd = 0x0a00;
|
|
mByteCodeGenerator->WriteByteCodeHeader();
|
|
|
|
const Ident* imain = Ident::Unique("main");
|
|
Declaration* dmain = mCompilationUnits->mScope->Lookup(imain);
|
|
if (!dmain)
|
|
{
|
|
mErrors->Error(loc, "main function not found");
|
|
return false;
|
|
}
|
|
|
|
InterCodeProcedure* iproc = mInterCodeGenerator->TranslateProcedure(mInterCodeModule, dmain->mValue, dmain);
|
|
|
|
if (mErrors->mErrorCount != 0)
|
|
return false;
|
|
|
|
for (int i = 0; i < mInterCodeModule->mProcedures.Size(); i++)
|
|
{
|
|
InterCodeProcedure* proc = mInterCodeModule->mProcedures[i];
|
|
|
|
proc->ReduceTemporaries();
|
|
|
|
#if _DEBUG
|
|
proc->Disassemble("final");
|
|
#endif
|
|
|
|
|
|
if (proc->mNativeProcedure)
|
|
{
|
|
NativeCodeProcedure* ncproc = new NativeCodeProcedure();
|
|
ncproc->Compile(mByteCodeGenerator, proc);
|
|
}
|
|
else
|
|
{
|
|
ByteCodeProcedure* bgproc = new ByteCodeProcedure();
|
|
|
|
bgproc->Compile(mByteCodeGenerator, proc);
|
|
mByteCodeFunctions.Push(bgproc);
|
|
|
|
#if _DEBUG
|
|
FILE* file;
|
|
fopen_s(&file, "r:\\cldiss.txt", "a");
|
|
|
|
if (file)
|
|
{
|
|
bgproc->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]);
|
|
fclose(file);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Compile used runtime functions
|
|
|
|
for (int i = 0; i < mByteCodeGenerator->mRelocations.Size(); i++)
|
|
{
|
|
if (mByteCodeGenerator->mRelocations[i].mRuntime)
|
|
{
|
|
Declaration* bcdec = mCompilationUnits->mRuntimeScope->Lookup(Ident::Unique(mByteCodeGenerator->mRelocations[i].mRuntime));
|
|
if (bcdec)
|
|
{
|
|
int index = -1, offset = 0;
|
|
if (bcdec->mType == DT_CONST_ASSEMBLER)
|
|
{
|
|
if (bcdec->mVarIndex < 0)
|
|
mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mValue);
|
|
index = bcdec->mVarIndex;
|
|
}
|
|
else if (bcdec->mType == DT_LABEL)
|
|
{
|
|
if (bcdec->mBase->mVarIndex < 0)
|
|
mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mBase->mValue);
|
|
index = bcdec->mBase->mVarIndex;
|
|
offset = bcdec->mInteger;
|
|
}
|
|
else if (bcdec->mType == DT_VARIABLE)
|
|
{
|
|
if (bcdec->mBase->mVarIndex < 0)
|
|
mInterCodeGenerator->InitGlobalVariable(mInterCodeModule, bcdec);
|
|
index = bcdec->mVarIndex;
|
|
offset = bcdec->mOffset + mByteCodeGenerator->mRelocations[i].mOffset;
|
|
}
|
|
assert(index > 0);
|
|
mInterCodeModule->UseGlobal(index);
|
|
|
|
mByteCodeGenerator->mRelocations[i].mIndex = index;
|
|
mByteCodeGenerator->mRelocations[i].mOffset = offset;
|
|
}
|
|
else
|
|
{
|
|
mErrors->Error(loc, "Missing runtime code implementation", mByteCodeGenerator->mRelocations[i].mRuntime);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compile used byte code functions
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
{
|
|
if (mByteCodeGenerator->mByteCodeUsed[i])
|
|
{
|
|
Declaration* bcdec = mCompilationUnits->mByteCodes[i];
|
|
if (bcdec)
|
|
{
|
|
int index = -1, offset = 0;
|
|
if (bcdec->mType == DT_CONST_ASSEMBLER)
|
|
{
|
|
if (bcdec->mVarIndex < 0)
|
|
mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mValue);
|
|
index = bcdec->mVarIndex;
|
|
}
|
|
else if (bcdec->mType == DT_LABEL)
|
|
{
|
|
if (bcdec->mBase->mVarIndex < 0)
|
|
mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mBase->mValue);
|
|
index = bcdec->mBase->mVarIndex;
|
|
offset = bcdec->mInteger;
|
|
}
|
|
|
|
assert(index > 0);
|
|
mInterCodeModule->UseGlobal(index);
|
|
|
|
ByteCodeRelocation rel;
|
|
rel.mAddr = 0x900 + 2 * i;
|
|
rel.mFunction = false;
|
|
rel.mLower = true;
|
|
rel.mUpper = true;
|
|
rel.mIndex = index;
|
|
rel.mOffset = offset;
|
|
rel.mRuntime = nullptr;
|
|
mByteCodeGenerator->mRelocations.Push(rel);
|
|
}
|
|
else
|
|
{
|
|
char n[10];
|
|
sprintf_s(n, "%d", i);
|
|
mErrors->Error(loc, "Missing byte code implementation", n);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < mInterCodeModule->mGlobalVars.Size(); i++)
|
|
{
|
|
InterVariable& var(mInterCodeModule->mGlobalVars[i]);
|
|
if (var.mUsed)
|
|
{
|
|
if (!var.mPlaced)
|
|
{
|
|
var.mAddr = mByteCodeGenerator->AddGlobal(var.mIndex, var.mIdent, var.mSize, var.mData, var.mAssembler);
|
|
var.mPlaced = true;
|
|
}
|
|
for (int j = 0; j < var.mNumReferences; j++)
|
|
{
|
|
InterVariable::Reference& ref(var.mReferences[j]);
|
|
ByteCodeRelocation rel;
|
|
rel.mAddr = var.mAddr + ref.mAddr;
|
|
rel.mFunction = ref.mFunction;
|
|
rel.mLower = ref.mLower;
|
|
rel.mUpper = ref.mUpper;
|
|
rel.mIndex = ref.mIndex;
|
|
rel.mOffset = ref.mOffset;
|
|
rel.mRuntime = nullptr;
|
|
mByteCodeGenerator->mRelocations.Push(rel);
|
|
}
|
|
}
|
|
}
|
|
|
|
mByteCodeGenerator->ResolveRelocations();
|
|
|
|
return mErrors->mErrorCount == 0;
|
|
}
|
|
|
|
bool Compiler::WriteOutputFile(const char* targetPath)
|
|
{
|
|
char prgPath[200], mapPath[200], asmPath[200];
|
|
|
|
strcpy_s(prgPath, targetPath);
|
|
int i = strlen(prgPath);
|
|
while (i > 0 && prgPath[i - 1] != '.')
|
|
i--;
|
|
prgPath[i] = 0;
|
|
|
|
strcpy_s(mapPath, prgPath);
|
|
strcpy_s(asmPath, prgPath);
|
|
|
|
strcat_s(prgPath, "prg");
|
|
strcat_s(mapPath, "map");
|
|
strcat_s(asmPath, "asm");
|
|
|
|
printf("Writing <%s>\n", prgPath);
|
|
mByteCodeGenerator->WritePRGFile(prgPath);
|
|
|
|
printf("Writing <%s>\n", mapPath);
|
|
mByteCodeGenerator->WriteMapFile(mapPath);
|
|
|
|
printf("Writing <%s>\n", asmPath);
|
|
{
|
|
FILE* file;
|
|
fopen_s(&file, asmPath, "w");
|
|
|
|
if (file)
|
|
{
|
|
for (int i = 0; i < mByteCodeFunctions.Size(); i++)
|
|
mByteCodeFunctions[i]->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]);
|
|
|
|
mByteCodeGenerator->WriteAsmFile(file);
|
|
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int Compiler::ExecuteCode(void)
|
|
{
|
|
Location loc;
|
|
|
|
printf("Running emulation...\n");
|
|
Emulator* emu = new Emulator();
|
|
memcpy(emu->mMemory + mByteCodeGenerator->mProgStart, mByteCodeGenerator->mMemory + mByteCodeGenerator->mProgStart, mByteCodeGenerator->mProgEnd - mByteCodeGenerator->mProgStart);
|
|
emu->mMemory[0x2d] = mByteCodeGenerator->mProgEnd & 0xff;
|
|
emu->mMemory[0x2e] = mByteCodeGenerator->mProgEnd >> 8;
|
|
int ecode = emu->Emulate(2061);
|
|
printf("Emulation result %d\n", ecode);
|
|
|
|
if (ecode != 0)
|
|
{
|
|
char sd[20];
|
|
sprintf_s(sd, "%d", ecode);
|
|
mErrors->Error(loc, "Execution failed", sd);
|
|
}
|
|
|
|
return ecode;
|
|
}
|