| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- #include "Compiler.h"
- #include <setjmp.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "Code.h"
- #include "Constants.h"
- #include "Memory.h"
- #include "SystemFunctions.h"
- typedef struct Variable Variable;
- struct Variable {
- Variable* next;
- i32 index;
- char name[];
- };
- typedef struct Function Function;
- struct Function {
- Function* next;
- i32 address;
- i32 valueAddress;
- i32 arguments;
- char name[];
- };
- typedef struct Return Return;
- struct Return {
- Return* next;
- i32 address;
- bool hasArgument;
- };
- typedef struct {
- Tokenizer* tokenizer;
- Code* code;
- Error error;
- int line;
- jmp_buf jump;
- Variable* variables;
- Function* functions;
- Return* returns;
- bool inFunction;
- } Context;
- #define THROW_ERROR(format, ...) \
- snprintf( \
- c->error.text, sizeof(c->error.text), "Line %d | " format, \
- c->line __VA_OPT__(, ) __VA_ARGS__); \
- longjmp(c->jump, 1)
- [[noreturn]] static void throwOutOfCodeMemory(Context* c) {
- THROW_ERROR("Too less memory for code");
- }
- static void codePushInstruction(Context* c, Instruction i) {
- if(bufferWriteU8(&c->code->code, i)) {
- throwOutOfCodeMemory(c);
- }
- }
- static void codePushI32(Context* c, i32 i) {
- if(bufferWriteI32(&c->code->code, i)) {
- throwOutOfCodeMemory(c);
- }
- }
- static void codePushConstantString(Context* c, const char* s) {
- if(bufferWriteString(&c->code->code, s)) {
- throwOutOfCodeMemory(c);
- }
- }
- static size_t codeGetWritePosition(const Context* c) {
- return c->code->code.writeIndex;
- }
- static size_t codePushInstructionI32(Context* c, Instruction i, i32 v) {
- codePushInstruction(c, i);
- size_t pos = codeGetWritePosition(c);
- codePushI32(c, v);
- return pos;
- }
- static void codeRewriteI32(Context* c, size_t pos, i32 i) {
- size_t oldPos = codeGetWritePosition(c);
- c->code->code.writeIndex = pos;
- codePushI32(c, i);
- c->code->code.writeIndex = oldPos;
- }
- static bool hasLocalVar(const Context* c) {
- return c->variables != nullptr && c->variables->index < 0;
- }
- static i32 addVariable(Context* c, const char* name, bool forceGlobal) {
- for(Variable* v = c->variables; v != nullptr; v = v->next) {
- if(!forceGlobal && c->inFunction && v->index >= 0) {
- break;
- }
- if(strcmp(v->name, name) == 0) {
- return v->index;
- }
- }
- size_t l = strlen(name) + 1;
- Variable* v = memoryAllocate(sizeof(Variable) + l);
- if(v == nullptr) {
- THROW_ERROR("Too less memory for variables");
- }
- v->next = c->variables;
- if(c->inFunction) {
- v->index = hasLocalVar(c) ? c->variables->index - 1 : -1;
- } else {
- v->index = c->variables != nullptr ? c->variables->index + 1 : 0;
- }
- memcpy(v->name, name, l);
- c->variables = v;
- return v->index;
- }
- static void addRawFunction(
- Context* c, const char* name, i32 address, i32 valueAddress,
- i32 arguments) {
- size_t l = strlen(name) + 1;
- Function* f = memoryAllocate(sizeof(Function) + l);
- if(f == nullptr) {
- THROW_ERROR("Too less memory for functions");
- }
- f->next = c->functions;
- f->address = address;
- f->valueAddress = valueAddress;
- f->arguments = arguments;
- memcpy(f->name, name, l);
- c->functions = f;
- }
- static void addFunction(
- Context* c, const char* name, i32 address, i32 arguments) {
- for(Function* f = c->functions; f != nullptr; f = f->next) {
- if(strcmp(f->name, name) != 0) {
- continue;
- } else if(f->address >= 0) {
- THROW_ERROR("Function '%s' registered again", name);
- } else if(f->arguments != arguments) {
- THROW_ERROR("Function '%s' with inconsistent arguments", name);
- }
- f->address = address;
- codeRewriteI32(c, (size_t)f->valueAddress, address);
- }
- addRawFunction(c, name, address, -1, arguments);
- }
- static i32 addCallFunction(
- Context* c, const char* name, i32 address, i32 arguments) {
- for(Function* f = c->functions; f != nullptr; f = f->next) {
- if(strcmp(f->name, name) == 0 && f->address >= 0) {
- if(f->arguments != arguments) {
- THROW_ERROR("Function '%s' with inconsistent arguments", name);
- }
- return f->address;
- }
- }
- addRawFunction(c, name, -1, address, arguments);
- return -1;
- }
- static void checkForInvalidFunctions(Context* c) {
- for(Function* f = c->functions; f != nullptr; f = f->next) {
- if(f->address < 0) {
- THROW_ERROR("Unmapped function call '%s'", f->name);
- }
- }
- }
- static void addReturn(Context* c, i32 address, bool hasArgument) {
- if(c->returns != nullptr && c->returns->hasArgument != hasArgument) {
- THROW_ERROR("Inconsistent returns in function");
- }
- Return* r = memoryAllocate(sizeof(Return));
- if(r == nullptr) {
- THROW_ERROR("Too less memory for returns");
- }
- r->next = c->returns;
- r->hasArgument = hasArgument;
- r->address = address;
- c->returns = r;
- }
- #define CLEAN_LIST(Type, field) \
- do { \
- Type* v = c->field; \
- while(v != nullptr) { \
- Type* next = v->next; \
- memoryFree(v); \
- v = next; \
- } \
- c->field = nullptr; \
- } while(false)
- static void cleanReturns(Context* c) {
- CLEAN_LIST(Return, returns);
- }
- static void cleanContext(Context* c) {
- CLEAN_LIST(Variable, variables);
- CLEAN_LIST(Function, functions);
- cleanReturns(c);
- }
- [[noreturn]] static void unexpectedToken(Context* c, Token token, int line) {
- char buffer[128];
- tokenizerPrintToken(&token, buffer, sizeof(buffer));
- THROW_ERROR("Unexpected %s token %d", buffer, line);
- }
- static Token consumeToken(Context* c, TokenType type) {
- Token actual = tokenizerNext(c->tokenizer);
- if(actual.type != type) {
- unexpectedToken(c, actual, __LINE__);
- }
- return actual;
- }
- static bool peekToken(Context* c, TokenType type) {
- return tokenizerPeek(c->tokenizer).type == type;
- }
- static bool consumeTokenIf(Context* c, TokenType type) {
- if(peekToken(c, type)) {
- consumeToken(c, type);
- return true;
- }
- return false;
- }
- static void consumeNewline(Context* c) {
- if(peekToken(c, TT_INVALID)) {
- return;
- }
- consumeToken(c, TT_NEWLINE);
- c->line++;
- }
- static void compileReadVariable(Context* c, Token token, bool forceGlobal) {
- i32 index = addVariable(c, token.stringValue, forceGlobal);
- codePushInstructionI32(c, READ_VARIABLE, index);
- }
- static void compileCallFunction(Context* c, Token t);
- static void compileConstant(Context* c) {
- Token token = tokenizerNext(c->tokenizer);
- if(token.type == TT_STRING) {
- codePushInstruction(c, PUSH_CONSTANT_STRING);
- codePushConstantString(c, token.stringValue);
- } else if(token.type == TT_INT32) {
- codePushInstructionI32(c, PUSH_INT32, token.intValue);
- } else if(token.type == TT_LITERAL) {
- if(peekToken(c, TT_OPEN_ROUND_BRACKET)) {
- compileCallFunction(c, token);
- } else {
- compileReadVariable(c, token, false);
- }
- } else if(token.type == TT_DOLLAR) {
- token = consumeToken(c, TT_LITERAL);
- compileReadVariable(c, token, true);
- } else {
- unexpectedToken(c, token, __LINE__);
- }
- }
- static void compileUnary(Context* c) {
- if(consumeTokenIf(c, TT_NOT)) {
- compileUnary(c);
- codePushInstruction(c, NOT);
- } else {
- compileConstant(c);
- }
- }
- static void compileMul(Context* c) {
- compileUnary(c);
- while(true) {
- if(consumeTokenIf(c, TT_MULTIPLY)) {
- compileUnary(c);
- codePushInstruction(c, MUL);
- } else if(consumeTokenIf(c, TT_DIVIDE)) {
- compileUnary(c);
- codePushInstruction(c, DIV);
- } else {
- break;
- }
- }
- }
- static void compileAdd(Context* c) {
- compileMul(c);
- while(true) {
- if(consumeTokenIf(c, TT_ADD)) {
- compileMul(c);
- codePushInstruction(c, ADD);
- } else if(consumeTokenIf(c, TT_SUBTRACT)) {
- compileMul(c);
- codePushInstruction(c, SUB);
- } else {
- break;
- }
- }
- }
- static void compileCompare(Context* c) {
- compileAdd(c);
- while(true) {
- if(consumeTokenIf(c, TT_EQUAL)) {
- compileAdd(c);
- codePushInstruction(c, EQUAL);
- } else if(consumeTokenIf(c, TT_NOT_EQUAL)) {
- compileAdd(c);
- codePushInstruction(c, NOT_EQUAL);
- } else if(consumeTokenIf(c, TT_GREATER)) {
- compileAdd(c);
- codePushInstruction(c, GREATER);
- } else if(consumeTokenIf(c, TT_SMALLER)) {
- compileAdd(c);
- codePushInstruction(c, SMALLER);
- } else if(consumeTokenIf(c, TT_GREATER_OR_EQUAL)) {
- compileAdd(c);
- codePushInstruction(c, GREATER_OR_EQUAL);
- } else if(consumeTokenIf(c, TT_SMALLER_OR_EQUAL)) {
- compileAdd(c);
- codePushInstruction(c, SMALLER_OR_EQUAL);
- } else {
- break;
- }
- }
- }
- static void compileLogical(Context* c) {
- compileCompare(c);
- while(true) {
- if(consumeTokenIf(c, TT_AND)) {
- compileCompare(c);
- codePushInstruction(c, AND);
- } else if(consumeTokenIf(c, TT_OR)) {
- compileCompare(c);
- codePushInstruction(c, OR);
- } else {
- break;
- }
- }
- }
- static void compileExpression(Context* c) {
- compileLogical(c);
- }
- static void compileLine(Context* c, Token token);
- static void compileIf(Context* c) {
- compileExpression(c);
- size_t posIndex = codePushInstructionI32(c, JUMP_ON_0, 0);
- consumeNewline(c);
- while(!peekToken(c, TT_END)) {
- compileLine(c, tokenizerNext(c->tokenizer));
- }
- consumeToken(c, TT_END);
- consumeNewline(c);
- codeRewriteI32(c, posIndex, (i32)codeGetWritePosition(c));
- }
- static void compileSetVariable(Context* c, const char* name, bool forceGlobal) {
- consumeToken(c, TT_ASSIGN);
- compileExpression(c);
- codePushInstructionI32(c, SET_VARIABLE, addVariable(c, name, forceGlobal));
- }
- static i32 compileFunctionArguments(Context* c) {
- consumeToken(c, TT_OPEN_ROUND_BRACKET);
- i32 vars = 0;
- while(!peekToken(c, TT_CLOSE_ROUND_BRACKET)) {
- if(vars > 0) {
- consumeToken(c, TT_COMMA);
- }
- Token varToken = consumeToken(c, TT_LITERAL);
- addVariable(c, varToken.stringValue, false);
- vars++;
- }
- consumeToken(c, TT_CLOSE_ROUND_BRACKET);
- return vars;
- }
- static void rewriteReturns(Context* c, i32 address) {
- for(Return* r = c->returns; r != nullptr; r = r->next) {
- codeRewriteI32(c, (size_t)r->address, address);
- }
- cleanReturns(c);
- }
- static void compileFunction(Context* c) {
- if(c->inFunction) {
- THROW_ERROR("Functions in functions are not allowed");
- }
- c->inFunction = true;
- size_t functionEnd = codePushInstructionI32(c, JUMP, 0);
- i32 functionStart = (i32)codeGetWritePosition(c);
- Token t = consumeToken(c, TT_LITERAL);
- size_t stackVarsLoc = codePushInstructionI32(c, PUSH_STACK_VARIABLES, 0);
- Variable* resetVar = c->variables;
- i32 vars = compileFunctionArguments(c);
- addFunction(c, t.stringValue, functionStart, vars);
- while(!peekToken(c, TT_END)) {
- compileLine(c, tokenizerNext(c->tokenizer));
- }
- consumeToken(c, TT_END);
- i32 popVars = hasLocalVar(c) ? -c->variables->index : 0;
- codePushInstructionI32(c, PUSH_INT32, 0);
- codePushInstructionI32(c, RETURN_VALUE, popVars);
- rewriteReturns(c, popVars);
- codeRewriteI32(c, stackVarsLoc, popVars - vars);
- while(c->variables != resetVar) {
- Variable* next = c->variables->next;
- memoryFree(c->variables);
- c->variables = next;
- }
- codeRewriteI32(c, functionEnd, (i32)codeGetWritePosition(c));
- c->inFunction = false;
- }
- static i32 compileCallFunctionArguments(Context* c) {
- consumeToken(c, TT_OPEN_ROUND_BRACKET);
- i32 offset = 0;
- while(!peekToken(c, TT_CLOSE_ROUND_BRACKET)) {
- if(offset > 0) {
- consumeToken(c, TT_COMMA);
- }
- offset++;
- compileExpression(c);
- }
- consumeToken(c, TT_CLOSE_ROUND_BRACKET);
- return offset;
- }
- static void compileCallFunction(Context* c, Token t) {
- i32 index = getSystemFunctionIndex(t.stringValue);
- if(index >= 0) {
- i32 args = compileCallFunctionArguments(c);
- i32 wantedArgs = getSystemFunctionArguments(index);
- if(wantedArgs >= 0 && args != wantedArgs) {
- THROW_ERROR(
- "System function '%s' called with invalid amount of arguments",
- t.stringValue);
- }
- static_assert(MAX_SYSTEM_FUNCTION_ARGUMENTS < (1 << 8));
- codePushInstructionI32(c, CALL_SYSTEM, (index << 8) | args);
- } else {
- // used to store return address and variable index
- codePushInstructionI32(c, PUSH_INT32, 0);
- codePushInstructionI32(c, PUSH_INT32, 0);
- i32 offset = compileCallFunctionArguments(c);
- codePushInstruction(c, JUMP_SUB);
- size_t pos = codeGetWritePosition(c);
- codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos, offset));
- codePushI32(c, offset);
- }
- }
- static void compileReturn(Context* c) {
- if(peekToken(c, TT_NEWLINE)) {
- consumeNewline(c);
- codePushInstructionI32(c, PUSH_INT32, 0);
- } else {
- compileExpression(c);
- }
- i32 address = (i32)codePushInstructionI32(c, RETURN_VALUE, 0);
- addReturn(c, address, true);
- }
- static void compileLineLiteral(Context* c, Token token) {
- const char* s = token.stringValue;
- if(peekToken(c, TT_ASSIGN)) {
- compileSetVariable(c, s, false);
- } else if(peekToken(c, TT_OPEN_ROUND_BRACKET)) {
- compileCallFunction(c, token);
- codePushInstruction(c, POP);
- } else {
- THROW_ERROR("Unexpected literal(%s)", s);
- }
- }
- static void compileLine(Context* c, Token token) {
- if(token.type == TT_NEWLINE) {
- c->line++;
- } else if(token.type == TT_IF) {
- compileIf(c);
- } else if(token.type == TT_FUNCTION) {
- compileFunction(c);
- } else if(token.type == TT_RETURN) {
- compileReturn(c);
- } else if(token.type == TT_DOLLAR) {
- token = consumeToken(c, TT_LITERAL);
- compileSetVariable(c, token.stringValue, true);
- } else if(token.type != TT_LITERAL) {
- unexpectedToken(c, token, __LINE__);
- } else {
- compileLineLiteral(c, token);
- }
- }
- static void parseTokens(Context* c) {
- codeReset(c->code);
- size_t stackVarsLoc = codePushInstructionI32(c, PUSH_STACK_VARIABLES, 0);
- while(true) {
- Token token = tokenizerNext(c->tokenizer);
- if(token.type == TT_INVALID) {
- break;
- }
- compileLine(c, token);
- }
- if(c->variables != nullptr) {
- codeRewriteI32(c, stackVarsLoc, c->variables->index + 1);
- }
- checkForInvalidFunctions(c);
- }
- Error compileFile(Tokenizer* t, Code* code) {
- Context c = {.tokenizer = t, .code = code, .line = 1};
- if(!setjmp(c.jump)) {
- parseTokens(&c);
- }
- cleanContext(&c);
- return c.error;
- }
|