From b9a946eab41778bc9196cdb7ce5ea8b3443e9a18 Mon Sep 17 00:00:00 2001 From: "anthony@rabine.fr" Date: Sun, 6 Apr 2025 22:43:34 +0200 Subject: [PATCH] Add main entry point, fix some bugs, continue AST compilation --- .vscode/launch.json | 28 +++ core/chip32/chip32_assembler.h | 13 ++ core/chip32/chip32_machine.h | 137 ++++++++++++ core/chip32/chip32_macros.h | 2 + core/story-manager/src/base_node.cpp | 39 ++++ core/story-manager/src/base_node.h | 26 +++ core/story-manager/src/compiler.h | 207 ++++++++++++++----- core/story-manager/src/execution_node.h | 36 ++++ core/story-manager/src/function_entry_node.h | 31 +++ core/story-manager/src/function_exit_node.h | 30 +++ core/story-manager/src/operator_node.h | 31 +++ core/story-manager/src/print_node.cpp | 56 ++--- core/story-manager/src/print_node.h | 15 +- core/story-manager/tests/CMakeLists.txt | 13 +- core/story-manager/tests/test_ast.cpp | 24 ++- 15 files changed, 598 insertions(+), 90 deletions(-) create mode 100644 core/chip32/chip32_machine.h create mode 100644 core/story-manager/src/execution_node.h create mode 100644 core/story-manager/src/function_entry_node.h create mode 100644 core/story-manager/src/function_exit_node.h create mode 100644 core/story-manager/src/operator_node.h diff --git a/.vscode/launch.json b/.vscode/launch.json index 6ec4f02..d979275 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -95,6 +95,34 @@ } ] + }, + { + "name": "Debug Compiler AST Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/core/story-manager/tests/build/compiler_test", // Remplacez par le chemin de votre exécutable + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/core/story-manager/tests/build", + "environment": [], + "externalConsole": false, + "linux": { + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb" + }, + "osx": { + "MIMode": "lldb", + "miDebuggerPath": "/Users/user936511/.vscode/extensions/ms-vscode.cpptools-1.18.5-darwin-arm64/debugAdapters/lldb-mi/bin/lldb-mi" + }, + + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, { "name": "Black Magic Probe", diff --git a/core/chip32/chip32_assembler.h b/core/chip32/chip32_assembler.h index 33d3093..955f7e6 100644 --- a/core/chip32/chip32_assembler.h +++ b/core/chip32/chip32_assembler.h @@ -119,6 +119,19 @@ public: Error GetLastError() { return m_lastError; } + bool GetMain(Instr &instr) const { + + // Find the main label + bool success = m_labels.count(".main") == 1; + + if (success) + { + instr = m_labels.at(".main"); + } + + return success; + } + private: bool CompileMnemonicArguments(Instr &instr); diff --git a/core/chip32/chip32_machine.h b/core/chip32/chip32_machine.h new file mode 100644 index 0000000..b995a96 --- /dev/null +++ b/core/chip32/chip32_machine.h @@ -0,0 +1,137 @@ +#pragma once + + + +#include +#include +#include +#include + +#include "chip32_assembler.h" +#include "chip32_macros.h" + +namespace Chip32 +{ + +class Machine +{ +public: + bool parseResult{false}; + bool buildResult{false}; + chip32_result_t runResult{VM_OK}; + + static int get_from_memory(chip32_ctx_t *ctx, uint32_t addr, char *text) + { + int valid = 0; + + // Test if address is valid + + bool isRam = addr & 0x80000000; + addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing + if (isRam) { + strcpy(&text[0], (const char *)&ctx->ram.mem[addr]); + } else { + strcpy(&text[0], (const char *)&ctx->rom.mem[addr]); + } + + return valid; + } + + + + static uint8_t story_player_syscall(chip32_ctx_t *ctx, uint8_t code) + { + uint8_t retCode = SYSCALL_RET_OK; + char working_buf[100] = {0}; + + // Printf + if (code == 4) + { + // In R0: string with escaped characters + // R1: Number of arguments + // R2, R3 ... arguments + + // Integers: stored in registers by values + // Strings: first character address in register + + get_from_memory(ctx, ctx->registers[R0], working_buf); + int arg_count = ctx->registers[R1]; + + switch(arg_count){ + case 0: + puts(working_buf); + break; + case 1: + printf(working_buf, ctx->registers[R2]); + puts(""); + break; + case 2: + printf(working_buf, ctx->registers[R2], ctx->registers[R3]); + puts(""); + break; + case 3: + printf(working_buf, ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]); + puts(""); + break; + default: + break; + } + + } + // WAIT (sleep) + else if (code == 5) + { + std::this_thread::sleep_for(std::chrono::milliseconds(ctx->registers[R0])); + } + + return retCode; + } + + + + void QuickExecute(const std::string &assemblyCode) + { + std::vector program; + Chip32::Assembler assembler; + Chip32::Result result; + uint8_t data[8*1024]; + + parseResult = assembler.Parse(assemblyCode); + + std::cout << assembler.GetLastError().ToString() << std::endl; + + + buildResult = assembler.BuildBinary(program, result); + result.Print(); + + chip32_ctx_t chip32_ctx; + + chip32_ctx.stack_size = 512; + + chip32_ctx.rom.mem = program.data(); + chip32_ctx.rom.addr = 0; + chip32_ctx.rom.size = program.size(); + + chip32_ctx.ram.mem = data; + chip32_ctx.ram.addr = 40 *1024; + chip32_ctx.ram.size = sizeof(data); + + chip32_ctx.syscall = story_player_syscall; + + chip32_initialize(&chip32_ctx); + + Instr mainLine; + if (assembler.GetMain(mainLine)) + { + // set pointer counter to the main line + chip32_ctx.registers[PC] = mainLine.addr; + } + + runResult = chip32_run(&chip32_ctx); + } + + +}; + + +} // namespace Chip32 diff --git a/core/chip32/chip32_macros.h b/core/chip32/chip32_macros.h index e12af80..5fcb2b0 100644 --- a/core/chip32/chip32_macros.h +++ b/core/chip32/chip32_macros.h @@ -22,6 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#pragma once + #include #include #include diff --git a/core/story-manager/src/base_node.cpp b/core/story-manager/src/base_node.cpp index 11fe0fb..5359978 100644 --- a/core/story-manager/src/base_node.cpp +++ b/core/story-manager/src/base_node.cpp @@ -17,6 +17,45 @@ BaseNode::~BaseNode() std::cout << "Deleted base node" << std::endl; } +std::string BaseNode::GenerateRandomString(size_t length, uint32_t flags) +{ + std::string charset = ""; + + if (flags & CHARSET_ALPHABET_LOWER) + { + charset += "abcdefghijklmnopqrstuvwxyz"; + } + + if (flags & CHARSET_ALPHABET_UPPER) + { + charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + } + + if (flags & CHARSET_NUMBERS) + { + charset += "0123456789"; + } + + if (flags & CHARSET_SIGNS) + { + charset += "!@#$%^&*()_+-=[]{}|;:,.<>?"; + } + + std::random_device rd; + std::mt19937 generator(rd()); + std::uniform_int_distribution<> distribution(0, charset.size() - 1); + + std::string result; + result.reserve(length); + + for (size_t i = 0; i < length; ++i) { + result += charset[distribution(generator)]; + } + + return result; +} + + std::string BaseNode::GetEntryLabel(const std::string &id) { std::stringstream ss; diff --git a/core/story-manager/src/base_node.h b/core/story-manager/src/base_node.h index 9f74d73..6ac4103 100644 --- a/core/story-manager/src/base_node.h +++ b/core/story-manager/src/base_node.h @@ -19,6 +19,24 @@ public: float y; }; + +/* + + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "!@#$%^&*()_+-=[]{}|;:,.<>?"; +*/ + + enum RandomFlags + { + CHARSET_ALPHABET_LOWER = 0x1, + CHARSET_ALPHABET_UPPER = 0x2, + CHARSET_NUMBERS = 0x4, + CHARSET_SIGNS = 0x8, + ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS + }; + BaseNode(const std::string &type, const std::string &typeName); virtual ~BaseNode(); @@ -28,12 +46,19 @@ public: virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) = 0; virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) = 0; + virtual std::string GenerateConstants() const { return ""; } + virtual std::string GenerateAssembly() const = 0; + void SetPosition(float x, float y); // make this virtual so that graphical node override the behavior virtual float GetX() const; virtual float GetY() const; + std::string GetMyEntryLabel() const { + return GetEntryLabel(m_uuid); + } + // Coded type, internal use std::string GetType() const { @@ -59,6 +84,7 @@ public: void SetInternalData(const nlohmann::json &j); nlohmann::json GetInternalData() const; + static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS); private: std::string m_title{"Default title"}; diff --git a/core/story-manager/src/compiler.h b/core/story-manager/src/compiler.h index 5f6a59b..939af6f 100644 --- a/core/story-manager/src/compiler.h +++ b/core/story-manager/src/compiler.h @@ -56,11 +56,11 @@ public: for (auto& node : nodes) { auto astNode = std::make_shared(); - astNode->position = {0, 0}; - x += 10; // Espacement horizontal - if (x > 50) { // Nouvelle ligne + astNode->position = {x, y}; + x += 1; // Espacement horizontal + if (x > 20) { // Nouvelle ligne x = 0; - y += 5; // Espacement vertical + y += 1; // Espacement vertical } astNode->node = node; @@ -75,74 +75,173 @@ public: } // Gestion des conditions et des corps de boucles/branches - /* - for(auto& node : nodes) { - if (node.type == Node::Type::LOOP || node.type == Node::Type::BRANCH){ + for (auto& node : nodes) { + std::string nodeType = node->GetTypeName(); + if (nodeType == "LOOP" || nodeType == "BRANCH") { for (auto& connection : connections) { - if (connection.inNodeId == node.id && connection.inPortIndex == 0) { // Condition - node.condition = nodeMap[connection.outNodeId]; - } - if (connection.inNodeId == node.id && connection.inPortIndex == 1) { // Body - node.body.push_back(nodeMap[connection.outNodeId]); - } - if (node.type == Node::Type::BRANCH && connection.inNodeId == node.id && connection.inPortIndex == 2) { // ElseBody - if(node.elseBody == nullptr) { - node.elseBody = new Node(Node::Type::VARIABLE, "dummy"); // Créer un noeud dummy juste pour l'elsebody. - node.elseBody->body.push_back(nodeMap[connection.outNodeId]); - } else { - node.elseBody->body.push_back(nodeMap[connection.outNodeId]); + if (connection->inNodeId == node->GetId()) { + if (connection->inPortIndex == 0) { // Condition + m_ast.nodeMap[node->GetId()]->condition = m_ast.nodeMap[connection->outNodeId]; + } else if (connection->inPortIndex == 1) { // Body + m_ast.nodeMap[node->GetId()]->body.push_back(m_ast.nodeMap[connection->outNodeId]); + } else if (nodeType == "BRANCH" && connection->inPortIndex == 2) { // ElseBody + // if (m_ast.nodeMap[node->GetId()]->elseBody == nullptr) { + // auto dummyNode = std::make_shared("DummyNode"); + // auto dummyAstNode = std::make_shared(); + // dummyAstNode->node = dummyNode; + // m_ast.nodeMap[node->GetId()]->elseBody = dummyAstNode; + // } + m_ast.nodeMap[node->GetId()]->elseBody->body.push_back(m_ast.nodeMap[connection->outNodeId]); } } } } } - */ + } - // Fonction pour afficher le schéma des nœuds void displayNodeSchema() { - - // Afficher les nœuds - for (auto& astNode : m_ast.nodeMap) { - auto pos = astNode.second->position; - std::cout << "\033[" << pos.second + 1 << ";" << pos.first + 1 << "H"; // Déplacer le curseur - std::cout << "[" << astNode.second->node->GetTypeName() << "]"; + // Définir une taille fixe pour la grille + const int gridWidth = 20; // 20 cases de large + int gridHeight = 0; + + // Calculer la hauteur nécessaire pour la grille + for (const auto& astNode : m_ast.nodeMap) { + gridHeight = std::max(gridHeight, astNode.second->position.second + 1); } -/* - // Afficher les connexions - for (auto& connection : connections) { - auto outPos = nodePositions[connection.outNodeId]; - auto inPos = nodePositions[connection.inNodeId]; - - // Dessiner une ligne entre les nœuds (simplifié) - int startX = outPos.first + 10; - int startY = outPos.second + 1; - int endX = inPos.first; - int endY = inPos.second + 1; - - if (startY == endY) { // Ligne horizontale - for (int i = startX; i < endX; ++i) { - std::cout << "\033[" << startY << ";" << i + 1 << "H-"; + + // Créer une grille pour la console + std::vector> grid(gridHeight, std::vector(gridWidth, " ")); + + // Placer les nœuds dans la grille + for (const auto& astNode : m_ast.nodeMap) { + auto pos = astNode.second->position; + std::string nodeName = astNode.second->node->GetTypeName(); + + // Tronquer le nom du nœud à 3 caractères + if (nodeName.length() > 3) { + nodeName = nodeName.substr(0, 3); + } else { + // Ajouter des espaces pour centrer le nom dans la case + nodeName.insert(nodeName.end(), 3 - nodeName.length(), ' '); + } + + // Placer le nom du nœud dans la grille + grid[pos.second][pos.first] = nodeName; + } + + // Dessiner les connexions + for (const auto& astNode : m_ast.nodeMap) { + for (const auto& input : astNode.second->inputs) { + auto outPos = input->position; + auto inPos = astNode.second->position; + + // Dessiner une ligne entre les nœuds + int startX = outPos.first + 1; // Commencer après le nom du nœud + int startY = outPos.second; + int endX = inPos.first; + int endY = inPos.second; + + // Ligne horizontale + for (int i = startX; i <= endX; ++i) { + if (i < gridWidth) { + grid[startY][i][0] = '-'; // Dessiner la ligne dans la première position de la case + } } - } else { // Ligne verticale + horizontale - for (int i = startX; i < startX + (endX - startX) / 2; ++i) { - std::cout << "\033[" << startY << ";" << i + 1 << "H-"; - } - for (int i = std::min(startY, endY); i < std::max(startY, endY); ++i) { - std::cout << "\033[" << i + 1 << ";" << startX + (endX - startX) / 2 + 1 << "H|"; - } - for (int i = startX + (endX - startX) / 2 + 1; i < endX; ++i) { - std::cout << "\033[" << endY << ";" << i + 1 << "H-"; + + // Ligne verticale + for (int i = std::min(startY, endY); i <= std::max(startY, endY); ++i) { + if (i < gridHeight) { + grid[i][endX][0] = '|'; // Dessiner la ligne dans la première position de la case + } } } - std::cout << "\033[" << endY << ";" << endX << "H>"; + } + + // Afficher la grille avec des séparateurs verticaux + for (const auto& row : grid) { + for (size_t i = 0; i < row.size(); ++i) { + std::cout << row[i]; + if (i < row.size() - 1) { + std::cout << "|"; // Séparateur vertical + } + } + std::cout << std::endl; + } + } + + + + void generateAssembly() { + std::string assemblyCode; + std::map labels; + + // Generate all constants + for (const auto& astNode : m_ast.nodeMap) { + assemblyCode += astNode.second->node->GenerateConstants(); } - std::cout << "\033[" << 100 << ";" << 1 << "H"; // Déplacer le curseur en bas + // After the constants, the main entry point: + assemblyCode += ".main:\n"; + + // Générer des labels uniques pour les nœuds + for (const auto& nodePair : m_ast.nodeMap) { + std::string label = m_ast.generateLabel(m_ast); + labels[nodePair.first] = label; + + // Générer du code pour chaque type de nœud + std::string nodeType = nodePair.second->node->GetTypeName(); + if (nodeType == "LOOP") { + // Générer du code pour une boucle + assemblyCode += " ; Loop start\n"; + // Ajouter des instructions pour la condition de la boucle + if (nodePair.second->condition) { + assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n"; + assemblyCode += " skipz r0\n"; + assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n"; + } + // Ajouter des instructions pour le corps de la boucle + for (const auto& bodyNode : nodePair.second->body) { + assemblyCode += " ; Loop body\n"; + // Ajouter des instructions pour chaque nœud du corps + } + assemblyCode += " jump " + label + "\n"; // Retour au début de la boucle + } else if (nodeType == "BRANCH") { + // Générer du code pour un branchement + assemblyCode += " ; Branch start\n"; + // Ajouter des instructions pour la condition du branchement + if (nodePair.second->condition) { + assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n"; + assemblyCode += " skipnz r0\n"; + assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n"; + } + // Ajouter des instructions pour le corps du branchement + for (const auto& bodyNode : nodePair.second->body) { + assemblyCode += " ; Branch body\n"; + // Ajouter des instructions pour chaque nœud du corps + } + // Ajouter des instructions pour le corps du else + if (nodePair.second->elseBody) { + assemblyCode += " ; Else body\n"; + // Ajouter des instructions pour chaque nœud du corps du else + } + } else { + // Générer du code pour d'autres types de nœuds + assemblyCode += " ; Other node type: " + nodeType + "\n"; + assemblyCode += nodePair.second->node->GenerateAssembly(); - */ + // Ajouter des instructions spécifiques au type de nœud + } + } + + // Ajouter le code assembleur généré à l'AST + m_ast.assemblyCode = assemblyCode; + } + + std::string GetCode() const { + return m_ast.assemblyCode; } private: diff --git a/core/story-manager/src/execution_node.h b/core/story-manager/src/execution_node.h new file mode 100644 index 0000000..4d712a0 --- /dev/null +++ b/core/story-manager/src/execution_node.h @@ -0,0 +1,36 @@ +#pragma once + +#include "base_node.h" + +class ExecutionNode : public BaseNode +{ +public: + ExecutionNode(const std::string &type, const std::string &typeName) + : BaseNode(type, typeName) {} + + void Initialize() override { + // Initialisation spécifique pour ExecutionNode + } + + std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override { + return GetMyEntryLabel() + ":\n"; + } + + std::string GenerateAssembly() const override { + return GetMyEntryLabel() + ":\n"; + } + + std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override { + // Génération des constantes pour ExecutionNode + return "ExecutionNode Constants"; + } + + // Ajoutez des méthodes spécifiques pour gérer les entrées et sorties d'exécution + void AddExecutionInput() { + // Logique pour ajouter une entrée d'exécution + } + + void AddExecutionOutput() { + // Logique pour ajouter une sortie d'exécution + } +}; diff --git a/core/story-manager/src/function_entry_node.h b/core/story-manager/src/function_entry_node.h new file mode 100644 index 0000000..59a2be9 --- /dev/null +++ b/core/story-manager/src/function_entry_node.h @@ -0,0 +1,31 @@ +#pragma once + +#include "execution_node.h" + + +class FunctionEntryNode : public ExecutionNode +{ +public: + FunctionEntryNode(const std::string &type, const std::string &typeName) + : ExecutionNode(type, typeName) {} + + void Initialize() override { + // Initialisation spécifique pour FunctionEntryNode + // Par exemple, préparer les entrées nécessaires pour la fonction + } + + std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override { + // Logique de construction pour FunctionEntryNode + return GetMyEntryLabel() + ":\n"; + } + + std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override { + // Génération des constantes pour FunctionEntryNode + return "FunctionEntryNode Constants"; + } + + // Ajoutez des méthodes spécifiques pour gérer l'entrée de la fonction + void PrepareFunctionEntry() { + // Logique pour préparer l'entrée de la fonction + } +}; diff --git a/core/story-manager/src/function_exit_node.h b/core/story-manager/src/function_exit_node.h new file mode 100644 index 0000000..c18f9c1 --- /dev/null +++ b/core/story-manager/src/function_exit_node.h @@ -0,0 +1,30 @@ +#pragma once + +#include "execution_node.h" + +class FunctionExitNode : public ExecutionNode +{ +public: + FunctionExitNode(const std::string &type, const std::string &typeName) + : ExecutionNode(type, typeName) {} + + void Initialize() override { + // Initialisation spécifique pour FunctionExitNode + // Par exemple, préparer les sorties nécessaires pour la fonction + } + + std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override { + // Logique de construction pour FunctionExitNode + return "FunctionExitNode Build"; + } + + std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override { + // Génération des constantes pour FunctionExitNode + return "FunctionExitNode Constants"; + } + + // Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction + void FinalizeFunctionExit() { + // Logique pour finaliser la sortie de la fonction + } +}; diff --git a/core/story-manager/src/operator_node.h b/core/story-manager/src/operator_node.h new file mode 100644 index 0000000..b705486 --- /dev/null +++ b/core/story-manager/src/operator_node.h @@ -0,0 +1,31 @@ +#pragma once + +#include "base_node.h" + +class OperatorNode : public BaseNode +{ +public: + OperatorNode(const std::string &type, const std::string &typeName) + : BaseNode(type, typeName) {} + + void Initialize() override { + // Initialisation spécifique pour DataNode + } + + std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override { + // Logique de construction pour DataNode + return "DataNode Build"; + } + + std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override { + // Génération des constantes pour DataNode + return "DataNode Constants"; + } + + // Ajoutez des méthodes spécifiques pour gérer les données directement + void ProcessData() { + // Logique pour traiter les données directement + } +}; + + diff --git a/core/story-manager/src/print_node.cpp b/core/story-manager/src/print_node.cpp index a50c49d..8c1ce21 100644 --- a/core/story-manager/src/print_node.cpp +++ b/core/story-manager/src/print_node.cpp @@ -6,9 +6,9 @@ PrintNode::PrintNode(const std::string &type) - : BaseNode(type, "Print Node") + : ExecutionNode(type, "Print Node") { - + m_label = GenerateRandomString(10, BaseNode::CHARSET_ALPHABET_LOWER | BaseNode::CHARSET_ALPHABET_UPPER );// Should be enough to avoid collision? } @@ -19,35 +19,39 @@ void PrintNode::Initialize() std::string PrintNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) { - std::string s; - - - - return s; + std::stringstream ss; + ss << "$" << m_label << " DC8, " << m_text << "\n"; + return ss.str(); } std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) +{ + return ""; +} + +std::string PrintNode::GenerateConstants() const { std::stringstream ss; - - std::list> conns; - page.GetNodeConnections(conns, GetId()); - int i = 0; - std::list>::iterator c = conns.begin(); - - if (conns.size() == 2) - { - ss << R"(; ---------------------------- )" - << GetTitle() - << " Type: Branch" - << "\n"; - - ss << "eq r0, r0, r1\n" - << "skipz r0\n" - << "jump " << BaseNode::GetEntryLabel((*c)->inNodeId); - ++c; - ss << "jump " << BaseNode::GetEntryLabel((*c)->inNodeId); - } + ss << "$" << m_label << " DC8, \"" << m_text << "\"\n"; return ss.str(); } +std::string PrintNode::GenerateAssembly() const +{ + + std::stringstream ss; + + ss << ExecutionNode::GenerateAssembly() + << " push r0\n" + << " push r1\n" + << " lcons r0, $" << m_label << "\n" + << " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments + << " syscall 4\n" + << " pop r1\n" + << " pop r0\n"; + +// << ""mov r2, %2 // arguments are in r2, r3, r4 etc. + + return ss.str(); +} + diff --git a/core/story-manager/src/print_node.h b/core/story-manager/src/print_node.h index d8acd3a..6ac3e21 100644 --- a/core/story-manager/src/print_node.h +++ b/core/story-manager/src/print_node.h @@ -2,20 +2,29 @@ #include #include "i_story_manager.h" -#include "base_node.h" +#include "execution_node.h" #include "i_script_node.h" #include "i_story_project.h" -class PrintNode : public BaseNode +class PrintNode : public ExecutionNode { public: -PrintNode(const std::string &type); + PrintNode(const std::string &type); virtual void Initialize() override; virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override; virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override; + virtual std::string GenerateConstants() const override; + std::string GenerateAssembly() const override; + + void SetText(const std::string &text) { + m_text = text; + } private: + std::string m_label; + std::string m_text; // Text to print + uint32_t m_arguments{0}; // number of arguments }; diff --git a/core/story-manager/tests/CMakeLists.txt b/core/story-manager/tests/CMakeLists.txt index 1fb1fd1..8791f47 100644 --- a/core/story-manager/tests/CMakeLists.txt +++ b/core/story-manager/tests/CMakeLists.txt @@ -8,9 +8,20 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(${PROJECT_NAME} main.cpp test_ast.cpp + ../src/base_node.cpp + ../src/branch_node.cpp + ../src/print_node.cpp + ../src/variable_node.cpp + ../src/connection.cpp ../../chip32/chip32_assembler.cpp ../../chip32/chip32_vm.c ) -target_include_directories(${PROJECT_NAME} PRIVATE ../../chip32) +target_include_directories(${PROJECT_NAME} PRIVATE + ../../chip32 + ../src + ../interfaces + ../lib + ../../../shared +) diff --git a/core/story-manager/tests/test_ast.cpp b/core/story-manager/tests/test_ast.cpp index a8e0bac..e7d623c 100644 --- a/core/story-manager/tests/test_ast.cpp +++ b/core/story-manager/tests/test_ast.cpp @@ -32,6 +32,7 @@ THE SOFTWARE. #include "branch_node.h" #include "print_node.h" #include "variable_node.h" +#include "chip32_machine.h" #include #include @@ -41,19 +42,22 @@ TEST_CASE( "Check various indentations and typos" ) { Compiler compiler; - auto printNode = std::make_shared(); - auto branchNode = std::make_shared(); + auto printNode = std::make_shared("print-node"); + + printNode->SetText("Hello from OST"); + + // auto branchNode = std::make_shared("branch-node"); std::vector> nodes; nodes.push_back(printNode); - nodes.push_back(branchNode); + // nodes.push_back(branchNode); std::vector> connections; auto cn1 = std::make_shared(); - cn1-> + // // Création des nœuds // std::vector nodes = { @@ -74,10 +78,18 @@ TEST_CASE( "Check various indentations and typos" ) { // Construction de l'AST - AST ast = buildAST(nodes, connections); + compiler.buildAST(nodes, connections); + compiler.displayNodeSchema(); + + compiler.generateAssembly(); + + std::cout << compiler.GetCode() << std::endl; + Chip32::Machine machine; - REQUIRE( parseResult == true ); + machine.QuickExecute(compiler.GetCode()); + + // REQUIRE( parseResult == true ); }