diff --git a/core/chip32/chip32_compiler.cpp b/core/chip32/chip32_compiler.cpp deleted file mode 100644 index f8c5ff7..0000000 --- a/core/chip32/chip32_compiler.cpp +++ /dev/null @@ -1,306 +0,0 @@ -#include -#include -#include -#include -#include -enum class TokenType { - FUNC, IDENTIFIER, INT, CONST, VAR, IF, ELSE, WHILE, NUMBER, ASSIGN, PLUS, MINUS, MULT, DIV, SEMICOLON, - LPAREN, RPAREN, LBRACE, RBRACE, END, GREATER, LESS, EQUAL, NOTEQUAL -}; - -struct Token { - TokenType type; - std::string value; -}; - -class Lexer { -public: - Lexer(const std::string& input) : input(input), pos(0) {} - - std::vector tokenize() { - std::vector tokens; - - while (pos < input.size()) { - if (std::isspace(input[pos])) { - ++pos; - } else if (std::isalpha(input[pos])) { - std::string ident = readIdentifier(); - if (ident == "func") { - tokens.push_back({TokenType::FUNC, ident}); - } else if (ident == "int") { - tokens.push_back({TokenType::INT, ident}); - } else if (ident == "const") { - tokens.push_back({TokenType::CONST, ident}); - } else if (ident == "var") { - tokens.push_back({TokenType::VAR, ident}); - } else if (ident == "if") { - tokens.push_back({TokenType::IF, ident}); - } else if (ident == "else") { - tokens.push_back({TokenType::ELSE, ident}); - } else if (ident == "while") { - tokens.push_back({TokenType::WHILE, ident}); - } else { - tokens.push_back({TokenType::IDENTIFIER, ident}); - } - } else if (std::isdigit(input[pos])) { - tokens.push_back({TokenType::NUMBER, readNumber()}); - } else { - switch (input[pos]) { - case '(': tokens.push_back({TokenType::LPAREN, "("}); break; - case ')': tokens.push_back({TokenType::RPAREN, ")"}); break; - case '{': tokens.push_back({TokenType::LBRACE, "{"}); break; - case '}': tokens.push_back({TokenType::RBRACE, "}"}); break; - case '=': tokens.push_back({TokenType::ASSIGN, "="}); break; - case '+': tokens.push_back({TokenType::PLUS, "+"}); break; - case '-': tokens.push_back({TokenType::MINUS, "-"}); break; - case '*': tokens.push_back({TokenType::MULT, "*"}); break; - case '/': tokens.push_back({TokenType::DIV, "/"}); break; - case ';': tokens.push_back({TokenType::SEMICOLON, ";"}); break; - case '>': tokens.push_back({TokenType::GREATER, ">"}); break; - case '<': tokens.push_back({TokenType::LESS, "<"}); break; - default: std::cerr << "Caractère inattendu : " << input[pos] << std::endl; - } - ++pos; - } - } - tokens.push_back({TokenType::END, ""}); - return tokens; - } - -private: - std::string input; - size_t pos; - - std::string readIdentifier() { - size_t start = pos; - while (pos < input.size() && std::isalnum(input[pos])) ++pos; - return input.substr(start, pos - start); - } - - std::string readNumber() { - size_t start = pos; - while (pos < input.size() && std::isdigit(input[pos])) ++pos; - return input.substr(start, pos - start); - } -}; - -// AST Nodes -struct ASTNode { - virtual ~ASTNode() = default; - virtual void print(int indent = 0) const = 0; - virtual void generateAssembly(std::ofstream& out) const = 0; -}; - -struct ExpressionNode : public ASTNode { - std::string value; - ExpressionNode(std::string value) : value(std::move(value)) {} - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "Number: " << value << std::endl; - } - - void generateAssembly(std::ofstream& out) const override { - out << "\tmov eax, " << value << "\n"; - } -}; - -struct BinaryOpNode : public ASTNode { - std::unique_ptr left; - std::unique_ptr right; - TokenType op; - - BinaryOpNode(std::unique_ptr left, TokenType op, std::unique_ptr right) - : left(std::move(left)), op(op), right(std::move(right)) {} - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "BinaryOp: "; - left->print(indent + 2); - std::cout << std::string(indent + 2, ' ') << (op == TokenType::PLUS ? "+" : - op == TokenType::MINUS ? "-" : - op == TokenType::MULT ? "*" : "/") << std::endl; - right->print(indent + 2); - } - - void generateAssembly(std::ofstream& out) const override { - left->generateAssembly(out); - out << "\tpush eax\n"; - right->generateAssembly(out); - out << "\tpop ebx\n"; - - switch (op) { - case TokenType::PLUS: out << "\tadd eax, ebx\n"; break; - case TokenType::MINUS: out << "\tsub eax, ebx\n"; break; - case TokenType::MULT: out << "\timul eax, ebx\n"; break; - case TokenType::DIV: out << "\tcdq\n\tidiv ebx\n"; break; - default: break; - } - } -}; - -struct AssignmentNode : public ASTNode { - std::string varName; - std::unique_ptr expression; - - AssignmentNode(std::string varName, std::unique_ptr expression) - : varName(std::move(varName)), expression(std::move(expression)) {} - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "Assignment: " << varName << " = " << std::endl; - expression->print(indent + 2); - } - - void generateAssembly(std::ofstream& out) const override { - expression->generateAssembly(out); - out << "\tmov [" << varName << "], eax\n"; - } -}; - -struct FunctionNode : public ASTNode { - std::string name; - std::vector> body; - - FunctionNode(std::string name) : name(std::move(name)) {} - - void print(int indent = 0) const override { - std::cout << "Function: " << name << std::endl; - for (const auto& stmt : body) { - stmt->print(indent + 2); - } - } - - void generateAssembly(std::ofstream& out) const override { - out << "." << name << ":\n"; - for (const auto& stmt : body) { - stmt->generateAssembly(out); - } - out << "\tret\n"; - } -}; - -struct StatementNode : public ASTNode { - -}; - - -struct VariableDeclarationNode : public StatementNode { - std::string name; - std::unique_ptr value; - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "VarDecl: " << name << std::endl; - } - - void generateAssembly(std::ofstream& out) const override {} -}; - -struct IfNode : public StatementNode { - std::unique_ptr condition; - std::vector> thenBranch; - std::vector> elseBranch; - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "If Statement" << std::endl; - } - - void generateAssembly(std::ofstream& out) const override {} -}; - -struct WhileNode : public StatementNode { - std::unique_ptr condition; - std::vector> body; - - void print(int indent = 0) const override { - std::cout << std::string(indent, ' ') << "While Statement" << std::endl; - } - - void generateAssembly(std::ofstream& out) const override {} -}; - - - -class Parser { -public: - Parser(const std::vector& tokens) : tokens(tokens), pos(0) {} - - std::unique_ptr parse() { - if (match(TokenType::FUNC)) { - consume(TokenType::FUNC); - std::string funcName = consume(TokenType::IDENTIFIER).value; - consume(TokenType::LPAREN); - consume(TokenType::RPAREN); - consume(TokenType::LBRACE); - std::vector> body; - while (!match(TokenType::RBRACE)) { - body.push_back(parseStatement()); - } - consume(TokenType::RBRACE); - return std::make_unique(funcName); - } - return nullptr; - } - -private: - const std::vector& tokens; - size_t pos; - - bool match(TokenType type) { - return pos < tokens.size() && tokens[pos].type == type; - } - - Token consume(TokenType type) { - if (match(type)) { - return tokens[pos++]; - } - std::cout << "type: " << (int)type << std::endl; - throw std::runtime_error("Unexpected token: expected " + std::to_string(static_cast(type)) + - ", got " + std::to_string(static_cast(tokens[pos].type)) + - " (" + tokens[pos].value + ")"); - } - - std::unique_ptr parseStatement() { return nullptr; } -}; - -int main() { - std::string code = R"( - - def MaFonction() - var x - x = 5 + 3 - - - )"; - Lexer lexer(code); - std::vector tokens = lexer.tokenize(); - - for (const auto& token : tokens) { - std::cout << "Token: " << static_cast(token.type) << " (" << token.value << ")\n"; - } - - - try { - Parser parser(tokens); - std::unique_ptr ast = parser.parse(); - - - - if (ast) { - ast->print(); - - std::ofstream outFile("output.asm"); - if (outFile.is_open()) { - ast->generateAssembly(outFile); - outFile.close(); - std::cout << "Code assembleur généré dans output.asm" << std::endl; - } else { - std::cerr << "Erreur lors de l'ouverture du fichier" << std::endl; - } - } else { - std::cerr << "Erreur de parsing" << std::endl; - } - -} catch(const std::exception &e) { - std::cerr << "Erreur de parsing: " << e.what() << std::endl; -} - - return 0; -} diff --git a/core/story-manager/src/compiler.h b/core/story-manager/src/compiler.h deleted file mode 100644 index 939af6f..0000000 --- a/core/story-manager/src/compiler.h +++ /dev/null @@ -1,250 +0,0 @@ -#pragma once - -#include "sys_lib.h" -#include "i_story_project.h" -#include "base_node.h" -#include "connection.h" - -struct AstNode -{ - std::shared_ptr node; // pointeur vers le noeud en cours - - std::vector> inputs; - std::shared_ptr condition; // Pour les boucles et les branchements - std::vector> body; // Pour les boucles et les branchements - std::shared_ptr elseBody; // Pour les branchements - - std::pair position; -}; - - -// AST (Arbre de syntaxe abstraite) -struct AST { - - std::map variables; // Stockage des variables (adresses mémoire) - std::string assemblyCode; - int labelCounter = 0; - std::map> nodeMap; - - // Fonction pour générer un label unique - std::string generateLabel(AST& ast) { - return "label" + std::to_string(ast.labelCounter++); - } -}; - - - - -class Compiler -{ - -public: - Compiler() = default; - ~Compiler() = default; - - - static std::string FileToConstant(const std::string &FileName, const std::string &extension, IStoryProject &project); - - - // Fonction pour construire l'AST à partir des nœuds et des connexions - void buildAST(std::vector>& nodes, std::vector>& connections) { - - m_ast.nodeMap.clear(); - - // Créer une map pour accéder aux nœuds par ID - int x = 0, y = 0; - for (auto& node : nodes) { - auto astNode = std::make_shared(); - - astNode->position = {x, y}; - x += 1; // Espacement horizontal - if (x > 20) { // Nouvelle ligne - x = 0; - y += 1; // Espacement vertical - } - - astNode->node = node; - m_ast.nodeMap[node->GetId()] = astNode; - } - - // Construire les connexions entre les nœuds - for (auto& connection : connections) { - std::shared_ptr outNode = m_ast.nodeMap[connection->outNodeId]; - std::shared_ptr inNode = m_ast.nodeMap[connection->inNodeId]; - inNode->inputs.push_back(outNode); // Ajoute le noeud de sortie en entrée du noeud d'entrée - } - - // Gestion des conditions et des corps de boucles/branches - for (auto& node : nodes) { - std::string nodeType = node->GetTypeName(); - if (nodeType == "LOOP" || nodeType == "BRANCH") { - for (auto& connection : connections) { - 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]); - } - } - } - } - } - - - } - - - void displayNodeSchema() { - // 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); - } - - // 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 - } - } - - // 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 - } - } - } - } - - // 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(); - } - - // 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: - AST m_ast; - -}; diff --git a/core/story-manager/src/compiler/assembly_generator.h b/core/story-manager/src/compiler/assembly_generator.h new file mode 100644 index 0000000..9d89425 --- /dev/null +++ b/core/story-manager/src/compiler/assembly_generator.h @@ -0,0 +1,363 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ast_builder.h" +#include "print_node.h" +#include "function_entry_node.h" +#include "variable_node.h" +#include "branch_node.h" +#include "operator_node.h" + +class AssemblyGenerator { +public: + struct GeneratorContext { + std::string timestamp; + std::string username; + bool debugOutput; + bool optimizeCode; + int stackSize; + + GeneratorContext(const std::string& ts = "2025-04-08 12:09:01", + const std::string& user = "arabine", + bool debug = true, + bool optimize = true, + int stack = 1024) + : timestamp(ts) + , username(user) + , debugOutput(debug) + , optimizeCode(optimize) + , stackSize(stack) + {} + }; + + AssemblyGenerator(const GeneratorContext& context = GeneratorContext()) + : m_context(context) + { + Reset(); + } + + void Reset() { + m_assembly.str(""); + m_labelCounter = 0; + m_variableAddresses.clear(); + m_currentStackOffset = 0; + m_stringLiterals.clear(); + m_depth = 0; + m_currentSection = Section::NONE; + } + + std::string GenerateAssembly(const std::vector& roots) { + Reset(); + + // Generate header comments + GenerateHeader(); + + // Generate data section + StartSection(Section::DATA); + GenerateDataSection(roots); + + // Generate bss section for uninitialized data + StartSection(Section::BSS); + GenerateBssSection(); + + // Generate text section + StartSection(Section::TEXT); + GenerateTextSection(roots); + + return m_assembly.str(); + } + +protected: + enum class Section { + NONE, + DATA, + BSS, + TEXT + }; + + virtual void GenerateNodeCode(std::shared_ptr node, bool isDataPath = false) { + if (!node) return; + + if (m_context.debugOutput) { + AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")"); + } + + if (node->IsType()) { + GenerateFunctionEntry(node); + } + else if (node->IsType()) { + GenerateBranchNode(node); + } + else if (node->IsType()) { + GeneratePrintNode(node); + } + else if (node->IsType()) { + GenerateOperatorNode(node); + } + else if (node->IsType()) { + GenerateVariableNode(node); + } + + // If we're processing a data path, traverse data outputs + if (isDataPath) { + for (const auto& [port, outputs] : node->dataOutputs) { + for (const auto& target : outputs) { + GenerateNodeCode(target.node, true); + } + } + } + } + +private: + GeneratorContext m_context; + std::stringstream m_assembly; + int m_labelCounter; + std::unordered_map m_variableAddresses; + int m_currentStackOffset; + std::vector m_stringLiterals; + int m_depth; + Section m_currentSection; + + void GenerateHeader() { + m_assembly << "; Assembly generated by Visual Node Editor\n" + << "; Generation time: " << m_context.timestamp << "\n" + << "; Generated by: " << m_context.username << "\n" + << "; Optimization: " << (m_context.optimizeCode ? "enabled" : "disabled") << "\n" + << "\n"; + } + + void StartSection(Section section) { + if (m_currentSection == section) return; + + m_currentSection = section; + switch (section) { + case Section::DATA: + m_assembly << "section .data\n"; + break; + case Section::BSS: + m_assembly << "section .bss\n"; + break; + case Section::TEXT: + m_assembly << "section .text\n" + << "global _start\n\n"; + break; + default: + break; + } + } + + void GenerateDataSection(const std::vector& trees) { + // Generate string literals + for (const auto& literal : m_stringLiterals) { + std::string label = "str_" + std::to_string(m_labelCounter++); + m_assembly << label << " db '" << literal << "',0\n" + << label << "_len equ $ - " << label << "\n"; + } + + // Generate variables + for (const auto& t : trees) { + CollectVariables(t.root); + } + } + + void GenerateBssSection() { + m_assembly << " stack_space resb " << m_context.stackSize << "\n"; + } + + void GenerateTextSection(const std::vector& trees) { + // Program entry point + m_assembly << "_start:\n"; + + // Setup stack frame + m_assembly << " mov ebp, esp\n" + << " sub esp, " << m_context.stackSize << "\n\n"; + + // Process execution paths first + for (const auto& tree : trees) { + if (tree.isExecutionPath) { + GenerateNodeCode(tree.root); + } + } + + // Process data paths + for (const auto& tree : trees) { + if (!tree.isExecutionPath) { + GenerateNodeCode(tree.root, true); + } + } + + // Program exit + GenerateExit(); + } + + void GenerateFunctionEntry(std::shared_ptr node) { + AddComment("Function Entry"); + m_depth++; + + for (auto& child : node->children) { + GenerateNodeCode(child); + } + + m_depth--; + } + + void GenerateBranchNode(std::shared_ptr node) { + std::string labelTrue = GenerateUniqueLabel("true"); + std::string labelFalse = GenerateUniqueLabel("false"); + std::string labelEnd = GenerateUniqueLabel("end"); + + AddComment("Branch condition evaluation"); + m_depth++; + + // Generate condition code + if (auto conditionNode = node->GetDataInput(0)) { + GenerateNodeCode(conditionNode); + } + + // Compare result and jump + m_assembly << " pop eax\n" + << " cmp eax, 0\n" + << " je " << labelFalse << "\n"; + + // True branch + m_assembly << labelTrue << ":\n"; + if (node->GetChildCount() > 0) { + GenerateNodeCode(node->GetChild(0)); + } + m_assembly << " jmp " << labelEnd << "\n"; + + // False branch + m_assembly << labelFalse << ":\n"; + if (node->GetChildCount() > 1) { + GenerateNodeCode(node->GetChild(1)); + } + + m_assembly << labelEnd << ":\n"; + m_depth--; + } + + void GeneratePrintNode(std::shared_ptr node) { + auto* printNode = node->GetAs(); + if (!printNode) return; + + std::string text = printNode->GetText(); + std::string label = AddStringLiteral(text); + + // System call to write + m_assembly << " mov edx, " << label << "_len\n" + << " mov ecx, " << label << "\n" + << " mov ebx, 1\n" // stdout + << " mov eax, 4\n" // sys_write + << " int 0x80\n"; + } + + void GenerateOperatorNode(std::shared_ptr node) { + auto* opNode = node->GetAs(); + if (!opNode) return; + + AddComment("Operator: " + std::to_string(static_cast(opNode->GetOperationType()))); + m_depth++; + + // Generate code for operands + for (const auto& [port, inputNode] : node->dataInputs) { + GenerateNodeCode(inputNode); + } + + // Generate operator code + switch (opNode->GetOperationType()) { + case OperatorNode::OperationType::ADD: + m_assembly << " pop ebx\n" + << " pop eax\n" + << " add eax, ebx\n" + << " push eax\n"; + break; + case OperatorNode::OperationType::SUBTRACT: + m_assembly << " pop ebx\n" + << " pop eax\n" + << " sub eax, ebx\n" + << " push eax\n"; + break; + case OperatorNode::OperationType::MULTIPLY: + m_assembly << " pop ebx\n" + << " pop eax\n" + << " imul eax, ebx\n" + << " push eax\n"; + break; + case OperatorNode::OperationType::DIVIDE: + m_assembly << " pop ebx\n" + << " pop eax\n" + << " cdq\n" + << " idiv ebx\n" + << " push eax\n"; + break; + // Add other operators... + } + + m_depth--; + } + + void GenerateVariableNode(std::shared_ptr node) { + auto* varNode = node->GetAs(); + if (!varNode) return; + + std::string varName = varNode->GetVariableName(); + + AddComment("Load variable: " + varName); + m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n" + << " push eax\n"; + } + + void GenerateExit() { + AddComment("Program exit"); + m_assembly << " mov eax, 1\n" // sys_exit + << " mov ebx, 0\n" // return 0 + << " int 0x80\n"; + } + + void CollectVariables(std::shared_ptr node) { + if (!node) return; + + if (node->IsType()) { + auto* varNode = node->GetAs(); + std::string varName = varNode->GetVariableName(); + if (m_variableAddresses.find(varName) == m_variableAddresses.end()) { + m_variableAddresses[varName] = varName; + m_assembly << varName << ":\n" << varNode->GenerateAssembly(); + } + } + + // Traverse children + for (auto& child : node->children) { + CollectVariables(child); + } + + // Traverse data inputs + for (const auto& [port, inputNode] : node->dataInputs) { + CollectVariables(inputNode); + } + } + + std::string AddStringLiteral(const std::string& text) { + std::string label = "str_" + std::to_string(m_stringLiterals.size()); + m_stringLiterals.push_back(text); + return label; + } + + std::string GenerateUniqueLabel(const std::string& prefix) { + return prefix + "_" + std::to_string(m_labelCounter++); + } + + void AddComment(const std::string& comment) { + if (m_context.debugOutput) { + m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n"; + } + } +}; \ No newline at end of file diff --git a/core/story-manager/src/compiler/ast_builder.h b/core/story-manager/src/compiler/ast_builder.h new file mode 100644 index 0000000..ad79c29 --- /dev/null +++ b/core/story-manager/src/compiler/ast_builder.h @@ -0,0 +1,293 @@ +#pragma once + + +#include "base_node.h" +#include "connection.h" +#include "function_entry_node.h" + +#include +#include +#include + +class ASTNode { +public: + // Structure to represent a data connection target + struct DataTarget { + std::shared_ptr node; + unsigned int portIndex; + }; + + explicit ASTNode(std::shared_ptr node) + : node(node) {} + + // The actual node from the visual editor + std::shared_ptr node; + + // Execution flow children (for EXECUTION_LINKJ connections) + std::vector> children; + + // Data inputs: port_index -> source node + std::unordered_map> dataInputs; + + // Data outputs: output_port_index -> vector of (target node, target port) + std::unordered_map> dataOutputs; + + // Helper methods + bool HasDataInput(unsigned int portIndex) const { + return dataInputs.find(portIndex) != dataInputs.end(); + } + + bool HasDataOutput(unsigned int portIndex) const { + return dataOutputs.find(portIndex) != dataOutputs.end(); + } + + std::shared_ptr GetDataInput(unsigned int portIndex) const { + auto it = dataInputs.find(portIndex); + if (it != dataInputs.end()) { + return it->second; + } + return nullptr; + } + + const std::vector& GetDataOutputs(unsigned int portIndex) const { + static const std::vector empty; + auto it = dataOutputs.find(portIndex); + if (it != dataOutputs.end()) { + return it->second; + } + return empty; + } + + // Add a data input connection + void AddDataInput(unsigned int portIndex, std::shared_ptr sourceNode) { + dataInputs[portIndex] = sourceNode; + } + + // Add a data output connection + void AddDataOutput(unsigned int sourcePort, std::shared_ptr targetNode, unsigned int targetPort) { + DataTarget target{targetNode, targetPort}; + dataOutputs[sourcePort].push_back(target); + } + + // Add an execution child + void AddChild(std::shared_ptr child) { + children.push_back(child); + } + + // Get execution path child count + size_t GetChildCount() const { + return children.size(); + } + + // Get child at specific index + std::shared_ptr GetChild(size_t index) const { + if (index < children.size()) { + return children[index]; + } + return nullptr; + } + + // Utility method to check if this is a specific node type + template + bool IsType() const { + return dynamic_cast(node.get()) != nullptr; + } + + // Get node as specific type + template + T* GetAs() const { + return dynamic_cast(node.get()); + } + + // Debug information + std::string GetDebugString() const { + std::string result = "Node: " + node->GetTypeName() + " (ID: " + node->GetId() + ")\n"; + + // Add data inputs info + for (const auto& [port, input] : dataInputs) { + result += " Input port " + std::to_string(port) + + " <- " + input->node->GetTypeName() + "\n"; + } + + // Add data outputs info + for (const auto& [port, outputs] : dataOutputs) { + for (const auto& target : outputs) { + result += " Output port " + std::to_string(port) + + " -> " + target.node->node->GetTypeName() + + " (port " + std::to_string(target.portIndex) + ")\n"; + } + } + + // Add execution children info + for (size_t i = 0; i < children.size(); ++i) { + result += " Child " + std::to_string(i) + ": " + + children[i]->node->GetTypeName() + "\n"; + } + + return result; + } +}; + +struct PathTree { + std::shared_ptr root; + std::vector> connections; + bool isExecutionPath; // true for main flow, false for input paths +}; + +class ASTBuilder { +public: + + ASTBuilder(const std::vector>& nodes, + const std::vector>& connections) + : m_nodes(nodes), m_connections(connections) {} + + std::vector BuildAST() { + // Create node map for quick lookups + std::unordered_map> nodeMap; + for (const auto& node : m_nodes) { + nodeMap[node->GetId()] = node; + } + + // Find all root nodes (nodes without incoming execution connections) + std::unordered_set hasIncomingExec; + std::unordered_set hasIncomingData; + + for (const auto& conn : m_connections) { + if (conn->type == Connection::EXECUTION_LINKJ) { + hasIncomingExec.insert(conn->inNodeId); + } else { + hasIncomingData.insert(conn->inNodeId); + } + } + + // Collect root nodes + std::vector> execRoots; + std::vector> dataRoots; + + for (const auto& node : m_nodes) { + if (hasIncomingExec.find(node->GetId()) == hasIncomingExec.end()) { + if (dynamic_cast(node.get())) { + execRoots.push_back(node); + } + } + // Nodes that have data outputs but no data inputs are data path roots + if (hasIncomingData.find(node->GetId()) == hasIncomingData.end()) { + // Check if the node has any outgoing data connections + bool hasDataOutput = false; + for (const auto& conn : m_connections) { + if (conn->type == Connection::DATA_LINK && + conn->outNodeId == node->GetId()) { + hasDataOutput = true; + break; + } + } + if (hasDataOutput) { + dataRoots.push_back(node); + } + } + } + + std::vector pathTrees; + + // Build execution path trees + for (const auto& root : execRoots) { + PathTree tree; + tree.root = std::make_shared(root); + tree.isExecutionPath = true; + BuildExecutionPath(tree, nodeMap); + pathTrees.push_back(tree); + } + + // Build data path trees + for (const auto& root : dataRoots) { + PathTree tree; + tree.root = std::make_shared(root); + tree.isExecutionPath = false; + BuildDataPath(tree, nodeMap); + pathTrees.push_back(tree); + } + + return pathTrees; + } + +private: + const std::vector>& m_nodes; + const std::vector>& m_connections; + + void BuildExecutionPath(PathTree& tree, + const std::unordered_map>& nodeMap) { + std::queue> queue; + queue.push(tree.root); + + while (!queue.empty()) { + auto current = queue.front(); + queue.pop(); + + // Find execution connections from this node + for (const auto& conn : m_connections) { + if (conn->type == Connection::EXECUTION_LINKJ && + conn->outNodeId == current->node->GetId()) { + auto targetNode = nodeMap.find(conn->inNodeId); + if (targetNode != nodeMap.end()) { + auto childNode = std::make_shared(targetNode->second); + current->children.push_back(childNode); + queue.push(childNode); + tree.connections.push_back(conn); + + // For each execution node, find its data inputs + BuildDataInputs(childNode, nodeMap); + } + } + } + } + } + + void BuildDataPath(PathTree& tree, + const std::unordered_map>& nodeMap) { + std::queue> queue; + queue.push(tree.root); + std::unordered_set visited; + + while (!queue.empty()) { + auto current = queue.front(); + queue.pop(); + + if (visited.find(current->node->GetId()) != visited.end()) { + continue; + } + visited.insert(current->node->GetId()); + + // Find data connections from this node + for (const auto& conn : m_connections) { + if (conn->type == Connection::DATA_LINK && + conn->outNodeId == current->node->GetId()) { + auto targetNode = nodeMap.find(conn->inNodeId); + if (targetNode != nodeMap.end()) { + auto childNode = std::make_shared(targetNode->second); + current->dataOutputs[conn->outPortIndex].push_back( + {childNode, conn->inPortIndex}); + queue.push(childNode); + tree.connections.push_back(conn); + } + } + } + } + } + + void BuildDataInputs(std::shared_ptr node, + const std::unordered_map>& nodeMap) { + for (const auto& conn : m_connections) { + if (conn->type == Connection::DATA_LINK && + conn->inNodeId == node->node->GetId()) { + auto sourceNode = nodeMap.find(conn->outNodeId); + if (sourceNode != nodeMap.end()) { + auto inputNode = std::make_shared(sourceNode->second); + node->dataInputs[conn->inPortIndex] = inputNode; + } + } + } + } +}; diff --git a/core/story-manager/src/compiler.cpp b/core/story-manager/src/compiler/compiler.cpp similarity index 100% rename from core/story-manager/src/compiler.cpp rename to core/story-manager/src/compiler/compiler.cpp diff --git a/core/story-manager/src/compiler/compiler.h b/core/story-manager/src/compiler/compiler.h new file mode 100644 index 0000000..d751d2a --- /dev/null +++ b/core/story-manager/src/compiler/compiler.h @@ -0,0 +1,442 @@ +#pragma once + +#include "sys_lib.h" +#include "i_story_project.h" +#include "base_node.h" +#include "connection.h" +#include "function_entry_node.h" + +struct AstNode +{ + std::shared_ptr node; // pointeur vers le noeud en cours + + std::vector> inputs; + std::shared_ptr condition; // Pour les boucles et les branchements + std::vector> body; // Pour les boucles et les branchements + std::shared_ptr elseBody; // Pour les branchements + + std::pair position; +}; + + + +// AST (Arbre de syntaxe abstraite) +struct AST { + + std::map variables; // Stockage des variables (adresses mémoire) + std::string assemblyCode; + int labelCounter = 0; + std::map> nodeMap; + + // Fonction pour générer un label unique + std::string generateLabel(AST& ast) { + return "label" + std::to_string(ast.labelCounter++); + } +}; + +class Compiler +{ + +public: + Compiler() = default; + ~Compiler() = default; + + + static std::string FileToConstant(const std::string &FileName, const std::string &extension, IStoryProject &project); + + + // Fonction pour construire l'AST à partir des nœuds et des connexions + void buildAST(std::vector>& nodes, std::vector>& connections) { + + m_ast.nodeMap.clear(); + + // Créer une map pour accéder aux nœuds par ID + int x = 0, y = 0; + for (auto& node : nodes) { + auto astNode = std::make_shared(); + + astNode->position = {x, y}; + x += 1; // Espacement horizontal + if (x > 20) { // Nouvelle ligne + x = 0; + y += 1; // Espacement vertical + } + + astNode->node = node; + m_ast.nodeMap[node->GetId()] = astNode; + } + + // Analyser les connexions pour établir les relations entre les nœuds + for (const auto& connection : connections) { + auto outNode = m_ast.nodeMap[connection->outNodeId]; + auto inNode = m_ast.nodeMap[connection->inNodeId]; + + // // Utiliser les indices des ports pour établir les connexions + // if (outNode->inputs.size() <= connection->inPortIndex) { + // outNode->inputs.resize(connection->inPortIndex + 1); + // } + // outNode->inputs[connection->inPortIndex] = inNode; + + // Gérer les sorties en utilisant connection->outPortIndex + if (outNode->body.size() <= connection->outPortIndex) { + outNode->body.resize(connection->outPortIndex + 1); + } + outNode->body[connection->outPortIndex] = inNode; + } + } + + + + + void printAST(const AST& ast, const std::shared_ptr& node, const std::string& prefix = "", bool isLast = true) { + // Afficher le nœud actuel + std::cout << prefix; + std::cout << (isLast ? "└──" : "├──"); + + // Afficher les informations du nœud + std::cout << "Node: " << node->node->GetTypeName() << " (" << node->node->GetId() << ")" << std::endl; + + // Préparer le préfixe pour les enfants + std::string newPrefix = prefix + (isLast ? " " : "│ "); + + // Parcourir les entrées (inputs) du nœud + // for (size_t i = 0; i < node->inputs.size(); ++i) { + // bool isLastInput = (i == node->inputs.size() - 1); + // printAST(ast, node->inputs[i], newPrefix, isLastInput); + // } + + // Parcourir les sorties (body) du nœud + for (size_t i = 0; i < node->body.size(); ++i) { + bool isLastBody = (i == node->body.size() - 1); + printAST(ast, node->body[i], newPrefix, isLastBody); + } + + // Parcourir le conditionnel (condition) du nœud, s'il existe + if (node->condition) { + printAST(ast, node->condition, newPrefix, true); + } + + // Parcourir le corps du else (elseBody) du nœud, s'il existe + if (node->elseBody) { + printAST(ast, node->elseBody, newPrefix, true); + } + } + + void printAST() { + // Trouver le nœud de type "function-entry-node" + std::shared_ptr entryNode; + for (const auto& pair : m_ast.nodeMap) { + if (pair.second->node->GetType() == "function-entry-node") { + entryNode = pair.second; + break; + } + } + + if (!entryNode) { + std::cerr << "No function-entry-node found in the AST." << std::endl; + return; + } + + // Commencer l'affichage de l'arbre à partir du nœud d'entrée + printAST(m_ast, entryNode); + } + + void generateAssembly() { + std::ostringstream assemblyCode; + std::map labels; + + // Trouver le nœud de type "function-entry-node" + std::shared_ptr entryNode; + for (const auto& pair : m_ast.nodeMap) { + if (pair.second->node->GetType() == "function-entry-node") { + entryNode = pair.second; + break; + } + } + + if (!entryNode) { + throw std::runtime_error("No function-entry-node found in the AST."); + } + + // Fonction récursive pour générer le code assembleur + std::function&)> generateCode = [&](const std::shared_ptr& node) { + if (node->node->GetType() == "print") { + // Générer le code pour un nœud de type "print" + assemblyCode << "PRINT "; + // Supposons que le nœud print a une entrée qui est une variable + if (!node->inputs.empty()) { + assemblyCode << node->inputs[0]->node->GetTitle(); + } + assemblyCode << std::endl; + } else if (node->node->GetType() == "variable-node") { + // Générer le code pour un nœud de type "variable-node" + assemblyCode << "LOAD " << node->node->GetTitle() << " INTO REGISTER" << std::endl; + } else if (node->node->GetType() == "branch-node") { + // Générer le code pour un nœud de type "branch-node" + assemblyCode << "BRANCH TO LABEL_" << node->node->GetId() << std::endl; + // Générer le code pour les sorties du nœud branch + for (const auto& outputNode : node->body) { + generateCode(outputNode); + } + } else if (node->node->GetType() == "function-entry-node") { + // Générer le code pour un nœud de type "function-entry-node" + assemblyCode << "FUNCTION ENTRY POINT" << std::endl; + // Générer le code pour les nœuds connectés à ce nœud + for (const auto& inputNode : node->inputs) { + generateCode(inputNode); + } + } + }; + + // Generate all constants + for (const auto& astNode : m_ast.nodeMap) { + assemblyCode << astNode.second->node->GenerateConstants(); + } + + // After the constants, the main entry point: + assemblyCode << ".main:\n"; + + // Commencer la génération de code à partir du nœud d'entrée + generateCode(entryNode); + + // Stocker le code assembleur généré dans l'AST + m_ast.assemblyCode = assemblyCode.str(); + } + + std::string GetCode() const { + return m_ast.assemblyCode; + } + +private: + AST m_ast; + +}; + +/* + +class AssemblyGenerator { + public: + AssemblyGenerator() { + Reset(); + } + + void Reset() { + m_assembly.str(""); + m_labelCounter = 0; + m_variableAddresses.clear(); + m_currentStackOffset = 0; + } + + std::string GenerateAssembly(const std::vector>& roots) { + Reset(); + + // Generate data section + m_assembly << "section .data\n"; + // Add string constants for print nodes + m_assembly << "msg_good db 'Good!',0xa,0\n"; + m_assembly << "msg_bad db 'Bad :(',0xa,0\n"; + + // Generate code section + m_assembly << "\nsection .text\n"; + m_assembly << "global _start\n\n"; + m_assembly << "_start:\n"; + + // Generate entry point code + for (const auto& root : roots) { + GenerateNodeCode(root); + } + + // Add exit syscall + m_assembly << " mov eax, 1\n"; // exit syscall + m_assembly << " mov ebx, 0\n"; // return 0 + m_assembly << " int 0x80\n"; + + return m_assembly.str(); + } + + private: + std::stringstream m_assembly; + int m_labelCounter; + std::unordered_map m_variableAddresses; + int m_currentStackOffset; + + std::string GenerateUniqueLabel(const std::string& prefix) { + return prefix + "_" + std::to_string(m_labelCounter++); + } + + void GenerateNodeCode(std::shared_ptr node) { + if (!node) return; + + if (node->IsType()) { + // Generate code for function entry + m_assembly << " ; Function Entry\n"; + for (auto& child : node->children) { + GenerateNodeCode(child); + } + } + else if (node->IsType()) { + GenerateBranchCode(node); + } + else if (node->IsType()) { + GeneratePrintCode(node); + } + else if (node->IsType()) { + GenerateVariableCode(node); + } + else if (node->IsType()) { + GenerateOperatorCode(node); + } + } + + void GenerateBranchCode(std::shared_ptr node) { + std::string labelTrue = GenerateUniqueLabel("true"); + std::string labelFalse = GenerateUniqueLabel("false"); + std::string labelEnd = GenerateUniqueLabel("end"); + + m_assembly << " ; Branch condition evaluation\n"; + + // Generate condition code + if (auto conditionNode = node->GetDataInput(0)) { + GenerateNodeCode(conditionNode); + } + + m_assembly << " pop eax\n"; + m_assembly << " cmp eax, 0\n"; + m_assembly << " je " << labelFalse << "\n"; + + // True branch + m_assembly << labelTrue << ":\n"; + if (node->GetChildCount() > 0) { + GenerateNodeCode(node->GetChild(0)); + } + m_assembly << " jmp " << labelEnd << "\n"; + + // False branch + m_assembly << labelFalse << ":\n"; + if (node->GetChildCount() > 1) { + GenerateNodeCode(node->GetChild(1)); + } + + m_assembly << labelEnd << ":\n"; + } + + void GeneratePrintCode(std::shared_ptr node) { + auto* printNode = node->GetAs(); + if (!printNode) return; + + m_assembly << " ; Print message\n"; + if (printNode->GetText() == "Good!") { + m_assembly << " mov edx, 6\n"; // message length + m_assembly << " mov ecx, msg_good\n"; + } else { + m_assembly << " mov edx, 6\n"; // message length + m_assembly << " mov ecx, msg_bad\n"; + } + m_assembly << " mov ebx, 1\n"; // file descriptor (stdout) + m_assembly << " mov eax, 4\n"; // sys_write + m_assembly << " int 0x80\n"; + } + + void GenerateVariableCode(std::shared_ptr node) { + auto* varNode = node->GetAs(); + if (!varNode) return; + + // For this example, we'll just push a value onto the stack + std::string varName = varNode->GetVariableName(); + if (m_variableAddresses.find(varName) == m_variableAddresses.end()) { + m_variableAddresses[varName] = m_currentStackOffset; + m_currentStackOffset += 4; + } + + m_assembly << " ; Load variable " << varName << "\n"; + m_assembly << " mov eax, [ebp-" << m_variableAddresses[varName] << "]\n"; + m_assembly << " push eax\n"; + } + + void GenerateOperatorCode(std::shared_ptr node) { + auto* opNode = node->GetAs(); + if (!opNode) return; + + // Generate code for operands + for (const auto& [port, inputNode] : node->dataInputs) { + GenerateNodeCode(inputNode); + } + + m_assembly << " ; Operator " << static_cast(opNode->GetOperationType()) << "\n"; + + switch (opNode->GetOperationType()) { + case OperatorNode::ADD: + m_assembly << " pop ebx\n"; + m_assembly << " pop eax\n"; + m_assembly << " add eax, ebx\n"; + m_assembly << " push eax\n"; + break; + case OperatorNode::SUBTRACT: + m_assembly << " pop ebx\n"; + m_assembly << " pop eax\n"; + m_assembly << " sub eax, ebx\n"; + m_assembly << " push eax\n"; + break; + // Add other operators... + } + } + }; + +*/ +/* + +// 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 + } + } + + + + +*/ + diff --git a/core/story-manager/src/compiler/flow_generator.h b/core/story-manager/src/compiler/flow_generator.h new file mode 100644 index 0000000..3313be7 --- /dev/null +++ b/core/story-manager/src/compiler/flow_generator.h @@ -0,0 +1,135 @@ +#pragma once + +#include "assembly_generator.h" + +#include +#include +#include + +class FlowVisualizer { +public: + static void PrintHeader(const std::string& user, const std::string& timestamp) { + std::cout << "==========================================================\n"; + std::cout << "AST Flow Visualization\n"; + std::cout << "User: " << user << "\n"; + std::cout << "Time: " << timestamp << "\n"; + std::cout << "==========================================================\n\n"; + } + + static void PrintNodeExecution(const std::string& nodeName, int depth = 0) { + PrintTimestamp(); + std::cout << std::string(depth * 2, ' ') << "→ Executing: " << nodeName << "\n"; + } + + static void PrintDataFlow(const std::string& from, const std::string& to, + const std::string& value, int depth = 0) { + PrintTimestamp(); + std::cout << std::string(depth * 2, ' ') << " ┌─ Data: " << from + << " → " << to << " (value: " << value << ")\n"; + } + + static void PrintBranchDecision(bool condition, const std::string& value, int depth = 0) { + PrintTimestamp(); + std::cout << std::string(depth * 2, ' ') << " ├─ Branch: " + << (condition ? "TRUE" : "FALSE") << " (condition: " << value << ")\n"; + } + +private: + static void PrintTimestamp() { + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) % 1000; + + std::cout << "[" << std::put_time(std::localtime(&now_c), "%H:%M:%S") + << "." << std::setfill('0') << std::setw(3) << ms.count() << "] "; + } +}; + +class VisualFlowGenerator : public AssemblyGenerator { + +public: + VisualFlowGenerator(const GeneratorContext& context) + : AssemblyGenerator(context) + { + + } + + protected: + void GenerateNodeCode(std::shared_ptr node, bool isDataPath = false) override { + if (!node) return; + + FlowVisualizer::PrintNodeExecution(node->node->GetTypeName(), m_depth); + + if (node->IsType()) { + m_depth++; + for (auto& child : node->children) { + GenerateNodeCode(child); + } + m_depth--; + } + else if (node->IsType()) { + m_depth++; + // Get condition value + auto conditionNode = node->GetDataInput(0); + int conditionValue = EvaluateCondition(conditionNode); + + FlowVisualizer::PrintBranchDecision(conditionValue > 7, + std::to_string(conditionValue), m_depth); + + // Execute appropriate path + if (conditionValue > 7) { + GenerateNodeCode(node->GetChild(0)); // True path + } else { + GenerateNodeCode(node->GetChild(1)); // False path + } + m_depth--; + } + else if (node->IsType()) { + auto* printNode = node->GetAs(); + FlowVisualizer::PrintNodeExecution("Print: " + printNode->GetText(), m_depth); + } + else if (node->IsType()) { + m_depth++; + auto* opNode = node->GetAs(); + + // Evaluate operands + int value1 = EvaluateOperand(node->GetDataInput(0)); + int value2 = EvaluateOperand(node->GetDataInput(1)); + + FlowVisualizer::PrintDataFlow("Operand 1", "ADD", + std::to_string(value1), m_depth); + FlowVisualizer::PrintDataFlow("Operand 2", "ADD", + std::to_string(value2), m_depth); + + int result = value1 + value2; + FlowVisualizer::PrintDataFlow("ADD", "Result", + std::to_string(result), m_depth); + m_depth--; + } + } + + private: + int m_depth = 0; + + int EvaluateOperand(std::shared_ptr node) { + if (!node) return 0; + + if (node->IsType()) { + auto* varNode = node->GetAs(); + return varNode->GetValue(); + } + return 0; + } + + int EvaluateCondition(std::shared_ptr node) { + if (!node) return 0; + + if (node->IsType()) { + auto input0 = node->GetDataInput(0); + auto input1 = node->GetDataInput(1); + return EvaluateOperand(input0) + EvaluateOperand(input1); + } + return 0; + } + }; diff --git a/core/story-manager/src/base_node.cpp b/core/story-manager/src/nodes/base_node.cpp similarity index 100% rename from core/story-manager/src/base_node.cpp rename to core/story-manager/src/nodes/base_node.cpp diff --git a/core/story-manager/src/base_node.h b/core/story-manager/src/nodes/base_node.h similarity index 63% rename from core/story-manager/src/base_node.h rename to core/story-manager/src/nodes/base_node.h index 6ac4103..d1b3970 100644 --- a/core/story-manager/src/base_node.h +++ b/core/story-manager/src/nodes/base_node.h @@ -13,30 +13,50 @@ class BaseNode { public: + struct Port + { + enum Type { + EXECUTION_PORT, + DATA_PORT + }; + + Port::Type type{EXECUTION_PORT}; + std::string label; + }; + struct NodePosition { float x; float y; }; - -/* - - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - "!@#$%^&*()_+-=[]{}|;:,.<>?"; -*/ - enum RandomFlags { - CHARSET_ALPHABET_LOWER = 0x1, - CHARSET_ALPHABET_UPPER = 0x2, - CHARSET_NUMBERS = 0x4, - CHARSET_SIGNS = 0x8, + CHARSET_ALPHABET_LOWER = 0x1, // "abcdefghijklmnopqrstuvwxyz" + CHARSET_ALPHABET_UPPER = 0x2, // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + CHARSET_NUMBERS = 0x4, // "0123456789" + CHARSET_SIGNS = 0x8, // "!@#$%^&*()_+-=[]{}|;:,.<>?"; ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS }; + struct ConstantValue + { + enum Type { + TYPE_STRING, + TYPE_INT, + }; + std::string stringVal; + int intVal{0}; + ConstantValue::Type type{TYPE_INT}; + }; + + struct Constant + { + std::string label; + int elementSize; // in bits: 8, 16 or 32 + std::vector values; + }; + BaseNode(const std::string &type, const std::string &typeName); virtual ~BaseNode(); @@ -86,6 +106,21 @@ public: static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS); + void ClearPorts() { + m_inputPorts.clear(); + m_outputPorts.clear(); + } + + // Port management + void AddInputPort(Port::Type type, const std::string& label) { + m_inputPorts.push_back({type, label}); + } + + void AddOutputPort(Port::Type type, const std::string& label) { + m_outputPorts.push_back({type, label}); + } + + private: std::string m_title{"Default title"}; std::string m_type; @@ -93,6 +128,9 @@ private: std::string m_uuid; NodePosition m_pos; + std::vector m_inputPorts; + std::vector m_outputPorts; + nlohmann::json m_internal_data{{}}; }; diff --git a/core/story-manager/src/branch_node.cpp b/core/story-manager/src/nodes/branch_node.cpp similarity index 100% rename from core/story-manager/src/branch_node.cpp rename to core/story-manager/src/nodes/branch_node.cpp diff --git a/core/story-manager/src/branch_node.h b/core/story-manager/src/nodes/branch_node.h similarity index 88% rename from core/story-manager/src/branch_node.h rename to core/story-manager/src/nodes/branch_node.h index 95aabce..d153d08 100644 --- a/core/story-manager/src/branch_node.h +++ b/core/story-manager/src/nodes/branch_node.h @@ -15,6 +15,7 @@ public: 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 GenerateAssembly() const { return ""; } private: }; diff --git a/core/story-manager/src/compare_node.cpp b/core/story-manager/src/nodes/compare_node.cpp similarity index 100% rename from core/story-manager/src/compare_node.cpp rename to core/story-manager/src/nodes/compare_node.cpp diff --git a/core/story-manager/src/compare_node.h b/core/story-manager/src/nodes/compare_node.h similarity index 100% rename from core/story-manager/src/compare_node.h rename to core/story-manager/src/nodes/compare_node.h diff --git a/core/story-manager/src/connection.cpp b/core/story-manager/src/nodes/connection.cpp similarity index 100% rename from core/story-manager/src/connection.cpp rename to core/story-manager/src/nodes/connection.cpp diff --git a/core/story-manager/src/connection.h b/core/story-manager/src/nodes/connection.h similarity index 90% rename from core/story-manager/src/connection.h rename to core/story-manager/src/nodes/connection.h index 7c9ddfe..ab8545e 100644 --- a/core/story-manager/src/connection.h +++ b/core/story-manager/src/nodes/connection.h @@ -5,6 +5,13 @@ struct Connection { + + enum Type + { + EXECUTION_LINKJ, + DATA_LINK + }; + Connection() : outPortIndex(0) , inPortIndex(0) @@ -16,6 +23,7 @@ struct Connection } + Connection::Type type{Connection::EXECUTION_LINKJ}; std::string outNodeId; unsigned int outPortIndex{0}; std::string inNodeId; diff --git a/core/story-manager/src/execution_node.h b/core/story-manager/src/nodes/execution_node.h similarity index 100% rename from core/story-manager/src/execution_node.h rename to core/story-manager/src/nodes/execution_node.h diff --git a/core/story-manager/src/function_entry_node.h b/core/story-manager/src/nodes/function_entry_node.h similarity index 88% rename from core/story-manager/src/function_entry_node.h rename to core/story-manager/src/nodes/function_entry_node.h index 59a2be9..1ead68f 100644 --- a/core/story-manager/src/function_entry_node.h +++ b/core/story-manager/src/nodes/function_entry_node.h @@ -6,8 +6,8 @@ class FunctionEntryNode : public ExecutionNode { public: - FunctionEntryNode(const std::string &type, const std::string &typeName) - : ExecutionNode(type, typeName) {} + FunctionEntryNode(const std::string &type) + : ExecutionNode(type, "Function Entry Node") {} void Initialize() override { // Initialisation spécifique pour FunctionEntryNode diff --git a/core/story-manager/src/function_exit_node.h b/core/story-manager/src/nodes/function_exit_node.h similarity index 100% rename from core/story-manager/src/function_exit_node.h rename to core/story-manager/src/nodes/function_exit_node.h diff --git a/core/story-manager/src/function_node.cpp b/core/story-manager/src/nodes/function_node.cpp similarity index 100% rename from core/story-manager/src/function_node.cpp rename to core/story-manager/src/nodes/function_node.cpp diff --git a/core/story-manager/src/function_node.h b/core/story-manager/src/nodes/function_node.h similarity index 100% rename from core/story-manager/src/function_node.h rename to core/story-manager/src/nodes/function_node.h diff --git a/core/story-manager/src/nodes/operator_node.h b/core/story-manager/src/nodes/operator_node.h new file mode 100644 index 0000000..b1a7b80 --- /dev/null +++ b/core/story-manager/src/nodes/operator_node.h @@ -0,0 +1,240 @@ +#pragma once + +#include "base_node.h" + +#pragma once + +#include "base_node.h" +#include +#include +#include + +class OperatorNode : public BaseNode +{ +public: + enum class OperationType { + ADD, // Addition (+) + SUBTRACT, // Subtraction (-) + MULTIPLY, // Multiplication (*) + DIVIDE, // Division (/) + MODULO, // Modulo (%) + AND, // Logical AND (&&) + OR, // Logical OR (||) + NOT, // Logical NOT (!) + XOR, // Logical XOR (^) + EQUAL, // Equal to (==) + NOT_EQUAL, // Not equal to (!=) + GREATER_THAN, // Greater than (>) + LESS_THAN, // Less than (<) + GREATER_EQUAL, // Greater than or equal (>=) + LESS_EQUAL, // Less than or equal (<=) + BITWISE_AND, // Bitwise AND (&) + BITWISE_OR, // Bitwise OR (|) + BITWISE_XOR, // Bitwise XOR (^) + BITWISE_NOT, // Bitwise NOT (~) + LEFT_SHIFT, // Left shift (<<) + RIGHT_SHIFT // Right shift (>>) + }; + + OperatorNode(const std::string& type = "operator-node", + const std::string& typeName = "Operator") + : BaseNode(type, typeName) + , m_operationType(OperationType::ADD) + { + Initialize(); + } + + void Initialize() override { + // Define input ports based on operator type + UpdatePorts(); + } + + // Set the operator type and update ports accordingly + void SetOperationType(OperationType type) { + m_operationType = type; + UpdatePorts(); + } + + OperationType GetOperationType() const { + return m_operationType; + } + + // Get the symbol representation of the operator + std::string GetOperatorSymbol() const { + static const std::unordered_map symbolMap = { + {OperationType::ADD, "+"}, + {OperationType::SUBTRACT, "-"}, + {OperationType::MULTIPLY, "*"}, + {OperationType::DIVIDE, "/"}, + {OperationType::MODULO, "%"}, + {OperationType::AND, "&&"}, + {OperationType::OR, "||"}, + {OperationType::NOT, "!"}, + {OperationType::XOR, "^"}, + {OperationType::EQUAL, "=="}, + {OperationType::NOT_EQUAL, "!="}, + {OperationType::GREATER_THAN, ">"}, + {OperationType::LESS_THAN, "<"}, + {OperationType::GREATER_EQUAL, ">="}, + {OperationType::LESS_EQUAL, "<="}, + {OperationType::BITWISE_AND, "&"}, + {OperationType::BITWISE_OR, "|"}, + {OperationType::BITWISE_XOR, "^"}, + {OperationType::BITWISE_NOT, "~"}, + {OperationType::LEFT_SHIFT, "<<"}, + {OperationType::RIGHT_SHIFT, ">>"} + }; + + auto it = symbolMap.find(m_operationType); + return it != symbolMap.end() ? it->second : "?"; + } + + std::string Build(IStoryPage& page, const StoryOptions& options, int nb_out_conns) override { + std::stringstream ss; + ss << "// Operator: " << GetOperatorSymbol() << "\n"; + + // For unary operators + if (IsUnaryOperator()) { + ss << GetOperatorSymbol() << "operand"; + } + // For binary operators + else { + ss << "operand1 " << GetOperatorSymbol() << " operand2"; + } + + return ss.str(); + } + + std::string GenerateConstants(IStoryPage& page, IStoryProject& project, int nb_out_conns) override { + return ""; // Operators don't generate constants + } + + std::string GenerateAssembly() const override { + std::stringstream ss; + + switch (m_operationType) { + case OperationType::ADD: + ss << " pop ebx\n" + << " pop eax\n" + << " add eax, ebx\n" + << " push eax\n"; + break; + case OperationType::SUBTRACT: + ss << " pop ebx\n" + << " pop eax\n" + << " sub eax, ebx\n" + << " push eax\n"; + break; + case OperationType::MULTIPLY: + ss << " pop ebx\n" + << " pop eax\n" + << " imul eax, ebx\n" + << " push eax\n"; + break; + case OperationType::DIVIDE: + ss << " pop ebx\n" + << " pop eax\n" + << " cdq\n" // Sign extend eax into edx + << " idiv ebx\n" + << " push eax\n"; // Push quotient + break; + case OperationType::AND: + ss << " pop ebx\n" + << " pop eax\n" + << " and eax, ebx\n" + << " push eax\n"; + break; + case OperationType::OR: + ss << " pop ebx\n" + << " pop eax\n" + << " or eax, ebx\n" + << " push eax\n"; + break; + // Add other operators... + } + + return ss.str(); + } + +private: + OperationType m_operationType; + + bool IsUnaryOperator() const { + return m_operationType == OperationType::NOT || + m_operationType == OperationType::BITWISE_NOT; + } + + void UpdatePorts() { + // Clear existing ports + ClearPorts(); + + // Add input ports based on operator type + if (IsUnaryOperator()) { + AddInputPort(Port::DATA_PORT, "in"); + } else { + AddInputPort(Port::DATA_PORT, "in1"); + AddInputPort(Port::DATA_PORT, "in2"); + } + + // Add output port + AddOutputPort(Port::DATA_PORT, "out"); + } + + static std::string OperatorTypeToString(OperationType type) { + static const std::unordered_map typeMap = { + {OperationType::ADD, "add"}, + {OperationType::SUBTRACT, "subtract"}, + {OperationType::MULTIPLY, "multiply"}, + {OperationType::DIVIDE, "divide"}, + {OperationType::MODULO, "modulo"}, + {OperationType::AND, "and"}, + {OperationType::OR, "or"}, + {OperationType::NOT, "not"}, + {OperationType::XOR, "xor"}, + {OperationType::EQUAL, "equal"}, + {OperationType::NOT_EQUAL, "not_equal"}, + {OperationType::GREATER_THAN, "greater_than"}, + {OperationType::LESS_THAN, "less_than"}, + {OperationType::GREATER_EQUAL, "greater_equal"}, + {OperationType::LESS_EQUAL, "less_equal"}, + {OperationType::BITWISE_AND, "bitwise_and"}, + {OperationType::BITWISE_OR, "bitwise_or"}, + {OperationType::BITWISE_XOR, "bitwise_xor"}, + {OperationType::BITWISE_NOT, "bitwise_not"}, + {OperationType::LEFT_SHIFT, "left_shift"}, + {OperationType::RIGHT_SHIFT, "right_shift"} + }; + + auto it = typeMap.find(type); + return it != typeMap.end() ? it->second : "unknown"; + } + + static OperationType StringToOperationType(const std::string& str) { + static const std::unordered_map typeMap = { + {"add", OperationType::ADD}, + {"subtract", OperationType::SUBTRACT}, + {"multiply", OperationType::MULTIPLY}, + {"divide", OperationType::DIVIDE}, + {"modulo", OperationType::MODULO}, + {"and", OperationType::AND}, + {"or", OperationType::OR}, + {"not", OperationType::NOT}, + {"xor", OperationType::XOR}, + {"equal", OperationType::EQUAL}, + {"not_equal", OperationType::NOT_EQUAL}, + {"greater_than", OperationType::GREATER_THAN}, + {"less_than", OperationType::LESS_THAN}, + {"greater_equal", OperationType::GREATER_EQUAL}, + {"less_equal", OperationType::LESS_EQUAL}, + {"bitwise_and", OperationType::BITWISE_AND}, + {"bitwise_or", OperationType::BITWISE_OR}, + {"bitwise_xor", OperationType::BITWISE_XOR}, + {"bitwise_not", OperationType::BITWISE_NOT}, + {"left_shift", OperationType::LEFT_SHIFT}, + {"right_shift", OperationType::RIGHT_SHIFT} + }; + + auto it = typeMap.find(str); + return it != typeMap.end() ? it->second : OperationType::ADD; + } +}; diff --git a/core/story-manager/src/print_node.cpp b/core/story-manager/src/nodes/print_node.cpp similarity index 100% rename from core/story-manager/src/print_node.cpp rename to core/story-manager/src/nodes/print_node.cpp diff --git a/core/story-manager/src/print_node.h b/core/story-manager/src/nodes/print_node.h similarity index 92% rename from core/story-manager/src/print_node.h rename to core/story-manager/src/nodes/print_node.h index 6ac3e21..4707eb5 100644 --- a/core/story-manager/src/print_node.h +++ b/core/story-manager/src/nodes/print_node.h @@ -22,6 +22,11 @@ public: void SetText(const std::string &text) { m_text = text; } + + std::string GetText() const { + return m_text; + } + private: std::string m_label; std::string m_text; // Text to print diff --git a/core/story-manager/src/variable_node.cpp b/core/story-manager/src/nodes/variable_node.cpp similarity index 100% rename from core/story-manager/src/variable_node.cpp rename to core/story-manager/src/nodes/variable_node.cpp diff --git a/core/story-manager/src/nodes/variable_node.h b/core/story-manager/src/nodes/variable_node.h new file mode 100644 index 0000000..62f2f96 --- /dev/null +++ b/core/story-manager/src/nodes/variable_node.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include + +#include "i_story_manager.h" +#include "base_node.h" +#include "i_script_node.h" +#include "i_story_project.h" + +class VariableNode : public BaseNode +{ +public: + + enum class ValueType { + INTEGER, + FLOAT, + BOOL, + STRING + }; + + using VariableValue = std::variant; + + VariableNode(const std::string &type = "variable-node"); + + 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 GenerateAssembly() const { return ""; } + + void StoreInternalData(); + + + // Setters + void SetVariableName(const std::string& name) { + m_variableName = name; + } + + void SetConstant(bool isConstant) { + m_isConstant = isConstant; + } + + void SetValueType(ValueType type) { + m_valueType = type; + // Reset value to default for new type + switch (type) { + case ValueType::INTEGER: + m_value = 0; + break; + case ValueType::FLOAT: + m_value = 0.0f; + break; + case ValueType::BOOL: + m_value = false; + break; + case ValueType::STRING: + m_value = ""; + break; + } + } + + template + void SetValue(const T& value) { + try { + m_value = value; + } catch (const std::bad_variant_access&) { + throw std::runtime_error("Invalid value type for variable"); + } + } + + // Getters + std::string GetVariableName() const { + return m_variableName; + } + + bool IsConstant() const { + return m_isConstant; + } + + ValueType GetValueType() const { + return m_valueType; + } + + template + T GetValue() const { + try { + return std::get(m_value); + } catch (const std::bad_variant_access&) { + throw std::runtime_error("Invalid value type requested"); + } + } + + + +private: + std::string m_variableName; + ValueType m_valueType; + VariableValue m_value; + bool m_isConstant; + +}; + diff --git a/core/story-manager/src/operator_node.h b/core/story-manager/src/operator_node.h deleted file mode 100644 index b705486..0000000 --- a/core/story-manager/src/operator_node.h +++ /dev/null @@ -1,31 +0,0 @@ -#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/variable_node.h b/core/story-manager/src/variable_node.h deleted file mode 100644 index a9aa049..0000000 --- a/core/story-manager/src/variable_node.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include "i_story_manager.h" -#include "base_node.h" -#include "i_script_node.h" -#include "i_story_project.h" - -class VariableNode : public BaseNode -{ -public: - VariableNode(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; - - void StoreInternalData(); - -private: - -}; - diff --git a/core/story-manager/tests/CMakeLists.txt b/core/story-manager/tests/CMakeLists.txt index 8791f47..ee5dc51 100644 --- a/core/story-manager/tests/CMakeLists.txt +++ b/core/story-manager/tests/CMakeLists.txt @@ -8,11 +8,13 @@ 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 + + + ../src/nodes/base_node.cpp + ../src/nodes/branch_node.cpp + ../src/nodes/print_node.cpp + ../src/nodes/variable_node.cpp + ../src/nodes/connection.cpp ../../chip32/chip32_assembler.cpp ../../chip32/chip32_vm.c @@ -24,4 +26,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE ../interfaces ../lib ../../../shared + ../src/nodes + ../src/compiler ) diff --git a/core/story-manager/tests/test_ast.cpp b/core/story-manager/tests/test_ast.cpp index e7d623c..25b5794 100644 --- a/core/story-manager/tests/test_ast.cpp +++ b/core/story-manager/tests/test_ast.cpp @@ -32,33 +32,124 @@ THE SOFTWARE. #include "branch_node.h" #include "print_node.h" #include "variable_node.h" +#include "function_entry_node.h" #include "chip32_machine.h" #include #include +#include "ast_builder.h" +#include "assembly_generator.h" +#include "flow_generator.h" +/* +void ProcessASTTree(const ASTBuilder::PathTree& tree, int depth = 0) { + std::queue, int>> queue; + queue.push({tree.root, depth}); + std::unordered_set visited; + + while (!queue.empty()) { + auto [node, currentDepth] = queue.front(); + queue.pop(); + + if (visited.find(node->node->GetId()) != visited.end()) { + continue; + } + visited.insert(node->node->GetId()); + + std::string indent(currentDepth * 2, ' '); + std::cout << indent << "Node: " << node->node->GetTypeName() + << " (ID: " << node->node->GetId() << ")" << std::endl; + + // Print data inputs + for (const auto& [portIndex, inputNode] : node->dataInputs) { + std::cout << indent << " Input at port " << portIndex + << " from: " << inputNode->node->GetTypeName() << std::endl; + } + + // Print data outputs + for (const auto& [portIndex, outputs] : node->dataOutputs) { + for (const auto& [targetNode, targetPort] : outputs) { + std::cout << indent << " Output from port " << portIndex + << " to: " << targetNode->node->GetTypeName() + << " port " << targetPort << std::endl; + } + } + + // Add children to queue + for (const auto& child : node->children) { + queue.push({child, currentDepth + 1}); + } + } +} +*/ TEST_CASE( "Check various indentations and typos" ) { Compiler compiler; - auto printNode = std::make_shared("print-node"); + auto printNodeTrue = std::make_shared("print-node"); + printNodeTrue->SetText("Good!"); - printNode->SetText("Hello from OST"); + auto printNodeFalse = std::make_shared("print-node"); + printNodeFalse->SetText("Bad :("); - // auto branchNode = std::make_shared("branch-node"); + auto branchNode = std::make_shared("branch-node"); + + auto functionEntryNode = std::make_shared("function-entry-node"); + + auto variableNode = std::make_shared("variable-node"); std::vector> nodes; - nodes.push_back(printNode); - // nodes.push_back(branchNode); + nodes.push_back(functionEntryNode); + nodes.push_back(printNodeTrue); + nodes.push_back(printNodeFalse); + nodes.push_back(branchNode); + nodes.push_back(variableNode); + + auto cn1 = std::make_shared(); + auto cn2 = std::make_shared(); + auto cn3 = std::make_shared(); + auto cn4 = std::make_shared(); std::vector> connections; - auto cn1 = std::make_shared(); + connections.push_back(cn1); + connections.push_back(cn2); + connections.push_back(cn3); + connections.push_back(cn4); + // Branch True -> print Ok + // False -> print Ko + + // True path + cn1->inNodeId = printNodeTrue->GetId(); + cn1->inPortIndex = 0; + cn1->outNodeId = branchNode->GetId(); + cn1->outPortIndex = 0; + + // False path + cn2->inNodeId = printNodeFalse->GetId(); + cn2->inPortIndex = 0; + cn2->outNodeId = branchNode->GetId(); + cn2->outPortIndex = 1; + + // Function entry -> Branch node + cn3->inNodeId = branchNode->GetId(); + cn3->inPortIndex = 0; + cn3->outNodeId = functionEntryNode->GetId(); + cn3->outPortIndex = 0; + + // Variable branch -> Branch node (condition input) + cn4->inNodeId = branchNode->GetId(); + cn4->inPortIndex = 1; + cn4->outNodeId = variableNode->GetId(); + cn4->outPortIndex = 0; + cn4->type = Connection::DATA_LINK; + + // // Création des nœuds // std::vector nodes = { // Node(Node::Type::VARIABLE, "i", "node_i"), @@ -75,20 +166,69 @@ TEST_CASE( "Check various indentations and typos" ) { // Node(Node::Type::LOOP, "node_loop") // }; + // try + // { + // // Construction de l'AST + // compiler.buildAST(nodes, connections); + // compiler.printAST(); + + // } catch(const std::exception &e) + // { + // std::cout << e.what() << std::endl; + // } - // Construction de l'AST - compiler.buildAST(nodes, connections); - compiler.displayNodeSchema(); + // Create generator context with current time and user + AssemblyGenerator::GeneratorContext context( + "2025-04-08 12:09:01", // Current UTC time + "arabine", // Current user + true, // Enable debug output + true, // Enable optimizations + 1024 // Stack size + ); - compiler.generateAssembly(); - - std::cout << compiler.GetCode() << std::endl; + // Create generator + AssemblyGenerator generator(context); - Chip32::Machine machine; + ASTBuilder builder(nodes, connections); + auto pathTrees = builder.BuildAST(); - machine.QuickExecute(compiler.GetCode()); + /* + // Process each path tree + for (const auto& tree : pathTrees) { + std::cout << (tree.isExecutionPath ? "Execution" : "Data") + << " Path Tree:" << std::endl; + ProcessASTTree(tree); + std::cout << std::endl; + } + */ + + // Generate flow in the console + VisualFlowGenerator flowGenerator(context); + std::string flow = flowGenerator.GenerateAssembly(pathTrees); + + FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01"); + std::cout << "\nGenerated flow:\n" << flow << std::endl; + + // Generate assembly + std::string assembly = generator.GenerateAssembly(pathTrees); + + + + + + + + + // compiler.generateAssembly(); + + // std::cout << compiler.GetCode() << std::endl; + + + // Chip32::Machine machine; + + // machine.QuickExecute(compiler.GetCode()); // REQUIRE( parseResult == true );