#include #include #include #include #include "Compiler.h" #include "Operation.h" #include "Tokenizer.h" #define MAX_BYTES (1024 * 1024) #define ERROR_LENGTH 256 static char error[ERROR_LENGTH] = {'\0'}; static unsigned char byteCode[MAX_BYTES]; static int writeIndex = 0; static int line = 1; static void cError(const char* format, ...) { va_list args; va_start(args, format); vsnprintf(error, ERROR_LENGTH, format, args); va_end(args); } static void cUnexpectedToken(Token t) { cError("unexpected token on line %d: %s", line, tGetTokenName(t)); } static bool cAddBytes(const void* data, int length) { if(writeIndex + length > MAX_BYTES) { cError("the compiler buffer is too small"); return false; } memcpy(byteCode + writeIndex, data, length); writeIndex += length; return true; } static bool cAddOperation(Operation token) { unsigned char c = token; return cAddBytes(&c, 1) && cAddBytes(&line, sizeof(int)); } static Token tReadTokenAndLine() { Token t = tReadToken(); if(tReadInt(&line)) { return t; } return T_END; } static bool cConsumeToken(Token wanted) { Token t = tReadTokenAndLine(); if(wanted == t) { return true; } cError("unexpected token on line %d: expected '%s' got '%s'", line, tGetTokenName(wanted), tGetTokenName(t)); return false; } static bool cConsumeTokenIf(Token t) { if(tPeekToken() == t) { tReadTokenAndLine(); return true; } return false; } static bool cExpression(); static bool cPrimary() { if(cConsumeTokenIf(T_INT)) { int value; return tReadInt(&value) && cAddOperation(OP_PUSH_INT) && cAddBytes(&value, sizeof(int)); } else if(cConsumeTokenIf(T_FLOAT)) { float value; return tReadFloat(&value) && cAddOperation(OP_PUSH_FLOAT) && cAddBytes(&value, sizeof(float)); } else if(cConsumeTokenIf(T_NULL)) { return cAddOperation(OP_PUSH_NULL); } else if(cConsumeTokenIf(T_TRUE)) { return cAddOperation(OP_PUSH_TRUE); } else if(cConsumeTokenIf(T_FALSE)) { return cAddOperation(OP_PUSH_FALSE); } else if(cConsumeTokenIf(T_OPEN_BRACKET)) { return cExpression() && cConsumeToken(T_CLOSE_BRACKET); } cUnexpectedToken(tPeekToken()); return false; } static bool cMul() { if(!cPrimary()) { return false; } while(cConsumeTokenIf(T_MUL)) { if(!cPrimary() || !cAddOperation(OP_MUL)) { return false; } } return true; } static bool cAdd() { if(!cMul()) { return false; } while(cConsumeTokenIf(T_ADD)) { if(!cMul() || !cAddOperation(OP_ADD)) { return false; } } return true; } static bool cExpression() { return cAdd(); } static bool cPrint() { return cExpression() && cConsumeToken(T_SEMICOLON) && cAddOperation(OP_PRINT); } static bool cLine() { Token t = tReadTokenAndLine(); if(t == T_END) { return false; } else if(t == T_PRINT) { return cPrint(); } cUnexpectedToken(t); return false; } unsigned char* cCompile(int* codeLength) { writeIndex = 0; error[0] = '\0'; while(cLine()) { } if(error[0] != '\0') { return NULL; } unsigned char* bytes = malloc(writeIndex); memcpy(bytes, byteCode, writeIndex); *codeLength = writeIndex; return bytes; } const char* cGetError() { return error; }