#include #include #include #include #include "Compiler.h" #include "Operation.h" #include "Tokenizer.h" #define MAX_BYTES (1024 * 1024) #define ERROR_LENGTH 256 #define VARS 256 static char error[ERROR_LENGTH] = {'\0'}; static unsigned char byteCode[MAX_BYTES]; static int writeIndex = 0; static int16 line = 1; static const char* vars[VARS]; static int varIndex = 0; static void cError(const char* format, ...) { va_list args; va_start(args, format); vsnprintf(error, ERROR_LENGTH, format, args); va_end(args); } static int cAddVar(const char* var) { for(int i = 0; i < varIndex; i++) { if(strcmp(var, vars[i]) == 0) { return i; } } if(varIndex >= VARS) { cError("variable buffer is too small"); return -1; } int index = varIndex; vars[varIndex++] = var; return index; } static void cUnexpectedToken(Token t) { cError("unexpected token on line %d: %s", line, tGetTokenName(t)); } static void* cReserveBytes(int length) { if(writeIndex + length > MAX_BYTES) { cError("the compiler buffer is too small"); return NULL; } unsigned char* p = byteCode + writeIndex; writeIndex += length; return p; } static void cSetBytes(const void* data, void* dest, int length) { memcpy(dest, data, length); } static bool cAddBytes(const void* data, int length) { void* p = cReserveBytes(length); if(p == NULL) { return false; } cSetBytes(data, p, length); return true; } static bool cAddOperation(Operation token) { unsigned char c = token; return cAddBytes(&c, 1); } static Token tReadTokenAndLine() { Token t = tReadToken(); if(tReadInt16(&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); } else if(cConsumeTokenIf(T_LITERAL)) { const char* literal = tReadString(); if(literal == NULL) { cError("literal without string on line %d", line); return false; } int varPointer = cAddVar(literal); if(varPointer == -1) { return false; } return cAddOperation(OP_GET) && cAddBytes(&varPointer, sizeof(int)); } 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 cLiteral() { const char* literal = tReadString(); if(literal == NULL) { cError("literal without string on line %d", line); return false; } Token t = tReadTokenAndLine(); if(t != T_SET) { cUnexpectedToken(t); return false; } int varPointer = cAddVar(literal); if(varPointer == -1) { return false; } return cExpression() && cAddOperation(OP_SET) && cAddBytes(&varPointer, sizeof(int)) && cConsumeToken(T_SEMICOLON); } 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(!cAddOperation(OP_LINE) || !cAddBytes(&line, sizeof(line))) { return false; } if(t == T_PRINT) { return cPrint(); } else if(t == T_LITERAL) { return cLiteral(); } cUnexpectedToken(t); return false; } static void cForEachLine() { writeIndex = 0; varIndex = 0; if(!cAddOperation(OP_PUSH)) { return; } void* globalVars = cReserveBytes(sizeof(int)); if(globalVars == NULL) { return; } while(cLine()) { } if(!cAddOperation(OP_POP)) { return; } cSetBytes(&varIndex, globalVars, sizeof(int)); cAddBytes(&varIndex, sizeof(int)); } unsigned char* cCompile(int* codeLength) { error[0] = '\0'; cForEachLine(); if(error[0] != '\0') { return NULL; } unsigned char* bytes = malloc(writeIndex); memcpy(bytes, byteCode, writeIndex); *codeLength = writeIndex; return bytes; } const char* cGetError() { return error; }