From bde25fd004a719836ae29efc672426e4ab9fa5d9 Mon Sep 17 00:00:00 2001 From: Anthony Rabine Date: Wed, 26 Apr 2023 13:50:02 +0200 Subject: [PATCH] New parser for lines + constants (allow labels in constants) --- software/chip32/chip32_assembler.cpp | 175 ++++++++++++------------ software/chip32/chip32_assembler.h | 2 +- story-editor/src/main_window.h | 4 +- story-editor/src/script_editor_dock.cpp | 47 ++++--- 4 files changed, 113 insertions(+), 115 deletions(-) diff --git a/software/chip32/chip32_assembler.cpp b/software/chip32/chip32_assembler.cpp index fa421bd..0487c2a 100644 --- a/software/chip32/chip32_assembler.cpp +++ b/software/chip32/chip32_assembler.cpp @@ -30,43 +30,14 @@ THE SOFTWARE. #include #include #include +#include +#include namespace Chip32 { // ============================================================================= // GLOBAL UTILITY FUNCTIONS // ============================================================================= -static const char* ws = " \t\n\r\f\v"; - -// trim from end of string (right) -static inline std::string& rtrim(std::string& s, const char* t = ws) -{ - s.erase(s.find_last_not_of(t) + 1); - return s; -} - -// trim from beginning of string (left) -static inline std::string& ltrim(std::string& s, const char* t = ws) -{ - s.erase(0, s.find_first_not_of(t)); - return s; -} - -// trim from both ends of string (right then left) -static inline std::string& trim(std::string& s, const char* t = ws) -{ - return ltrim(rtrim(s, t), t); -} - -static std::vector Split(const std::string &theString) -{ - std::vector result; - std::istringstream iss(theString); - for(std::string s; iss >> s; ) - result.push_back(s); - return result; -} - static std::string ToLower(const std::string &text) { std::string newText = text; @@ -108,16 +79,6 @@ static bool IsOpCode(const std::string &label, OpCode &op) return success; } -static void GetArgs(Instr &instr, const std::string &data) -{ - std::string value; - std::istringstream iss(data); - while (getline(iss, value, ',')) - { - instr.args.push_back(trim(value)); - } -} - static inline void leu32_put(std::vector &container, uint32_t data) { container.push_back(data & 0xFFU); @@ -144,6 +105,37 @@ static inline void leu16_put(std::vector &container, uint16_t data m_lastError = ss.str(); \ return false; } \ +std::vector Split(std::string line) +{ + std::vector result; + std::istringstream iss(line); + std::string token; + + while (std::getline(iss, token, ' ')) { + // Vérifier si le jeton contient une virgule + size_t comma_pos = token.find(","); + if (comma_pos != std::string::npos) { + // Diviser le jeton en deux parties séparées par la virgule + std::string first_token = token.substr(0, comma_pos); + std::string second_token = token.substr(comma_pos + 1); + // Ajouter chaque partie au vecteur de résultats + if (!first_token.empty()) { + result.push_back(first_token); + } + if (!second_token.empty()) { + result.push_back(second_token); + } + } else { + // Ajouter le jeton entier au vecteur de résultats + if (!token.empty()) { + result.push_back(token); + } + } + } + + return result; +} + // ============================================================================= // ASSEMBLER CLASS // ============================================================================= @@ -255,44 +247,52 @@ bool Assembler::CompileMnemonicArguments(Instr &instr) return true; } -bool Assembler::CompileConstantArguments(Instr &instr) +bool Assembler::CompileConstantArgument(Instr &instr, const std::string &a) { - for (auto &a : instr.args) + instr.compiledArgs.clear(); instr.args.clear(); instr.useLabel = false; + + // Check string + if (a.size() > 2) { - // Check string - if (a.size() > 2) + // Detected string + if ((a[0] == '"') && (a[a.size() - 1] == '"')) { - // Detected string - if ((a[0] == '"') && (a[a.size() - 1] == '"')) + for (int i = 1; i < (a.size() - 1); i++) { - for (int i = 1; i < (a.size() - 1); i++) - { - instr.compiledArgs.push_back(a[i]); - } - instr.compiledArgs.push_back(0); - continue; + instr.compiledArgs.push_back(a[i]); } + instr.compiledArgs.push_back(0); + return true; } - - // here, we check if the intergers are correct - uint32_t intVal = static_cast(strtol(a.c_str(), NULL, 0)); - - bool sizeOk = false; - if (((intVal <= UINT8_MAX) && (instr.dataTypeSize == 8)) || - ((intVal <= UINT16_MAX) && (instr.dataTypeSize == 16)) || - ((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) { - sizeOk = true; - } - CHIP32_CHECK(instr, sizeOk, "integer too high: " << intVal); - if (instr.dataTypeSize == 8) { - instr.compiledArgs.push_back(intVal); - } else if (instr.dataTypeSize == 16) { - leu16_put(instr.compiledArgs, intVal); - } else { - leu32_put(instr.compiledArgs, intVal); + // Detect label + else if (a[0] == '.') + { + // Label must be 32-bit, throw an error if not the case + CHIP32_CHECK(instr, instr.dataTypeSize == 32, "Labels must be stored in a 32-bit area (DC32)") + instr.useLabel = true; + instr.args.push_back(a); + leu32_put(instr.compiledArgs, 0); // reserve 4 bytes + return true; } } + // here, we check if the intergers are correct + uint32_t intVal = static_cast(strtol(a.c_str(), NULL, 0)); + + bool sizeOk = false; + if (((intVal <= UINT8_MAX) && (instr.dataTypeSize == 8)) || + ((intVal <= UINT16_MAX) && (instr.dataTypeSize == 16)) || + ((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) { + sizeOk = true; + } + CHIP32_CHECK(instr, sizeOk, "integer too high: " << intVal); + if (instr.dataTypeSize == 8) { + instr.compiledArgs.push_back(intVal); + } else if (instr.dataTypeSize == 16) { + leu16_put(instr.compiledArgs, intVal); + } else { + leu32_put(instr.compiledArgs, intVal); + } return true; } @@ -336,19 +336,14 @@ bool Assembler::Parse(const std::string &data) lineNum++; Instr instr; instr.line = lineNum; - - line = trim(line); - int pos = line.find_first_of(";"); if (pos != std::string::npos) { line.erase(pos); } - - if (line.length() <= 0) continue; + if (std::all_of(line.begin(), line.end(), ::isspace)) continue; // Split the line std::vector lineParts = Split(line); - CHIP32_CHECK(instr, (lineParts.size() > 0), " not a valid line"); // Ok until now @@ -384,12 +379,7 @@ bool Assembler::Parse(const std::string &data) } else if ((instr.code.nbAargs > 0) && (lineParts.size() >= 2)) { - // Compute arguments - for (int i = 1; i < lineParts.size(); i++) - { - GetArgs(instr, lineParts[i]); - } - + instr.args.insert(instr.args.begin(), lineParts.begin() + 1, lineParts.end()); CHIP32_CHECK(instr, instr.args.size() == instr.code.nbAargs, "Bad number of parameters. Required: " << static_cast(instr.code.nbAargs) << ", got: " << instr.args.size()); nbArgsSuccess = true; @@ -402,7 +392,6 @@ bool Assembler::Parse(const std::string &data) if (nbArgsSuccess) { CHIP32_CHECK(instr, CompileMnemonicArguments(instr) == true, "Compile failure"); - instr.addr = code_addr; code_addr += 1 + instr.compiledArgs.size(); m_instructions.push_back(instr); @@ -430,23 +419,27 @@ bool Assembler::Parse(const std::string &data) if (instr.isRomData) { + instr.addr = code_addr; + m_labels[opcode] = instr; // location of the start of the data + // if ROM data, we generate one instruction per argument + // reason: arguments may be labels, easier to replace later + for (int i = 2; i < lineParts.size(); i++) { - GetArgs(instr, lineParts[i]); + CHIP32_CHECK(instr, CompileConstantArgument(instr, lineParts[i]), "Compile argument error, stopping."); + m_instructions.push_back(instr); + code_addr += instr.compiledArgs.size(); + instr.addr = code_addr; } - CHIP32_CHECK(instr, CompileConstantArguments(instr), "Compile error, stopping."); - - instr.addr = code_addr; - code_addr += instr.compiledArgs.size(); } - else // RAM DATA + else // RAM DATA, only one argument is used: the size of the array { instr.addr = ram_addr; instr.dataLen = static_cast(strtol(lineParts[2].c_str(), NULL, 0)); ram_addr += instr.dataLen; + m_labels[opcode] = instr; + m_instructions.push_back(instr); } - m_labels[opcode] = instr; - m_instructions.push_back(instr); } else { diff --git a/software/chip32/chip32_assembler.h b/software/chip32/chip32_assembler.h index da47e0d..4e92a3e 100644 --- a/software/chip32/chip32_assembler.h +++ b/software/chip32/chip32_assembler.h @@ -115,7 +115,7 @@ private: std::string m_lastError; std::vector m_instructions; - bool CompileConstantArguments(Instr &instr); + bool CompileConstantArgument(Instr &instr, const std::string &a); }; } diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index dbd8ffd..e82e1f0 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -58,14 +58,14 @@ struct DebugContext for (std::vector::const_iterator iter = assembler.Begin(); iter != assembler.End(); ++iter) { - if (iter->isRomCode()) + if (iter->isRomCode() || iter->isRomData) { qDebug() << "-------------------"; qDebug() << "Instr: " << iter->mnemonic.c_str(); qDebug() << "Addr: " << Qt::hex << iter->addr; qDebug() << "Line: " << iter->line; qDebug() << "\t- Opcode: " << Qt::hex << iter->code.opcode - << ", Args: " << iter->code.bytes; + << ", opcode args: " << iter->code.bytes; int i = 1; for (auto arg : iter->compiledArgs) diff --git a/story-editor/src/script_editor_dock.cpp b/story-editor/src/script_editor_dock.cpp index 3386402..e7a5fb1 100644 --- a/story-editor/src/script_editor_dock.cpp +++ b/story-editor/src/script_editor_dock.cpp @@ -5,13 +5,19 @@ static const std::string test1 = R"( jump .entry ; Constant elements are separated by commas -$imageBird DC8 "example.bmp", 8 ; string of chars, followed by one byte -$soundChoice DC8 "choose1.snd" -$someConstant DC32 12456789 +$imageBird DC8, "example.bmp", 8 ; string of chars, followed by one byte +$soundChoice DC8, "choose1.snd" +$yaya DC8, "yaya.bmp" +$rabbit DC8, "rabbit.bmp" +$someConstant DC32, 12456789 + +; Liste des labels +$ChoiceObject DC32, .MEDIA_02, .MEDIA_03 ; DVsxx to declare a variable in RAM, followed by the number of elements -$MyArray DV8 10 ; array of 10 bytes -$RamData1 DV32 1 ; one 32-bit integer +$MyArray DV8, 10 ; array of 10 bytes +$RamData1 DV32, 1 ; one 32-bit integer +$ChoiceMem DV32, 10 ; 10 elements for the choices, to be generated ; label definition .entry: ;; comment here should work @@ -22,13 +28,16 @@ $RamData1 DV32 1 ; one 32-bit integer lcons r1, $soundChoice ; set to 0 if no sound syscall 1 - mov r1, sp ; save sp address in R1 (first element) - lcons r0, .MEDIA_02 - push r0 + ; We put all the choices in reserved global memory + lcons t2, 4 ; address increment + lcons t0, $ChoiceMem + lcons t1, .MEDIA_02 + store @t0, t1, 4 ; @t0 = t1 + lcons r0, .MEDIA_03 push r0 - lcons r2, 3 ; 3 iterations - jump .media + lcons r2, 2 ; 3 iterations + jump .media ; no return possible, so a jump is enough ; Generic media choice manager .media: @@ -51,30 +60,26 @@ $RamData1 DV32 1 ; one 32-bit integer .media_loop: sub t0, t1 ; i-- add t4, t3 ; @++ - skipnz r0 ; if (r0) goto start_loop; + skipnz t0 ; if (r0) goto start_loop; jump .media_loop_start - push sp - push r0 - push r1 - load r0, @r4, 4 + load r0, @t4, 4 ; r0 = content in ram at address in T4 call r0 - pop r1 - pop r0 - pop sp ; TODO: wait for event + ; TODO: if ok event, free stack, then + jump .media_loop .MEDIA_02: - lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated) + lcons r0, $yaya ; image name address in ROM located in R0 (null terminated) lcons r1, $soundChoice ; set to 0 if no sound syscall 1 ret .MEDIA_03: - lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated) - lcons r1, $soundChoice ; set to 0 if no sound + lcons r0, $rabbit + lcons r1, $soundChoice syscall 1 ret