#include #include #include #include #include #include #include #include #include "memory.h" #include "cpu.h" #include "loader.h" #include "image.h" #include "assembler.h" #include "keywords.h" #include "functions.h" #include "operators.h" #include "linker.h" #include "midi.h" #define FONT_WIDTH 6 #define FONT_HEIGHT 8 #define MAPPING_SIZE 96 namespace Keywords { enum LoadUsage {LoadType=0, LoadWave, LoadMidi, LoadImage, LoadSprite, LoadFont}; enum InitTypes {InitTime, InitMidi, InitMidiV, InitUser}; enum MidiTypes {MidiNone, Midi, MidiV, MidiId, MidiIdV}; struct Gprintf { int codeLineIndex = 0; Assembler::Gprintf _gprintfAsm; }; bool _constDimStrArray = false; int _numNumericGotosGosubs = 0; MidiTypes _midiType = MidiNone; std::string _userRoutine; std::map _keywords; std::map _equalsKeywords; std::map& getKeywords(void) {return _keywords; } std::map& getEqualsKeywords(void) {return _equalsKeywords;} std::vector _gprintfs; void reset(void) { _midiType = MidiNone; _userRoutine = ""; _gprintfs.clear(); } void restart(void) { _constDimStrArray = false; _numNumericGotosGosubs = 0; } bool initialise(void) { restart(); // Equals keywords _equalsKeywords["CONST" ] = "CONST"; _equalsKeywords["DIM" ] = "DIM"; _equalsKeywords["DEF" ] = "DEF"; _equalsKeywords["FOR" ] = "FOR"; _equalsKeywords["IF" ] = "IF"; _equalsKeywords["ELSEIF"] = "ELSEIF"; _equalsKeywords["WHILE" ] = "WHILE"; _equalsKeywords["UNTIL" ] = "UNTIL"; // Keywords _keywords["END" ] = {"END", END, Compiler::SingleStatementParsed}; _keywords["INC" ] = {"INC", INC, Compiler::SingleStatementParsed}; _keywords["DEC" ] = {"DEC", DEC, Compiler::SingleStatementParsed}; _keywords["ON" ] = {"ON", ON, Compiler::SingleStatementParsed}; _keywords["GOTO" ] = {"GOTO", GOTO, Compiler::SingleStatementParsed}; _keywords["GOSUB" ] = {"GOSUB", GOSUB, Compiler::SingleStatementParsed}; _keywords["RETURN" ] = {"RETURN", RETURN, Compiler::SingleStatementParsed}; _keywords["RET" ] = {"RET", RET, Compiler::SingleStatementParsed}; _keywords["CLS" ] = {"CLS", CLS, Compiler::SingleStatementParsed}; _keywords["?" ] = {"?", PRINT, Compiler::SingleStatementParsed}; _keywords["PRINT" ] = {"PRINT", PRINT, Compiler::SingleStatementParsed}; _keywords["INPUT" ] = {"INPUT", INPUT, Compiler::SingleStatementParsed}; _keywords["FOR" ] = {"FOR", FOR, Compiler::SingleStatementParsed}; _keywords["NEXT" ] = {"NEXT", NEXT, Compiler::SingleStatementParsed}; _keywords["IF" ] = {"IF", IF, Compiler::MultiStatementParsed }; _keywords["ELSEIF" ] = {"ELSEIF", ELSEIF, Compiler::SingleStatementParsed}; _keywords["ELSE" ] = {"ELSE", ELSE, Compiler::SingleStatementParsed}; _keywords["ENDIF" ] = {"ENDIF", ENDIF, Compiler::SingleStatementParsed}; _keywords["WHILE" ] = {"WHILE", WHILE, Compiler::SingleStatementParsed}; _keywords["WEND" ] = {"WEND", WEND, Compiler::SingleStatementParsed}; _keywords["REPEAT" ] = {"REPEAT", REPEAT, Compiler::SingleStatementParsed}; _keywords["UNTIL" ] = {"UNTIL", UNTIL, Compiler::SingleStatementParsed}; _keywords["FOREVER" ] = {"FOREVER", FOREVER, Compiler::SingleStatementParsed}; _keywords["&FOREVER"] = {"&FOREVER", FOREVER, Compiler::SingleStatementParsed}; _keywords["AS" ] = {"AS", AS, Compiler::SingleStatementParsed}; _keywords["TYPE" ] = {"TYPE", TYPE, Compiler::SingleStatementParsed}; _keywords["CALL" ] = {"CALL", CALL, Compiler::SingleStatementParsed}; _keywords["PROC" ] = {"PROC", PROC, Compiler::SingleStatementParsed}; _keywords["ENDPROC" ] = {"ENDPROC", ENDPROC, Compiler::SingleStatementParsed}; _keywords["LOCAL" ] = {"LOCAL", LOCAL, Compiler::SingleStatementParsed}; _keywords["CONST" ] = {"CONST", CONST, Compiler::SingleStatementParsed}; _keywords["DIM" ] = {"DIM", DIM, Compiler::SingleStatementParsed}; _keywords["DEF" ] = {"DEF", DEF, Compiler::SingleStatementParsed}; _keywords["DATA" ] = {"DATA", DATA, Compiler::SingleStatementParsed}; _keywords["READ" ] = {"READ", READ, Compiler::SingleStatementParsed}; _keywords["RESTORE" ] = {"RESTORE", RESTORE, Compiler::SingleStatementParsed}; _keywords["ALLOC" ] = {"ALLOC", ALLOC, Compiler::SingleStatementParsed}; _keywords["FREE" ] = {"FREE", FREE, Compiler::SingleStatementParsed}; _keywords["AT" ] = {"AT", AT, Compiler::SingleStatementParsed}; _keywords["PUT" ] = {"PUT", PUT, Compiler::SingleStatementParsed}; _keywords["MODE" ] = {"MODE", MODE, Compiler::SingleStatementParsed}; _keywords["WAIT" ] = {"WAIT", WAIT, Compiler::SingleStatementParsed}; _keywords["PSET" ] = {"PSET", PSET, Compiler::SingleStatementParsed}; _keywords["LINE" ] = {"LINE", LINE, Compiler::SingleStatementParsed}; _keywords["HLINE" ] = {"HLINE", HLINE, Compiler::SingleStatementParsed}; _keywords["VLINE" ] = {"VLINE", VLINE, Compiler::SingleStatementParsed}; _keywords["CIRCLE" ] = {"CIRCLE", CIRCLE, Compiler::SingleStatementParsed}; _keywords["CIRCLEF" ] = {"CIRCLEF", CIRCLEF, Compiler::SingleStatementParsed}; _keywords["RECT" ] = {"RECT", RECT, Compiler::SingleStatementParsed}; _keywords["RECTF" ] = {"RECTF", RECTF, Compiler::SingleStatementParsed}; _keywords["POLY" ] = {"POLY", POLY, Compiler::SingleStatementParsed}; _keywords["POLYR" ] = {"POLYR", POLYR, Compiler::SingleStatementParsed}; _keywords["TCLIP" ] = {"TCLIP", TCLIP, Compiler::SingleStatementParsed}; _keywords["SCROLL" ] = {"SCROLL", SCROLL, Compiler::SingleStatementParsed}; _keywords["POKE" ] = {"POKE", POKE, Compiler::SingleStatementParsed}; _keywords["DOKE" ] = {"DOKE", DOKE, Compiler::SingleStatementParsed}; _keywords["INIT" ] = {"INIT", INIT, Compiler::SingleStatementParsed}; _keywords["TICK" ] = {"TICK", TICK, Compiler::SingleStatementParsed}; _keywords["PLAY" ] = {"PLAY", PLAY, Compiler::SingleStatementParsed}; _keywords["LOAD" ] = {"LOAD", LOAD, Compiler::SingleStatementParsed}; _keywords["SPRITE" ] = {"SPRITE", SPRITE, Compiler::SingleStatementParsed}; _keywords["SOUND" ] = {"SOUND", SOUND, Compiler::SingleStatementParsed}; _keywords["SET" ] = {"SET", SET, Compiler::SingleStatementParsed}; _keywords["ASM" ] = {"ASM", ASM, Compiler::SingleStatementParsed}; _keywords["ENDASM" ] = {"ENDASM", ENDASM, Compiler::SingleStatementParsed}; _keywords["BCDADD" ] = {"BCDADD", BCDADD, Compiler::SingleStatementParsed}; _keywords["BCDSUB" ] = {"BCDSUB", BCDSUB, Compiler::SingleStatementParsed}; _keywords["BCDINT" ] = {"BCDINT", BCDINT, Compiler::SingleStatementParsed}; _keywords["BCDCPY" ] = {"BCDCPY", BCDCPY, Compiler::SingleStatementParsed}; _keywords["GPRINTF" ] = {"GPRINTF", GPRINTF, Compiler::SingleStatementParsed}; _keywords["EXEC" ] = {"EXEC", EXEC, Compiler::SingleStatementParsed}; _keywords["OPEN" ] = {"OPEN", OPEN, Compiler::SingleStatementParsed}; return true; } bool findKeyword(std::string code, const std::string& keyword, size_t& foundPos) { Expression::strToUpper(code); foundPos = code.find(keyword); if(foundPos != std::string::npos) { foundPos += keyword.size(); return true; } return false; } KeywordResult handleKeywords(Compiler::CodeLine& codeLine, const std::string& keyword, int codeLineIndex, int tokenIndex, KeywordFuncResult& result) { size_t foundPos; std::string key = keyword; Expression::strToUpper(key); if(_keywords.find(key) == _keywords.end()) return KeywordNotFound; // Handle keyword in code line if(findKeyword(key, _keywords[key]._name, foundPos) && _keywords[key]._func) { // Line index taking into account modules int codeLineStart = Compiler::getCodeLineStart(codeLineIndex); // Keyword bool success = _keywords[key]._func(codeLine, codeLineIndex, codeLineStart, tokenIndex, foundPos, result); return (!success) ? KeywordError : KeywordFound; } return KeywordFound; } #ifndef STAND_ALONE bool addGprintf(const std::string& lineToken, const std::string& formatText, const std::vector& variables, uint16_t address, int codeLineIndex) { std::vector vars; std::vector subs; Assembler::parseGprintfFormat(formatText, variables, vars, subs); Gprintf gprintf = {codeLineIndex, {Compiler::getVasmPC(), codeLineIndex, lineToken, formatText, vars, subs}}; for(int i=0; i gOffsets; std::vector gTokens = Expression::tokeniseOffsets(codeLine._code.substr(gOffset + gSize), ',', gOffsets, false); if(gTokens.size() < 1) { fprintf(stderr, "Keywords::ON() : '%s:%d' : syntax error, must have at least one label after GOTO/GOSUB : %s\n", codeLine._moduleName.c_str(), codeLineStart, codeLine._text.c_str()); return false; } // Create on goto/gosub label LUT Compiler::getCodeLines()[codeLineIndex]._onGotoGosubLut._lut.clear(); for(int i=0; i gotoOffsets; std::vector gotoTokens = Expression::tokeniseOffsets(codeLine._code.substr(foundPos), ',', gotoOffsets, false); if(gotoTokens.size() < 1 || gotoTokens.size() > 2) { fprintf(stderr, "Keywords::GOTO() : '%s:%d' : syntax error, must have one or two parameters, e.g. 'GOTO 200' or 'GOTO k+1,default' : %s\n", codeLine._moduleName.c_str(), codeLineStart, codeLine._text.c_str()); return false; } // Parse GOTO field Expression::Numeric gotoValue; std::string gotoToken = gotoTokens[0]; Expression::stripWhitespace(gotoToken); bool useBRA = false; if(gotoToken[0] == '&') { useBRA = true; gotoToken.erase(0, 1); } int labelIndex = Compiler::findLabel(gotoToken); if(labelIndex == -1) { if(Expression::isNumber(gotoToken)) { fprintf(stderr, "Keywords::GOTO() : '%s:%d' : numeric label '%s' does not exist : %s\n", codeLine._moduleName.c_str(), codeLineStart, gotoToken.c_str(), codeLine._text.c_str()); return false; } if(++_numNumericGotosGosubs > Compiler::getNumNumericLabels()) { fprintf(stderr, "Keywords::GOTO() : '%s:%d' : numeric label '%s' does not exist : %s\n", codeLine._moduleName.c_str(), codeLineStart, gotoToken.c_str(), codeLine._text.c_str()); return false; } Compiler::setCreateNumericLabelLut(true); if(Compiler::parseExpression(codeLineIndex, gotoToken, gotoValue) == Expression::IsInvalid) { fprintf(stderr, "Keywords::GOTO() : '%s:%d' : syntax error in %s : %s\n", codeLine._moduleName.c_str(), codeLineStart, gotoToken.c_str(), codeLine._text.c_str()); return false; } Compiler::emitVcpuAsm("STW", "numericLabel", false); // Default label exists if(gotoTokens.size() == 2) { std::string defaultToken = gotoTokens[1]; Expression::stripWhitespace(defaultToken); labelIndex = Compiler::findLabel(defaultToken); if(labelIndex == -1) { fprintf(stderr, "Keywords::GOTO() : '%s:%d' : default label does not exist : %s\n", codeLine._moduleName.c_str(), codeLineStart, codeLine._text.c_str()); return false; } Compiler::emitVcpuAsm("LDWI", "_" + Compiler::getLabels()[labelIndex]._name, false); } // No default label else { Compiler::emitVcpuAsm("LDI", "0", false); } Compiler::emitVcpuAsm("STW", "defaultLabel", false); // Call gotoNumericLabel Compiler::emitVcpuAsm("%GotoNumeric", "", false); return true; } // Within same page, (validation check on same page branch may fail after outputCode(), user will be warned) if(useBRA) { Compiler::emitVcpuAsm("BRA", "_" + gotoToken, false); } // Long jump else { if(Compiler::getCodeRomType() >= Cpu::ROMv5a) { Compiler::emitVcpuAsm("CALLI", "_" + gotoToken, false); } else { Compiler::emitVcpuAsm("LDWI", "_" + gotoToken, false); Compiler::emitVcpuAsm("CALL", "giga_vAC", false); } } return true; } bool GOSUB(Compiler::CodeLine& codeLine, int codeLineIndex, int codeLineStart, int tokenIndex, size_t foundPos, KeywordFuncResult& result) { UNREFERENCED_PARAM(result); UNREFERENCED_PARAM(tokenIndex); // Parse labels std::vector gosubOffsets; std::vector gosubTokens = Expression::tokeniseOffsets(codeLine._code.substr(foundPos), ',', gosubOffsets, false); if(gosubTokens.size() < 1 || gosubTokens.size() > 2) { fprintf(stderr, "Keywords::GOSUB() : '%s:%d' : syntax error, must have one or two parameters, e.g. 'GOSUB