|
|
@@ -22,9 +22,18 @@ 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;
|
|
|
@@ -33,6 +42,7 @@ typedef struct {
|
|
|
jmp_buf jump;
|
|
|
Variable* variables;
|
|
|
Function* functions;
|
|
|
+ Return* returns;
|
|
|
bool inFunction;
|
|
|
} Context;
|
|
|
|
|
|
@@ -68,6 +78,13 @@ 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;
|
|
|
@@ -75,8 +92,15 @@ static void codeRewriteI32(Context* c, size_t pos, i32 i) {
|
|
|
c->code->code.writeIndex = oldPos;
|
|
|
}
|
|
|
|
|
|
-static i32 addVariable(Context* c, const char* name) {
|
|
|
+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;
|
|
|
}
|
|
|
@@ -87,14 +111,19 @@ static i32 addVariable(Context* c, const char* name) {
|
|
|
THROW_ERROR("Too less memory for variables");
|
|
|
}
|
|
|
v->next = c->variables;
|
|
|
- v->index = c->variables != nullptr ? c->variables->index + 1 : 0;
|
|
|
+ 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) {
|
|
|
+ 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) {
|
|
|
@@ -103,30 +132,38 @@ static void addRawFunction(
|
|
|
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) {
|
|
|
+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);
|
|
|
+ addRawFunction(c, name, address, -1, arguments);
|
|
|
}
|
|
|
|
|
|
-static i32 addCallFunction(Context* c, const char* name, i32 address) {
|
|
|
+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);
|
|
|
+ addRawFunction(c, name, -1, address, arguments);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
@@ -138,100 +175,228 @@ static void checkForInvalidFunctions(Context* c) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void cleanContext(Context* c) {
|
|
|
- Variable* v = c->variables;
|
|
|
- while(v != nullptr) {
|
|
|
- Variable* next = v->next;
|
|
|
- memoryFree(v);
|
|
|
- v = next;
|
|
|
+static void addReturn(Context* c, i32 address, bool hasArgument) {
|
|
|
+ if(c->returns != nullptr && c->returns->hasArgument != hasArgument) {
|
|
|
+ THROW_ERROR("Inconsistent returns in function");
|
|
|
}
|
|
|
- c->variables = nullptr;
|
|
|
-
|
|
|
- Function* f = c->functions;
|
|
|
- while(f != nullptr) {
|
|
|
- Function* next = f->next;
|
|
|
- memoryFree(f);
|
|
|
- f = next;
|
|
|
+ Return* r = memoryAllocate(sizeof(Return));
|
|
|
+ if(r == nullptr) {
|
|
|
+ THROW_ERROR("Too less memory for returns");
|
|
|
}
|
|
|
- c->functions = nullptr;
|
|
|
+ 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) {
|
|
|
+[[noreturn]] static void unexpectedToken(Context* c, Token token, int line) {
|
|
|
char buffer[128];
|
|
|
tokenizerPrintToken(&token, buffer, sizeof(buffer));
|
|
|
- THROW_ERROR("Unexpected %s token", 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);
|
|
|
+ unexpectedToken(c, actual, __LINE__);
|
|
|
}
|
|
|
return actual;
|
|
|
}
|
|
|
|
|
|
-static Token consumeNewline(Context* c) {
|
|
|
- Token t = consumeToken(c, NEWLINE);
|
|
|
+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++;
|
|
|
- return t;
|
|
|
}
|
|
|
|
|
|
+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 == STRING) {
|
|
|
+ if(token.type == TT_STRING) {
|
|
|
codePushInstruction(c, PUSH_CONSTANT_STRING);
|
|
|
codePushConstantString(c, token.stringValue);
|
|
|
- } else if(token.type == INT32) {
|
|
|
- codePushInstruction(c, PUSH_INT64);
|
|
|
- codePushI32(c, token.intValue);
|
|
|
- } else if(token.type == LITERAL) {
|
|
|
- i32 index = addVariable(c, token.stringValue);
|
|
|
- codePushInstruction(c, READ_VARIABLE);
|
|
|
- codePushI32(c, index);
|
|
|
+ } 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);
|
|
|
+ unexpectedToken(c, token, __LINE__);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void compileAdd(Context* c) {
|
|
|
- compileConstant(c);
|
|
|
- while(tokenizerPeek(c->tokenizer).type == PLUS) {
|
|
|
- tokenizerNext(c->tokenizer);
|
|
|
+static void compileUnary(Context* c) {
|
|
|
+ if(consumeTokenIf(c, TT_NOT)) {
|
|
|
+ compileUnary(c);
|
|
|
+ codePushInstruction(c, NOT);
|
|
|
+ } else {
|
|
|
compileConstant(c);
|
|
|
- codePushInstruction(c, ADD);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void compileExpression(Context* 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);
|
|
|
- codePushInstruction(c, JUMP_ON_0);
|
|
|
- size_t posIndex = codeGetWritePosition(c);
|
|
|
- codePushI32(c, 0);
|
|
|
- consumeToken(c, THEN);
|
|
|
+ size_t posIndex = codePushInstructionI32(c, JUMP_ON_0, 0);
|
|
|
consumeNewline(c);
|
|
|
- while(true) {
|
|
|
- if(tokenizerPeek(c->tokenizer).type == ENDIF) {
|
|
|
- break;
|
|
|
- }
|
|
|
+ while(!peekToken(c, TT_END)) {
|
|
|
compileLine(c, tokenizerNext(c->tokenizer));
|
|
|
}
|
|
|
- consumeToken(c, ENDIF);
|
|
|
+ consumeToken(c, TT_END);
|
|
|
consumeNewline(c);
|
|
|
codeRewriteI32(c, posIndex, (i32)codeGetWritePosition(c));
|
|
|
}
|
|
|
|
|
|
-static void compileSetVariable(Context* c, const char* name) {
|
|
|
- consumeToken(c, EQUAL);
|
|
|
+static void compileSetVariable(Context* c, const char* name, bool forceGlobal) {
|
|
|
+ consumeToken(c, TT_ASSIGN);
|
|
|
compileExpression(c);
|
|
|
- i32 index = addVariable(c, name);
|
|
|
- codePushInstruction(c, SET_VARIABLE);
|
|
|
- codePushI32(c, index);
|
|
|
+ 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) {
|
|
|
@@ -239,75 +404,111 @@ static void compileFunction(Context* c) {
|
|
|
THROW_ERROR("Functions in functions are not allowed");
|
|
|
}
|
|
|
c->inFunction = true;
|
|
|
- codePushInstruction(c, JUMP);
|
|
|
- size_t pos = codeGetWritePosition(c);
|
|
|
- codePushI32(c, 0);
|
|
|
-
|
|
|
- Token t = consumeToken(c, LITERAL);
|
|
|
- addFunction(c, t.stringValue, (i32)codeGetWritePosition(c));
|
|
|
- consumeToken(c, OPEN_ROUND_BRACKET);
|
|
|
- consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
|
- while(true) {
|
|
|
- if(tokenizerPeek(c->tokenizer).type == END) {
|
|
|
- break;
|
|
|
- }
|
|
|
+ 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, END);
|
|
|
- codePushInstruction(c, RETURN);
|
|
|
+ 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, pos, (i32)codeGetWritePosition(c));
|
|
|
+ codeRewriteI32(c, functionEnd, (i32)codeGetWritePosition(c));
|
|
|
c->inFunction = false;
|
|
|
}
|
|
|
|
|
|
static void compileCallFunction(Context* c, Token t) {
|
|
|
+ // used to store return address and variable index
|
|
|
+ codePushInstructionI32(c, PUSH_INT32, 0);
|
|
|
+ codePushInstructionI32(c, PUSH_INT32, 0);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
codePushInstruction(c, JUMP_SUB);
|
|
|
size_t pos = codeGetWritePosition(c);
|
|
|
- codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos));
|
|
|
- consumeToken(c, OPEN_ROUND_BRACKET);
|
|
|
- consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
|
- consumeNewline(c);
|
|
|
+ codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos, offset));
|
|
|
+ codePushI32(c, offset);
|
|
|
}
|
|
|
|
|
|
-static void compileLine(Context* c, Token token) {
|
|
|
- if(token.type == NEWLINE) {
|
|
|
- c->line++;
|
|
|
- return;
|
|
|
- } else if(token.type == IF) {
|
|
|
- compileIf(c);
|
|
|
- return;
|
|
|
- } else if(token.type == FUNCTION) {
|
|
|
- compileFunction(c);
|
|
|
- return;
|
|
|
- } else if(token.type != LITERAL) {
|
|
|
- unexpectedToken(c, token);
|
|
|
+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(strcmp(s, "print") == 0) {
|
|
|
- while(tokenizerPeek(c->tokenizer).type != NEWLINE) {
|
|
|
+ while(!peekToken(c, TT_NEWLINE)) {
|
|
|
compileExpression(c);
|
|
|
codePushInstruction(c, PRINT);
|
|
|
}
|
|
|
consumeNewline(c);
|
|
|
codePushInstruction(c, PRINT_NEWLINE);
|
|
|
- } else if(tokenizerPeek(c->tokenizer).type == EQUAL) {
|
|
|
- compileSetVariable(c, s);
|
|
|
- } else if(tokenizerPeek(c->tokenizer).type == OPEN_ROUND_BRACKET) {
|
|
|
+ } else if(peekToken(c, TT_ASSIGN)) {
|
|
|
+ compileSetVariable(c, s, false);
|
|
|
+ } else if(peekToken(c, TT_OPEN_ROUND_BRACKET)) {
|
|
|
compileCallFunction(c, token);
|
|
|
} 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);
|
|
|
- codePushInstruction(c, PUSH_STACK_VARIABLES);
|
|
|
- size_t stackVarsLoc = codeGetWritePosition(c);
|
|
|
- codePushI32(c, 0);
|
|
|
+ size_t stackVarsLoc = codePushInstructionI32(c, PUSH_STACK_VARIABLES, 0);
|
|
|
|
|
|
while(true) {
|
|
|
Token token = tokenizerNext(c->tokenizer);
|
|
|
- if(token.type == INVALID) {
|
|
|
+ if(token.type == TT_INVALID) {
|
|
|
break;
|
|
|
}
|
|
|
compileLine(c, token);
|