|
|
@@ -7,132 +7,143 @@
|
|
|
|
|
|
#include "Code.h"
|
|
|
|
|
|
-static Error error = {};
|
|
|
-static int line = 0;
|
|
|
-static jmp_buf jumpPosition = {};
|
|
|
-
|
|
|
-#define THROW_ERROR(format, ...) \
|
|
|
- snprintf( \
|
|
|
- error.text, sizeof(error.text), "Line %d | " format, \
|
|
|
- line __VA_OPT__(, ) __VA_ARGS__); \
|
|
|
- longjmp(jumpPosition, 1)
|
|
|
-
|
|
|
-#define CODE(command) \
|
|
|
- do { \
|
|
|
- if(command) { \
|
|
|
- THROW_ERROR("Code overflow"); \
|
|
|
- } \
|
|
|
+typedef struct {
|
|
|
+ Tokenizer* tokenizer;
|
|
|
+ Code* code;
|
|
|
+ Error error;
|
|
|
+ int line;
|
|
|
+ jmp_buf jump;
|
|
|
+} 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)
|
|
|
+
|
|
|
+#define CODE(command) \
|
|
|
+ do { \
|
|
|
+ if(command) { \
|
|
|
+ THROW_ERROR("Too less memory for code"); \
|
|
|
+ } \
|
|
|
} while(false)
|
|
|
|
|
|
-[[noreturn]] static void unexpectedToken(Token token) {
|
|
|
+[[noreturn]] static void unexpectedToken(Context* c, Token token) {
|
|
|
char buffer[128];
|
|
|
tokenizerPrintToken(&token, buffer, sizeof(buffer));
|
|
|
THROW_ERROR("Unexpected %s token", buffer);
|
|
|
}
|
|
|
|
|
|
-static Token consumeToken(Tokenizer* t, TokenType type) {
|
|
|
- Token actual = tokenizerNext(t);
|
|
|
+static Token consumeToken(Context* c, TokenType type) {
|
|
|
+ Token actual = tokenizerNext(c->tokenizer);
|
|
|
if(actual.type != type) {
|
|
|
- unexpectedToken(actual);
|
|
|
+ unexpectedToken(c, actual);
|
|
|
}
|
|
|
return actual;
|
|
|
}
|
|
|
|
|
|
-static void consumeLiteral(Tokenizer* t, const char* name) {
|
|
|
- Token token = consumeToken(t, LITERAL);
|
|
|
+static Token consumeNewline(Context* c) {
|
|
|
+ Token t = consumeToken(c, NEWLINE);
|
|
|
+ c->line++;
|
|
|
+ return t;
|
|
|
+}
|
|
|
+
|
|
|
+static void consumeLiteral(Context* c, const char* name) {
|
|
|
+ Token token = consumeToken(c, LITERAL);
|
|
|
const char* actual = token.stringValue;
|
|
|
if(strcmp(actual, name) != 0) {
|
|
|
THROW_ERROR("Unexpected literal(%s)", actual);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void compileConstant(Tokenizer* t) {
|
|
|
- Token token = tokenizerNext(t);
|
|
|
+static void compileConstant(Context* c) {
|
|
|
+ Token token = tokenizerNext(c->tokenizer);
|
|
|
if(token.type == STRING) {
|
|
|
- CODE(codePushInstruction(PUSH_CONSTANT_STRING));
|
|
|
- CODE(codePushConstantString(token.stringValue));
|
|
|
+ CODE(codePushInstruction(c->code, PUSH_CONSTANT_STRING));
|
|
|
+ CODE(codePushConstantString(c->code, token.stringValue));
|
|
|
} else if(token.type == INT64) {
|
|
|
- CODE(codePushInstruction(PUSH_INT64));
|
|
|
- CODE(codePushI64(token.intValue));
|
|
|
+ CODE(codePushInstruction(c->code, PUSH_INT64));
|
|
|
+ CODE(codePushI64(c->code, token.intValue));
|
|
|
} else {
|
|
|
- unexpectedToken(token);
|
|
|
+ unexpectedToken(c, token);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void compileAdd(Tokenizer* t) {
|
|
|
- compileConstant(t);
|
|
|
- while(tokenizerPeek(t).type == PLUS) {
|
|
|
- tokenizerNext(t);
|
|
|
- compileConstant(t);
|
|
|
- CODE(codePushInstruction(ADD));
|
|
|
+static void compileAdd(Context* c) {
|
|
|
+ compileConstant(c);
|
|
|
+ while(tokenizerPeek(c->tokenizer).type == PLUS) {
|
|
|
+ tokenizerNext(c->tokenizer);
|
|
|
+ compileConstant(c);
|
|
|
+ CODE(codePushInstruction(c->code, ADD));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void compileExpression(Tokenizer* t) {
|
|
|
- compileAdd(t);
|
|
|
+static void compileExpression(Context* c) {
|
|
|
+ compileAdd(c);
|
|
|
}
|
|
|
|
|
|
-static void compileLine(Tokenizer* t, Token token);
|
|
|
+static void compileLine(Context* c, Token token);
|
|
|
|
|
|
-static void compileIf(Tokenizer* t) {
|
|
|
- compileExpression(t);
|
|
|
- CODE(codePushInstruction(JUMP_ON_0));
|
|
|
- size_t posIndex = codeGetWritePosition();
|
|
|
- CODE(codePushSize(0));
|
|
|
- consumeLiteral(t, "then");
|
|
|
- consumeToken(t, NEWLINE);
|
|
|
+static void compileIf(Context* c) {
|
|
|
+ compileExpression(c);
|
|
|
+ CODE(codePushInstruction(c->code, JUMP_ON_0));
|
|
|
+ size_t posIndex = codeGetWritePosition(c->code);
|
|
|
+ CODE(codePushSize(c->code, 0));
|
|
|
+ consumeLiteral(c, "then");
|
|
|
+ consumeNewline(c);
|
|
|
while(true) {
|
|
|
- Token token = tokenizerPeek(t);
|
|
|
+ Token token = tokenizerPeek(c->tokenizer);
|
|
|
if(token.type == LITERAL && strcmp(token.stringValue, "endif") == 0) {
|
|
|
break;
|
|
|
}
|
|
|
- compileLine(t, tokenizerNext(t));
|
|
|
+ compileLine(c, tokenizerNext(c->tokenizer));
|
|
|
}
|
|
|
- consumeLiteral(t, "endif");
|
|
|
- consumeToken(t, NEWLINE);
|
|
|
- size_t endIndex = codeGetWritePosition();
|
|
|
- codeSetWritePosition(posIndex);
|
|
|
- CODE(codePushSize(endIndex));
|
|
|
- codeSetWritePosition(endIndex);
|
|
|
+ consumeLiteral(c, "endif");
|
|
|
+ consumeNewline(c);
|
|
|
+ size_t endIndex = codeGetWritePosition(c->code);
|
|
|
+ codeSetWritePosition(c->code, posIndex);
|
|
|
+ CODE(codePushSize(c->code, endIndex));
|
|
|
+ codeSetWritePosition(c->code, endIndex);
|
|
|
}
|
|
|
|
|
|
-static void compileLine(Tokenizer* t, Token token) {
|
|
|
+static void compileLine(Context* c, Token token) {
|
|
|
if(token.type == NEWLINE) {
|
|
|
+ c->line++;
|
|
|
return;
|
|
|
}
|
|
|
if(token.type != LITERAL) {
|
|
|
- unexpectedToken(token);
|
|
|
+ unexpectedToken(c, token);
|
|
|
}
|
|
|
const char* s = token.stringValue;
|
|
|
if(strcmp(s, "print") == 0) {
|
|
|
- while(tokenizerPeek(t).type != NEWLINE) {
|
|
|
- compileExpression(t);
|
|
|
- CODE(codePushInstruction(PRINT));
|
|
|
+ while(tokenizerPeek(c->tokenizer).type != NEWLINE) {
|
|
|
+ compileExpression(c);
|
|
|
+ CODE(codePushInstruction(c->code, PRINT));
|
|
|
}
|
|
|
- tokenizerNext(t);
|
|
|
- CODE(codePushInstruction(PRINT_NEWLINE));
|
|
|
+ consumeNewline(c);
|
|
|
+ CODE(codePushInstruction(c->code, PRINT_NEWLINE));
|
|
|
} else if(strcmp(s, "if") == 0) {
|
|
|
- compileIf(t);
|
|
|
+ compileIf(c);
|
|
|
} else {
|
|
|
THROW_ERROR("Unexpected literal(%s)", s);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void parseTokens(Tokenizer* t) {
|
|
|
- codeReset();
|
|
|
+static void parseTokens(Context* c) {
|
|
|
+ codeReset(c->code);
|
|
|
while(true) {
|
|
|
- Token token = tokenizerNext(t);
|
|
|
+ Token token = tokenizerNext(c->tokenizer);
|
|
|
if(token.type == END) {
|
|
|
break;
|
|
|
}
|
|
|
- compileLine(t, token);
|
|
|
+ compileLine(c, token);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-Error compileFile(Tokenizer* t) {
|
|
|
- error.text[0] = '\0';
|
|
|
- if(!setjmp(jumpPosition)) {
|
|
|
- parseTokens(t);
|
|
|
+Error compileFile(Tokenizer* t, Code* code) {
|
|
|
+ Context c = {.tokenizer = t, .code = code, .line = 1};
|
|
|
+ if(!setjmp(c.jump)) {
|
|
|
+ parseTokens(&c);
|
|
|
}
|
|
|
- return error;
|
|
|
+ return c.error;
|
|
|
}
|