📄 compiler.cpp
字号:
CtkObject CtkEnvExpr::getLvalue(CtkFrame* frame)
{
CtkObject base = expr->getRvalue(frame);
char* value = getenv(TO_STRING(base));
CtkMemoryManager::instance.beginAccess(frame->thread);
PUSH_CHECK(frame->thread, ctkNull);
if (value == NULL) {
PUSH_CHECK(frame->thread, ctkNull);
CtkMemoryManager::instance.endAccess(frame->thread);
return ctkNull;
}
CtkObject result;
result.u.svalue = (char*)ctkAllocateObject(strlen(value)+1, NULL);
strcpy(result.u.svalue, value);
result.type = CTK_STRING;
PUSH_CHECK(frame->thread, result);
CtkMemoryManager::instance.endAccess(frame->thread);
return result;
}
void CtkEnvExpr::assign(CtkFrame* frame, CtkObject value)
{
CtkObject name = expr->getRvalue(frame);
char* nam = TO_STRING(name);
char* val = TO_STRING(value);
char* buf = (char*)alloca(strlen(nam) + strlen(val) + 2);
sprintf(buf, "%s=%s", nam, val);
putenv(buf);
POP(frame->thread);
}
void CtkEnvExpr::setLvalue(CtkFrame* frame, CtkObject value)
{
POP2(frame->thread);
char* nam = TO_STRING(TOP(frame->thread));
char* val = TO_STRING(value);
char* buf = (char*)alloca(strlen(nam) + strlen(val) + 2);
sprintf(buf, "%s=%s", nam, val);
putenv(buf);
POP(frame->thread);
}
bool CtkEnvExpr::isLvalue() {
return true;
}
void CtkArrayAccessExpr::compile(CtkCompiler* compiler, CompileCtx)
{
array->compile(compiler);
index->compile(compiler);
}
CtkObject CtkArrayAccessExpr::getRvalue(CtkFrame* frame)
{
CtkObject base = array->getRvalue(frame);
CtkObject key = index->getRvalue(frame);
if (base.type != CTK_ARRAY) {
THROW_EXCEPTION("Applying index to non-array type");
}
CtkObject result = ctkGetArray((CtkArray*)base.u.ptr, key);
POP2(frame->thread);
PUSH_CS(frame->thread, result);
return result;
}
CtkObject CtkArrayAccessExpr::getLvalue(CtkFrame* frame)
{
CtkObject base = array->getRvalue(frame);
CtkObject key = index->getRvalue(frame);
if (base.type != CTK_ARRAY) {
THROW_EXCEPTION("Applying index to non-array type");
}
CtkMemoryManager::instance.beginAccess(frame->thread);
CtkObject result = ctkGetArray((CtkArray*)base.u.ptr, key);
PUSH_CHECK(frame->thread, result);
CtkMemoryManager::instance.endAccess(frame->thread);
return result;
}
void CtkArrayAccessExpr::assign(CtkFrame* frame, CtkObject value)
{
CtkObject base = array->getRvalue(frame);
CtkObject key = index->getRvalue(frame);
if (base.type != CTK_ARRAY) {
THROW_EXCEPTION("Applying index to non-array type");
}
CtkMemoryManager::instance.beginAccess(frame->thread);
ctkPutArray((CtkArray*)base.u.ptr, key, value);
POP2(frame->thread);
CtkMemoryManager::instance.endAccess(frame->thread);
}
void CtkArrayAccessExpr::setLvalue(CtkFrame* frame, CtkObject value)
{
CtkMemoryManager::instance.beginAccess(frame->thread);
ctkPutArray((CtkArray*)frame->thread->stack[frame->thread->sp-3].u.ptr,
frame->thread->stack[frame->thread->sp-2], value);
frame->thread->sp -= 3;
CtkMemoryManager::instance.endAccess(frame->thread);
}
bool CtkArrayAccessExpr::isLvalue() {
return true;
}
void CtkFuncCallExpr::compile(CtkCompiler* compiler, CompileCtx)
{
func->compile(compiler);
int n = 0;
for (CtkExpr* arg = args; arg != NULL; arg = arg->next, n++) {
arg->compile(compiler);
}
CtkFuncDef* fdef = func->getFuncDef();
if (fdef != NULL && fdef->nParams != n) {
char buf[256];
sprintf(buf, "Too %s parameters for function %s",
fdef->nParams < n ? "many" : "few", fdef->tok->name);
compiler->error(buf, func);
}
nArgs = n;
}
static CtkObject ctkDllFunctionTrampoline(CtkPrimitive* prim, int nArgs, CtkObject* args)
{
if (nArgs >= MAX_DLL_FUNC_ARGS) {
char buf[256];
sprintf(buf, "Attempt to pass %d arguments to DLL function %s (limit for maximal number of arguments is %d)",
nArgs, prim->name, MAX_DLL_FUNC_ARGS);
ctkThrowException(buf);
}
int profile = 1 << nArgs;
for (int i = 0; i < nArgs; i++) {
switch (args[i].type) {
case CTK_INTEGER:
profile |= 1 << i;
break;
case CTK_REAL:
ctkThrowException("Real type of parameter is not supported for transparent DLL invocations");
}
}
void* rc = ctkTrampoline[profile]((void*)prim->func, args);
CtkObject result;
MAKE_RAW_POINTER(result, rc);
return result;
}
CtkObject CtkFuncCallExpr::getRvalue(CtkFrame* frame)
{
CtkObject f = func->getRvalue(frame);
if (f.type == CTK_STRING) {
CtkPrimitive* prim = ctkGetPrimitive(f.u.svalue);
if (prim != NULL) {
MAKE_PRIMITIVE(f, prim);
} else {
CtkFunction* func = ctkGetFunction(f.u.svalue);
if (func != NULL) {
MAKE_FUNCTION(f, func);
} else {
void* dllFunc = ctkFindFunction(f.u.svalue);
if (dllFunc != NULL) {
prim = new CtkPrimitive(f.u.svalue, (CtkPrimitiveFunc)dllFunc, false, &ctkDllFunctionTrampoline);
MAKE_PRIMITIVE(f, prim);
} else {
char buf[256];
sprintf(buf, "Function %s not found", f.u.svalue);
THROW_EXCEPTION(buf);
}
}
}
}
frame->call = func;
if (f.type == CTK_PRIMITIVE) {
CtkPrimitive* p = (CtkPrimitive*)f.u.ptr;
CtkObject* params = (CtkObject*)alloca(nArgs*sizeof(CtkObject));
int n = 0;
for (CtkExpr* arg = args; arg != NULL; arg = arg->next) {
params[n++] = arg->getRvalue(frame);
}
CtkMemoryManager::instance.beginAccess(frame->thread);
frame->thread->sp -= n + 1;
frame->thread->currFrame = frame;
CtkObject result = p->trampoline(p, n, params);
PUSH_CHECK(frame->thread, result);
CtkMemoryManager::instance.endAccess(frame->thread);
return result;
}
if (f.type != CTK_FUNCTION) {
THROW_EXCEPTION("Attempt to call non-function object");
}
CtkFunction* fp = (CtkFunction*)f.u.ptr;
if (fp->nParams != nArgs) {
THROW_EXCEPTION("Number of actual and formal parameters doesn't match");
}
CtkMemoryManager::instance.beginAccess(frame->thread);
CtkFrame* callFrame = ctkCreateFrame(fp);
CtkFrame* up = frame->up;
frame->up = callFrame;
callFrame->thread = frame->thread;
int n = 0;
for (CtkExpr* arg = args; arg != NULL; arg = arg->next) {
CtkObject value = arg->getRvalue(frame);
callFrame->vars[n++] = value;
POP(frame->thread);
}
CtkStmt* stmts = fp->stmts;
POP(frame->thread);
CtkMemoryManager::instance.endAccess(frame->thread);
switch (stmts->executeBlock(callFrame)) {
case JMP_RETURN:
frame->up = up;
return TOP(frame->thread);
case JMP_BREAK:
THROW_EXCEPTION("Invalid use of BREAK statement");
case JMP_CONTINUE:
THROW_EXCEPTION("Invalid use of CONTINUE statement");
case JMP_NEXT:
frame->up = up;
PUSH_CHECK_CS(frame->thread, ctkNull);
return ctkNull;
case JMP_EXCEPTION:
ctkPropagateException();
}
return ctkNull;
}
CtkObject CtkRunThreadExpr::getRvalue(CtkFrame* frame)
{
CtkObject f = func->getRvalue(frame);
if (f.type != CTK_FUNCTION) {
THROW_EXCEPTION("Attemp to call non-function object");
}
CtkFunction* fp = (CtkFunction*)f.u.ptr;
if (fp->nParams != nArgs) {
THROW_EXCEPTION("Number of actual and formal parameters doesn't match");
}
CtkFrame* callFrame = ctkCreateFrame(fp);
frame->call = func;
int n = 0;
CtkMemoryManager::instance.beginAccess(frame->thread);
for (CtkExpr* arg = args; arg != NULL; arg = arg->next) {
callFrame->vars[n++] = arg->getRvalue(frame);
}
CtkThread* thr = ctkCreateThread(ctkRunThread, callFrame, CTK_MIN_STACK_SIZE);
CtkObject result;
MAKE_THREAD(result, thr);
frame->thread->sp -= n + 1;
PUSH_CHECK(frame->thread, result);
CtkMemoryManager::instance.endAccess(frame->thread);
return result;
}
CtkObject CtkIntConst::getRvalue(CtkFrame* frame)
{
PUSH_CHECK_CS(frame->thread, value);
return value;
}
CtkObject CtkRealConst::getRvalue(CtkFrame* frame)
{
PUSH_CHECK_CS(frame->thread, value);
return value;
}
CtkObject CtkNullConst::getRvalue(CtkFrame* frame)
{
PUSH_CHECK_CS(frame->thread, ctkNull);
return ctkNull;
}
CtkObject CtkStringConst::getRvalue(CtkFrame* frame)
{
PUSH_CHECK_CS(frame->thread, value);
return value;
}
void CtkArrayElemExpr::compile(CtkCompiler* compiler, CompileCtx)
{
key->compile(compiler);
value->compile(compiler);
}
void CtkArrayConst::compile(CtkCompiler* compiler, CompileCtx)
{
int i = 0;
for (CtkArrayElemExpr* elem = elements; elem != NULL; i++, elem = (CtkArrayElemExpr*)elem->next) {
if (elem->key == NULL) {
elem->key = new CtkIntConst(i);
}
elem->compile(compiler, CC_RVALUE);
}
}
CtkObject CtkArrayConst::getRvalue(CtkFrame* frame)
{
CtkMemoryManager::instance.beginAccess(frame->thread);
CtkArray* array = ctkCreateArray();
for (CtkArrayElemExpr* elem = elements; elem != NULL; elem = (CtkArrayElemExpr*)elem->next) {
CtkObject key = elem->key->getRvalue(frame);
CtkObject value = elem->value->getRvalue(frame);
ctkPutArray(array, key, value);
POP2(frame->thread);
}
CtkObject result;
MAKE_ARRAY(result, array);
PUSH_CHECK(frame->thread, result);
CtkMemoryManager::instance.endAccess(frame->thread);
return result;
}
void CtkVariable::compile(CtkCompiler* compiler, CompileCtx cc)
{
int ctxLevel = 0;
CtkContext* ctx;
prim = NULL;
func = NULL;
for (ctx = compiler->currCtx; ctx != NULL; ctxLevel++, ctx = ctx->exterior) {
for (CtkSymbol* symb = ctx->symbols; symb != NULL; symb = symb->next) {
if (symb->tok == tok) {
level = ctxLevel;
index = symb->index;
func = symb->func;
module = NULL;
if (cc != CC_RVALUE && func != NULL) {
compiler->error("Function is not l-value", this);
}
return;
}
}
}
for (CtkImport* imp = compiler->importList; imp != NULL; imp = imp->next) {
ctx = imp->module->ctx;
for (CtkSymbol* symb = ctx->symbols; symb != NULL; symb = symb->next) {
if (symb->tok == tok) {
index = symb->index;
func = symb->func;
module = imp->module->frame;
if (cc != CC_RVALUE && func != NULL) {
compiler->error("Function is not l-value", this);
}
return;
}
}
}
// no symbol was found
if (cc == CC_RVALUE) {
if ((prim = ctkGetPrimitive(tok->name)) == NULL) {
void* dllFunc = ctkFindFunction(tok->name);
if (dllFunc != NULL) {
prim = new CtkPrimitive(tok->name, (CtkPrimitiveFunc)dllFunc, false, &ctkDllFunctionTrampoline);
} else {
char buf[256];
sprintf(buf, "Access to uninitialized variable %s", tok->name);
compiler->error(buf, this);
}
}
} else {
level = 0;
index = compiler->currCtx->nSymbols++;
module = NULL;
compiler->currCtx->symbols = new CtkSymbol(tok, index,
compiler->currCtx->symbols);
}
}
CtkFuncDef* CtkVariable::getFuncDef() {
return func;
}
CtkObject CtkVariable::getRvalue(CtkFrame* frame)
{
CtkObject result;
if (prim != NULL) {
MAKE_PRIMITIVE(result, prim);
} else if (module != NULL) {
result = module->vars[index];
} else {
CtkFrame* scope = frame;
for (int n = level; --n >= 0; scope = scope->func->exterior);
result = scope->vars[index];
}
PUSH_CHECK_CS(frame->thread, result);
return result;
}
CtkObject CtkVariable::getLvalue(CtkFrame* frame)
{
PUSH_CHECK_CS(frame->thread, ctkNull);
PUSH_CHECK_CS(frame->thread, ctkNull);
return getRvalue(frame);
}
void CtkVariable::assign(CtkFrame* frame, CtkObject value)
{
CtkMemoryManager::instance.beginAccess(frame->thread);
if (module != NULL) {
module->vars[index] = value;
} else {
CtkFrame* scope = frame;
for (int n = level; --n >= 0; scope = scope->func->exterior);
scope->vars[index] = value;
}
CtkMemoryManager::instance.endAccess(frame->thread);
}
bool CtkVariable::isLvalue()
{
return true;
}
void CtkVariable::setLvalue(CtkFrame* frame, CtkObject value)
{
assign(frame, value);
frame->thread->sp -= 3;
}
void CtkFuncDef::compile(CtkCompiler* compiler)
{
CtkContext* exterior = compiler->currCtx;
for (CtkContext* cpp = compiler->currCtx; cpp != NULL; cpp = cpp->exterior) {
for (CtkSymbol* symb = cpp->symbols; symb != NULL; symb = symb->next) {
if (symb->tok == tok) {
compiler->error("Symbol is already defined", this);
return;
}
}
}
index = compiler->currCtx->nSymbols++;
CtkSymbol* symb = new CtkSymbol(tok, index, compiler->currCtx->symbols);
symb->func = this;
compiler->currCtx->symbols = symb;
CtkContext ctx;
CtkSymbol* next = NULL;
int n = 0;
for (CtkTokenList* p = params; p != NULL; p = p->next) {
next = new CtkSymbol(p->tkn, n++, next);
}
ctx.nSymbols = nParams = n;
ctx.symbols = next;
ctx.exterior = exterior;
compiler->currCtx = &ctx;
compiler->currLevel += 1;
compiler->compileBlock(stmts);
compiler->currCtx = exterior;
compiler->currLevel -= 1;
nLocals = ctx.nSymbols;
}
JumpType CtkFuncDef::execute(CtkFrame* frame)
{
CtkMemoryManager::instance.beginAccess(frame->thread);
CtkFunction* func = (CtkFunction*)ctkAllocateObject(sizeof(CtkFunction), NULL);
func->stmts = stmts;
func->nestedLevel = frame->func->nestedLevel + 1;
func->nParams = nParams;
func->nLocalVars = nLocals;
func->module = frame->func->module;
func->name = tok->name;
func->exterior = frame;
if (func->nestedLevel == 1) {
ctkAddFunction(func);
}
CtkObject f;
MAKE_FUNCTION(f, func);
frame->vars[index] = f;
CtkMemoryManager::instance.endAccess(frame->thread);
return JMP_NEXT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -