📄 compiler.cpp
字号:
#include "compiler.h"
#include "ctkparser.h"
#include "trampoline.h"
#include <malloc.h>
#ifndef MAX_PATH_LEN
#define MAX_PATH_LEN 1024
#endif
#define TOP(t) (t)->stack[(t)->sp-1]
#define POP(t) ((t)->sp -= 1)
#define POP2(t) ((t)->sp -= 2)
#define POP4(t) ((t)->sp -= 4)
//#define POP(t) assert(((t)->sp -= 1) >= 0)
//#define POP2(t) assert(((t)->sp -= 2) >= 0)
//#define POP4(t) assert(((t)->sp -= 4) >= 0)
#define PUSH(t, o) ((t)->stack[(t)->sp] = (o), (t)->sp += 1)
#define PUSH_CS(t, o) { \
CtkMemoryManager::instance.beginAccess(t); \
(t)->stack[(t)->sp] = (o); \
(t)->sp += 1; \
CtkMemoryManager::instance.endAccess(t); }
#define PUSH_CHECK(t, o) \
if ((t)->sp == (t)->stackSize) ctkThrowException("Stack overflow"); \
else ((t)->stack[(t)->sp] = (o), (t)->sp += 1)
#define PUSH_CHECK_CS(t, o) { \
CtkMemoryManager::instance.beginAccess(t); \
if ((t)->sp == (t)->stackSize) { \
ctkThrowException("Stack overflow"); \
} else { \
(t)->stack[(t)->sp] = (o); \
(t)->sp += 1; \
} \
CtkMemoryManager::instance.endAccess(t); }
#define THROW_EXCEPTION(x) (frame->call = this, ctkThrowException(x))
CtkCompiler CtkCompiler::instance;
CtkObject CtkExpr::getLvalue(CtkFrame* frame) {
THROW_EXCEPTION("Lvalue expected");
return ctkNull;
}
void CtkExpr::setLvalue(CtkFrame* frame, CtkObject) {
THROW_EXCEPTION("Lvalue expected");
}
void CtkExpr::assign(CtkFrame* frame, CtkObject) {
THROW_EXCEPTION("Lvalue expected");
}
bool CtkExpr::isLvalue() {
return false;
}
CtkFuncDef* CtkExpr::getFuncDef() {
return NULL;
}
void CtkExpr::compile(CtkCompiler*, CompileCtx) {}
CtkObject CtkExpr::getRvalue(CtkFrame* frame) {
PUSH_CHECK_CS(frame->thread, ctkNull);
return ctkNull;
}
void CtkStmt::compile(CtkCompiler*) {}
JumpType CtkStmt::execute(CtkFrame*) {
return JMP_NEXT;
}
JumpType CtkStmt::executeBlock(CtkFrame* frame) {
CtkStmt* stmt = this;
while (stmt != NULL) {
JumpType jump = stmt->execute(frame);
if (jump != JMP_NEXT) {
return jump;
}
stmt = stmt->next;
}
return JMP_NEXT;
}
#ifdef _WIN32
#define FILE_SEP '\\'
#else
#define FILE_SEP '/'
#endif
CtkModule::~CtkModule()
{
delete[] path;
delete ctx;
delete prog;
}
void CtkCompiler::reset()
{
CtkModule *mod, *nextMod;
for (mod = modules; mod != NULL; mod = nextMod) {
nextMod = mod->next;
delete mod;
}
CtkImport *imp, *nextImp;
for (imp = importList; imp != NULL; imp = nextImp) {
nextImp = imp->next;
delete imp;
}
program = NULL;
modules = NULL;
importList = NULL;
}
void CtkCompiler::compileBlock(CtkStmt* stmts) {
CtkSymbol* beforeSymbols = currCtx->symbols;
while (stmts != NULL) {
stmts->compile(this);
stmts = stmts->next;
}
CtkSymbol* afterSymbols = currCtx->symbols;
while (beforeSymbols != afterSymbols) {
CtkSymbol* symbol = afterSymbols;
afterSymbols = afterSymbols->next;
delete symbol;
}
currCtx->symbols = beforeSymbols;
}
extern int yyparse();
CtkModule* CtkCompiler::compile(char const* moduleName)
{
critical_section cs(mutex);
return compile(CtkSymbolTable::instance.add(moduleName, IDENT));
}
CtkModule* CtkCompiler::compile(CtkToken* moduleName)
{
critical_section cs(mutex);
for (CtkModule* module = modules; module != NULL; module = module->next) {
if (module->tkn->symId == moduleName->symId) {
return module;
}
}
for (CtkPath* p = path; p != NULL; p = p->next) {
char buf[MAX_PATH_LEN];
sprintf(buf, "%s%c%s.ctk", p->dir, FILE_SEP, moduleName->name);
FILE* f = fopen(buf, "r");
if (f != NULL) {
CtkScanner::instance.reset(f);
CtkModule* saveCurrModule = currModule;
CtkModule* curr = new CtkModule(moduleName, buf, modules);
currModule = modules = curr;
yyparse();
fclose(f);
program->compile(this);
int nVars = curr->prog->nVars;
CtkThread* currThread = ctkGetCurrentThread();
CtkMemoryManager::instance.beginAccess(currThread);
CtkFrame* frame =
(CtkFrame*)ctkAllocateObject(sizeof(CtkFrame)
+ (nVars-1)*sizeof(CtkObject), NULL);
frame->nVars = nVars;
frame->call = NULL;
frame->up = NULL;
memset(frame->vars, 0, nVars*sizeof(CtkObject));
curr->frame = frame;
CtkFunction* func = (CtkFunction*)ctkAllocateObject(sizeof(CtkFunction), NULL);
func->nestedLevel = 0;
func->nParams = 0;
func->nLocalVars = nVars;
func->next = NULL;
func->exterior = NULL;
func->stmts = curr->prog->stmts;
func->name = "<main>";
func->module = curr;
frame->func = func;
CtkFrame* topFrame = currThread->currFrame;
if (topFrame == NULL) {
currThread->currFrame = currThread->callStack = frame;
} else {
topFrame->up = frame;
}
frame->thread = currThread;
CtkMemoryManager::instance.endAccess(currThread);
curr->prog->execute(curr->frame);
currModule = saveCurrModule;
currThread->currFrame = topFrame;
if (topFrame != NULL) {
topFrame->up = NULL;
}
return curr;
}
}
return NULL;
}
void CtkCompiler::error(char const* errText, CtkNode* node)
{
ctkTrace("%s:%d: %s\n", currModule->path, node->line, errText);
exit(1);
}
void CtkProgram::compile(CtkCompiler* compiler) {
CtkImport* saveImport = compiler->importList;
compiler->importList = NULL;
for (CtkTokenList* imp = modules; imp != NULL; imp = imp->next) {
CtkModule* module = compiler->compile(imp->tkn);
if (module == NULL) {
char buf[256];
sprintf(buf, "Module %s not found", imp->tkn->name);
compiler->error(buf, stmts);
}
compiler->importList = new CtkImport(module, compiler->importList);
}
CtkContext* ctx = new CtkContext();
ctx->nSymbols = 0;
ctx->symbols = NULL;
ctx->exterior = NULL;
compiler->currCtx = ctx;
for (CtkStmt* stmt = stmts; stmt != NULL; stmt = stmt->next) {
stmt->compile(compiler);
}
nVars = ctx->nSymbols;
compiler->currModule->ctx = ctx;
compiler->currModule->prog = this;
compiler->importList = saveImport;
}
JumpType CtkProgram::execute(CtkFrame* frame)
{
CtkThread* currThread = (CtkThread*)ctkGetCurrentThread();
#ifdef USE_CTALK_EXCEPTION
try {
#else
jmp_buf buf;
jmp_buf* saveBuf = currThread->catchCtx;
currThread->catchCtx = &buf;
if (setjmp(buf) == 0) {
#endif
for (CtkStmt* stmt = stmts; stmt != NULL; stmt = stmt->next) {
JumpType jump = stmt->execute(frame);
switch (jump) {
case JMP_EXCEPTION:
ctkTrace("Uncatched exception %s\n",
IF_STRING(currThread->exceptionObject));
ctkPrintStackTrace(frame);
exit(1);
case JMP_RETURN:
#ifndef USE_CTALK_EXCEPTION
currThread->catchCtx = saveBuf;
#endif
return JMP_RETURN;
case JMP_NEXT:
continue;
default:
assert(false);
}
}
#ifndef USE_CTALK_EXCEPTION
currThread->catchCtx = saveBuf;
#endif
#ifdef USE_CTALK_EXCEPTION
} catch (CtkException const& x) {
#else
} else {
currThread->catchCtx = saveBuf;
#endif
ctkTrace("Uncatched exception %s\n",
IF_STRING(currThread->exceptionObject));
ctkPrintStackTrace(frame);
exit(1);
}
return JMP_NEXT;
}
void CtkIfStmt::compile(CtkCompiler* compiler)
{
cond->compile(compiler);
compiler->compileBlock(thenStmt);
if (elseStmt != NULL) {
compiler->compileBlock(elseStmt);
}
}
JumpType CtkIfStmt::execute(CtkFrame* frame)
{
if (cond->testCondition(frame)) {
return thenStmt->executeBlock(frame);
} else if (elseStmt != NULL) {
return elseStmt->executeBlock(frame);
} else {
return JMP_NEXT;
}
}
void CtkForStmt::compile(CtkCompiler* compiler)
{
if (init != NULL) {
init->compile(compiler);
}
if (cond != NULL) {
cond->compile(compiler);
}
if (inc != NULL) {
inc->compile(compiler);
}
compiler->compileBlock(body);
}
JumpType CtkForStmt::execute(CtkFrame* frame)
{
if (init != NULL) {
init->evaluate(frame);
}
while (cond == NULL || cond->testCondition(frame)) {
JumpType jump = body->executeBlock(frame);
switch (jump) {
case JMP_NEXT:
case JMP_CONTINUE:
break;
case JMP_BREAK:
return JMP_NEXT;
default:
return jump;
}
if (inc != NULL) {
inc->evaluate(frame);
}
}
return JMP_NEXT;
}
void CtkDoWhileStmt::compile(CtkCompiler* compiler)
{
compiler->compileBlock(body);
cond->compile(compiler);
}
JumpType CtkDoWhileStmt::execute(CtkFrame* frame)
{
do {
JumpType jump = body->executeBlock(frame);
switch (jump) {
case JMP_NEXT:
case JMP_CONTINUE:
break;
case JMP_BREAK:
return JMP_NEXT;
default:
return jump;
}
} while (cond->testCondition(frame));
return JMP_NEXT;
}
void CtkWhileStmt::compile(CtkCompiler* compiler)
{
cond->compile(compiler);
compiler->compileBlock(body);
}
JumpType CtkWhileStmt::execute(CtkFrame* frame)
{
while (cond->testCondition(frame)) {
JumpType jump = body->executeBlock(frame);
switch (jump) {
case JMP_NEXT:
case JMP_CONTINUE:
break;
case JMP_BREAK:
return JMP_NEXT;
default:
return jump;
}
}
return JMP_NEXT;
}
void CtkSwitchStmt::compile(CtkCompiler* compiler)
{
expr->compile(compiler);
for (CtkCaseStmt* cnode = cases; cnode != NULL; cnode = cnode->next) {
if (cnode->selector != NULL) {
cnode->selector->compile(compiler);
}
compiler->compileBlock(cnode->stmt);
}
}
JumpType CtkSwitchStmt::execute(CtkFrame* frame)
{
CtkCaseStmt* selectedNode = NULL;
CtkObject value = expr->getRvalue(frame);
for (CtkCaseStmt* cnode = cases; cnode != NULL; cnode = cnode->next) {
if (cnode->selector != NULL) {
CtkObject selector = cnode->selector->getRvalue(frame);
if (IS_EQUAL(selector, value)) {
POP(frame->thread);
selectedNode = cnode;
break;
}
POP(frame->thread);
} else {
selectedNode = cnode;
}
}
POP(frame->thread);
while (selectedNode != NULL) {
JumpType jump = selectedNode->stmt->executeBlock(frame);
switch (jump) {
case JMP_BREAK:
return JMP_NEXT;
case JMP_NEXT:
selectedNode = selectedNode->next;
continue;
default:
return jump;
}
}
return JMP_NEXT;
}
JumpType CtkBreakStmt::execute(CtkFrame* frame)
{
return JMP_BREAK;
}
JumpType CtkContinueStmt::execute(CtkFrame* frame)
{
return JMP_CONTINUE;
}
void CtkReturnStmt::compile(CtkCompiler* compiler)
{
if (expr != NULL) {
expr->compile(compiler);
}
}
JumpType CtkReturnStmt::execute(CtkFrame* frame)
{
if (expr != NULL) {
expr->getRvalue(frame);
} else {
PUSH_CHECK_CS(frame->thread, ctkNull);
}
return JMP_RETURN;
}
void CtkThrowStmt::compile(CtkCompiler* compiler)
{
except->compile(compiler);
}
JumpType CtkThrowStmt::execute(CtkFrame* frame)
{
CtkThread* currThread = frame->thread;
frame->call = this;
currThread->exceptionObject = except->getRvalue(frame);
POP(currThread);
return JMP_EXCEPTION;
}
void CtkTryStmt::compile(CtkCompiler* compiler)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -