#include #include #include "Compiler.h" #include "Operation.h" #include "StringIntMap.h" #include "Tokenizer.h" #define MAX_BYTES (1024 * 1024) #define ERROR_LENGTH 256 #define VARS 256 static char error[ERROR_LENGTH] = {'\0'}; static ByteCode* code; static int16 line = 1; static StringIntMap vars; static int varIndex = 0; static StringIntMap functions; 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) { int index = varIndex; if(simAdd(&vars, var, &index)) { varIndex++; } return index; } static void cUnexpectedToken(Token t) { cError("unexpected token on line %d: %s", line, tGetTokenName(t)); } static void cAddOperation(Operation token) { unsigned char c = token; bcAddBytes(code, &c, 1); } static int cReserveInt() { return bcReserveBytes(code, sizeof(int)); } static void cSetInt(int p, int i) { bcSetBytes(code, p, &i, sizeof(int)); } static void cAddInt(int i) { bcAddBytes(code, &i, sizeof(int)); } static void cAddInt16(int16 i) { bcAddBytes(code, &i, sizeof(int16)); } static void cAddFloat(float f) { bcAddBytes(code, &f, sizeof(float)); } 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 cConstantInt() { int value; if(tReadInt(&value)) { cAddOperation(OP_PUSH_INT); cAddInt(value); return true; } return false; } static bool cConstantFloat() { float value; if(tReadFloat(&value)) { cAddOperation(OP_PUSH_FLOAT); cAddFloat(value); return true; } return false; } static bool cGetVar() { const char* literal = tReadString(); if(literal == NULL) { cError("literal without string on line %d", line); return false; } cAddOperation(OP_GET); cAddInt(cAddVar(literal)); return true; } static bool cPrimary() { Token t = tReadTokenAndLine(); switch(t) { case T_INT: return cConstantInt(); case T_FLOAT: return cConstantFloat(); case T_NULL: cAddOperation(OP_PUSH_NULL); return true; case T_TRUE: cAddOperation(OP_PUSH_TRUE); return true; case T_FALSE: cAddOperation(OP_PUSH_FALSE); return true; case T_OPEN_BRACKET: return cExpression() && cConsumeToken(T_CLOSE_BRACKET); case T_LITERAL: return cGetVar(); default: cUnexpectedToken(t); return false; } } static bool cMul() { if(!cPrimary()) { return false; } while(cConsumeTokenIf(T_MUL)) { if(!cPrimary()) { return false; } cAddOperation(OP_MUL); } return true; } static bool cAdd() { if(!cMul()) { return false; } while(cConsumeTokenIf(T_ADD)) { if(!cMul()) { return false; } cAddOperation(OP_ADD); } return true; } static bool cExpression() { return cAdd(); } static bool cSetVar(const char* literal) { bool b = cExpression() && cConsumeToken(T_SEMICOLON); cAddOperation(OP_SET); cAddInt(cAddVar(literal)); return b; } static bool cCallFunction(const char* literal) { int index; if(simSearch(&functions, literal, &index)) { cAddOperation(OP_GOSUB); cAddInt(index); } else { cError("unknown function on line %d", line); return false; } return cConsumeToken(T_CLOSE_BRACKET) && cConsumeToken(T_SEMICOLON); } 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) { return cSetVar(literal); } else if(t == T_OPEN_BRACKET) { return cCallFunction(literal); } cUnexpectedToken(t); return false; } static bool cLine(); static bool cFunction() { if(!cConsumeToken(T_LITERAL)) { return false; } const char* name = tReadString(); if(name == NULL) { cError("function literal without a function name on line %d", line); return false; } if(!cConsumeToken(T_OPEN_BRACKET) || !cConsumeToken(T_CLOSE_BRACKET) || !cConsumeToken(T_OPEN_CURVED_BRACKET)) { return false; } cAddOperation(OP_GOTO); int p = cReserveInt(); int functionIndex = code->length; if(!simAdd(&functions, name, &functionIndex)) { cError("function registered twice on line %d", line); return false; } int oldLine = line; while(!cConsumeTokenIf(T_CLOSE_CURVED_BRACKET)) { if(cConsumeTokenIf(T_END)) { cError("unexpected end of file: function not closed on line %d", oldLine); return false; } cLine(); } cAddOperation(OP_RETURN); cSetInt(p, code->length); return true; } static bool cPrint() { bool b = cExpression() && cConsumeToken(T_SEMICOLON); cAddOperation(OP_PRINT); return b; } static bool cLine() { Token t = tReadTokenAndLine(); if(t == T_END) { return false; } cAddOperation(OP_LINE); cAddInt16(line); if(t == T_PRINT) { return cPrint(); } else if(t == T_LITERAL) { return cLiteral(); } else if(t == T_FUNCTION) { return cFunction(); } cUnexpectedToken(t); return false; } static void cForEachLine() { varIndex = 0; cAddOperation(OP_PUSH); int globalVars = cReserveInt(); while(cLine()) { } cAddOperation(OP_POP); cSetInt(globalVars, varIndex); cAddInt(varIndex); } static void cAllocAndCompile() { simInit(&vars); simInit(&functions); cForEachLine(); simDelete(&functions); simDelete(&vars); } ByteCode* cCompile() { error[0] = '\0'; code = bcInit(); cAllocAndCompile(); if(error[0] != '\0') { bcDelete(code); return NULL; } return code; } const char* cGetError() { return error; }