Good architecture between AST and assembly generation, still WIP
Some checks failed
Build-StoryEditor / build_linux (push) Has been cancelled
Build-StoryEditor / build_win32 (push) Has been cancelled
Deploy-Documentation / deploy (push) Has been cancelled

This commit is contained in:
anthony@rabine.fr 2025-04-17 21:14:44 +02:00
parent 183e5d0727
commit 5c16e2bd94
8 changed files with 465 additions and 289 deletions

View file

@ -16,6 +16,10 @@
#include "branch_node.h" #include "branch_node.h"
#include "operator_node.h" #include "operator_node.h"
class AssemblyGenerator { class AssemblyGenerator {
public: public:
struct GeneratorContext { struct GeneratorContext {
@ -26,7 +30,7 @@ public:
int stackSize; int stackSize;
GeneratorContext(const std::string& ts = "2025-04-08 12:09:01", GeneratorContext(const std::string& ts = "2025-04-08 12:09:01",
const std::string& user = "arabine", const std::string& user = "anonymous",
bool debug = true, bool debug = true,
bool optimize = true, bool optimize = true,
int stack = 1024) int stack = 1024)
@ -54,7 +58,9 @@ public:
m_currentSection = Section::NONE; m_currentSection = Section::NONE;
} }
std::string GenerateAssembly(const std::vector<PathTree>& roots) { std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& roots)
{
m_roots = roots;
Reset(); Reset();
// Generate header comments // Generate header comments
@ -62,11 +68,7 @@ public:
// Generate data section // Generate data section
StartSection(Section::DATA); StartSection(Section::DATA);
GenerateDataSection(roots); GenerateDataSection(nodes, roots);
// Generate bss section for uninitialized data
StartSection(Section::BSS);
GenerateBssSection();
// Generate text section // Generate text section
StartSection(Section::TEXT); StartSection(Section::TEXT);
@ -79,59 +81,46 @@ protected:
enum class Section { enum class Section {
NONE, NONE,
DATA, DATA,
BSS,
TEXT TEXT
}; };
virtual void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) { virtual void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) = 0;
if (!node) return;
if (m_context.debugOutput) { virtual void AddComment(const std::string& comment) = 0;
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
}
if (node->IsType<FunctionEntryNode>()) { virtual void GenerateExit() = 0;
GenerateFunctionEntry(node);
}
else if (node->IsType<BranchNode>()) {
GenerateBranchNode(node);
}
else if (node->IsType<PrintNode>()) {
GeneratePrintNode(node);
}
else if (node->IsType<OperatorNode>()) {
GenerateOperatorNode(node);
}
else if (node->IsType<VariableNode>()) {
GenerateVariableNode(node);
}
// If we're processing a data path, traverse data outputs
if (isDataPath) { std::string AddStringLiteral(const std::string& text)
for (const auto& [port, outputs] : node->dataOutputs) { {
for (const auto& target : outputs) { std::string label = "str_" + std::to_string(m_stringLiterals.size());
GenerateNodeCode(target.node, true); m_stringLiterals.push_back(text);
} return label;
}
}
} }
private: std::string GenerateUniqueLabel(const std::string& prefix)
{
return prefix + "_" + std::to_string(m_labelCounter++);
}
protected:
GeneratorContext m_context; GeneratorContext m_context;
std::stringstream m_assembly; std::stringstream m_assembly;
int m_labelCounter; int m_labelCounter;
std::unordered_map<std::string, std::string> m_variableAddresses; std::unordered_map<std::string, std::string> m_variableAddresses;
int m_currentStackOffset; int m_currentStackOffset;
std::vector<std::string> m_stringLiterals; std::vector<std::string> m_stringLiterals;
int m_depth; int m_depth{0};
Section m_currentSection; Section m_currentSection;
std::vector<PathTree> m_roots;
private:
void GenerateHeader() { void GenerateHeader() {
m_assembly << "; Assembly generated by Visual Node Editor\n" AddComment("Assembly generated by Visual Node Editor");
<< "; Generation time: " << m_context.timestamp << "\n" AddComment("Generation time: " + m_context.timestamp);
<< "; Generated by: " << m_context.username << "\n" AddComment("Generated by: " + m_context.username);
<< "; Optimization: " << (m_context.optimizeCode ? "enabled" : "disabled") << "\n" AddComment("Optimization: " + m_context.optimizeCode ? "enabled" : "disabled");
<< "\n";
} }
void StartSection(Section section) { void StartSection(Section section) {
@ -140,21 +129,24 @@ private:
m_currentSection = section; m_currentSection = section;
switch (section) { switch (section) {
case Section::DATA: case Section::DATA:
m_assembly << "section .data\n"; AddComment("======================= DATA =======================");
break;
case Section::BSS:
m_assembly << "section .bss\n";
break; break;
case Section::TEXT: case Section::TEXT:
m_assembly << "section .text\n" AddComment("======================= CODE =======================");
<< "global _start\n\n";
break; break;
default: default:
break; break;
} }
} }
void GenerateDataSection(const std::vector<PathTree>& trees) { void GenerateDataSection(const std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& trees) {
// Generate all constants
for (const auto& n : nodes) {
m_assembly << n->GenerateConstants();
}
// Generate string literals // Generate string literals
for (const auto& literal : m_stringLiterals) { for (const auto& literal : m_stringLiterals) {
std::string label = "str_" + std::to_string(m_labelCounter++); std::string label = "str_" + std::to_string(m_labelCounter++);
@ -168,18 +160,10 @@ private:
} }
} }
void GenerateBssSection() {
m_assembly << " stack_space resb " << m_context.stackSize << "\n";
}
void GenerateTextSection(const std::vector<PathTree>& trees) { void GenerateTextSection(const std::vector<PathTree>& trees) {
// Program entry point // Program entry point
m_assembly << "_start:\n"; m_assembly << ".main:\n";
// Setup stack frame
m_assembly << " mov ebp, esp\n"
<< " sub esp, " << m_context.stackSize << "\n\n";
// Process execution paths first // Process execution paths first
for (const auto& tree : trees) { for (const auto& tree : trees) {
if (tree.isExecutionPath) { if (tree.isExecutionPath) {
@ -198,130 +182,6 @@ private:
GenerateExit(); GenerateExit();
} }
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
AddComment("Function Entry");
m_depth++;
for (auto& child : node->children) {
GenerateNodeCode(child);
}
m_depth--;
}
void GenerateBranchNode(std::shared_ptr<ASTNode> 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<ASTNode> node) {
auto* printNode = node->GetAs<PrintNode>();
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<ASTNode> node) {
auto* opNode = node->GetAs<OperatorNode>();
if (!opNode) return;
AddComment("Operator: " + std::to_string(static_cast<int>(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<ASTNode> node) {
auto* varNode = node->GetAs<VariableNode>();
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<ASTNode> node) { void CollectVariables(std::shared_ptr<ASTNode> node) {
if (!node) return; if (!node) return;
@ -345,19 +205,6 @@ private:
} }
} }
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";
}
}
}; };

View file

@ -0,0 +1,199 @@
#pragma once
#include "ast_builder.h"
#include "assembly_generator.h"
class AssemblyGeneratorChip32 : public AssemblyGenerator
{
public:
AssemblyGeneratorChip32(const GeneratorContext& context = GeneratorContext())
: AssemblyGenerator(context)
{
}
virtual ~AssemblyGeneratorChip32() = default;
void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override
{
if (!node) return;
if (m_context.debugOutput) {
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
}
if (isDataPath)
{
if (node->IsType<OperatorNode>()) {
GenerateOperatorNode(node);
}
else if (node->IsType<VariableNode>()) {
GenerateVariableNode(node);
}
}
else
{
if (node->IsType<FunctionEntryNode>()) {
GenerateFunctionEntry(node);
}
else if (node->IsType<BranchNode>()) {
GenerateBranchNode(node);
}
else if (node->IsType<PrintNode>()) {
GeneratePrintNode(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);
}
}
}
}
virtual void AddComment(const std::string& comment) {
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
}
virtual void GenerateExit() {
AddComment("Program exit");
m_assembly << " halt\n";
}
private:
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
AddComment("Function Entry");
m_depth++;
for (auto& child : node->children) {
GenerateNodeCode(child);
}
m_depth--;
}
void GenerateBranchNode(std::shared_ptr<ASTNode> 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
// We search a path tree that have a last node equivalent to our node
// (this is the input of the condition)
auto lastNode = std::find_if(m_roots.begin(), m_roots.end(),
[&node](const PathTree& tree) {
return tree.lastNode && tree.lastNode->node->GetId() == node->node->GetId();
});
AddComment("Last node: " + lastNode->lastNode->node->GetTypeName() + " (ID: " + lastNode->lastNode->node->GetId() + ")");
// 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<ASTNode> node) {
auto* printNode = node->GetAs<PrintNode>();
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<ASTNode> node) {
auto* opNode = node->GetAs<OperatorNode>();
if (!opNode) return;
AddComment("Operator: " + std::to_string(static_cast<int>(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<ASTNode> node) {
auto* varNode = node->GetAs<VariableNode>();
if (!varNode) return;
std::string varName = varNode->GetVariableName();
AddComment("Load variable: " + varName);
m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n"
<< " push eax\n";
}
};

View file

@ -32,6 +32,14 @@ public:
// Data outputs: output_port_index -> vector of (target node, target port) // Data outputs: output_port_index -> vector of (target node, target port)
std::unordered_map<unsigned int, std::vector<DataTarget>> dataOutputs; std::unordered_map<unsigned int, std::vector<DataTarget>> dataOutputs;
bool IsExecutionNode() const {
return node->GetBehavior() == BaseNode::Behavior::BEHAVIOR_EXECUTION;
}
bool IsDataNode() const {
return node->GetBehavior() == BaseNode::Behavior::BEHAVIOR_DATA;
}
// Helper methods // Helper methods
bool HasDataInput(unsigned int portIndex) const { bool HasDataInput(unsigned int portIndex) const {
return dataInputs.find(portIndex) != dataInputs.end(); return dataInputs.find(portIndex) != dataInputs.end();
@ -130,6 +138,7 @@ public:
struct PathTree { struct PathTree {
std::shared_ptr<ASTNode> root; std::shared_ptr<ASTNode> root;
std::shared_ptr<ASTNode> lastNode; // Dernier nœud du PathTree
std::vector<std::shared_ptr<Connection>> connections; std::vector<std::shared_ptr<Connection>> connections;
bool isExecutionPath; // true for main flow, false for input paths bool isExecutionPath; // true for main flow, false for input paths
}; };
@ -171,19 +180,28 @@ public:
} }
} }
// Nodes that have data outputs but no data inputs are data path roots // Nodes that have data outputs but no data inputs are data path roots
if (hasIncomingData.find(node->GetId()) == hasIncomingData.end()) { if ((hasIncomingData.find(node->GetId()) == hasIncomingData.end()) ||
AreAllInputsVariables(node, nodeMap))
{
// Check if the node has any outgoing data connections // Check if the node has any outgoing data connections
bool hasDataOutput = false; bool hasDataOutput = false;
for (const auto& conn : m_connections) { for (const auto& conn : m_connections)
{
if (conn->type == Connection::DATA_LINK && if (conn->type == Connection::DATA_LINK &&
conn->outNodeId == node->GetId()) { conn->outNodeId == node->GetId()) {
hasDataOutput = true; hasDataOutput = true;
break; break;
} }
} }
if (hasDataOutput) {
if (hasDataOutput && !(dynamic_cast<VariableNode*>(node.get())))
{
dataRoots.push_back(node); dataRoots.push_back(node);
} }
// if (hasDataOutput) {
// dataRoots.push_back(node);
// }
} }
} }
@ -214,6 +232,23 @@ private:
const std::vector<std::shared_ptr<BaseNode>>& m_nodes; const std::vector<std::shared_ptr<BaseNode>>& m_nodes;
const std::vector<std::shared_ptr<Connection>>& m_connections; const std::vector<std::shared_ptr<Connection>>& m_connections;
bool AreAllInputsVariables(const std::shared_ptr<BaseNode>& node, const std::unordered_map<std::string, std::shared_ptr<BaseNode>>& nodeMap) const
{
for (const auto& conn : m_connections)
{
if (conn->type == Connection::DATA_LINK && conn->inNodeId == node->GetId())
{
auto sourceNode = nodeMap.find(conn->outNodeId);
if (sourceNode != nodeMap.end() && !dynamic_cast<VariableNode*>(sourceNode->second.get()))
{
return false;
}
}
}
return true;
}
void BuildExecutionPath(PathTree& tree, void BuildExecutionPath(PathTree& tree,
const std::unordered_map<std::string, const std::unordered_map<std::string,
std::shared_ptr<BaseNode>>& nodeMap) { std::shared_ptr<BaseNode>>& nodeMap) {
@ -250,6 +285,8 @@ private:
queue.push(tree.root); queue.push(tree.root);
std::unordered_set<std::string> visited; std::unordered_set<std::string> visited;
std::shared_ptr<ASTNode> currentLastNode = nullptr;
while (!queue.empty()) { while (!queue.empty()) {
auto current = queue.front(); auto current = queue.front();
queue.pop(); queue.pop();
@ -257,6 +294,8 @@ private:
if (visited.find(current->node->GetId()) != visited.end()) { if (visited.find(current->node->GetId()) != visited.end()) {
continue; continue;
} }
currentLastNode = current; // Met à jour le dernier nœud visité
visited.insert(current->node->GetId()); visited.insert(current->node->GetId());
// Find data connections from this node // Find data connections from this node
@ -266,14 +305,24 @@ private:
auto targetNode = nodeMap.find(conn->inNodeId); auto targetNode = nodeMap.find(conn->inNodeId);
if (targetNode != nodeMap.end()) { if (targetNode != nodeMap.end()) {
auto childNode = std::make_shared<ASTNode>(targetNode->second); auto childNode = std::make_shared<ASTNode>(targetNode->second);
current->dataOutputs[conn->outPortIndex].push_back(
{childNode, conn->inPortIndex}); // Add childNode as a children only if it is not an execution node
// Otherwise, the assembly code will be generated twice
if (childNode->IsDataNode())
{
current->dataOutputs[conn->outPortIndex].push_back({childNode, conn->inPortIndex});
}
queue.push(childNode); queue.push(childNode);
tree.connections.push_back(conn); tree.connections.push_back(conn);
} }
} }
} }
} }
// On garde la trace du dernier nœud visité
// De cette façon on va pouvoir savoir à quel nœud on doit se connecter
// pour la génération de code
tree.lastNode = currentLastNode;
} }
void BuildDataInputs(std::shared_ptr<ASTNode> node, void BuildDataInputs(std::shared_ptr<ASTNode> node,

View file

@ -13,7 +13,7 @@ public:
std::cout << "AST Flow Visualization\n"; std::cout << "AST Flow Visualization\n";
std::cout << "User: " << user << "\n"; std::cout << "User: " << user << "\n";
std::cout << "Time: " << timestamp << "\n"; std::cout << "Time: " << timestamp << "\n";
std::cout << "==========================================================\n\n"; std::cout << "==========================================================\n\n" << std::endl;
} }
static void PrintNodeExecution(const std::string& nodeName, int depth = 0) { static void PrintNodeExecution(const std::string& nodeName, int depth = 0) {
@ -55,81 +55,117 @@ public:
} }
protected: protected:
void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override {
if (!node) return;
FlowVisualizer::PrintNodeExecution(node->node->GetTypeName(), m_depth); virtual void AddComment(const std::string& comment) {
}
if (node->IsType<FunctionEntryNode>()) {
m_depth++;
for (auto& child : node->children) {
GenerateNodeCode(child);
}
m_depth--;
}
else if (node->IsType<BranchNode>()) {
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) { virtual void GenerateExit() {
GenerateNodeCode(node->GetChild(0)); // True path
} else { }
GenerateNodeCode(node->GetChild(1)); // False path
} void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override
m_depth--; {
} if (!node) return;
else if (node->IsType<PrintNode>()) {
auto* printNode = node->GetAs<PrintNode>(); FlowVisualizer::PrintNodeExecution(node->node->GetTypeName(), m_depth);
FlowVisualizer::PrintNodeExecution("Print: " + printNode->GetText(), m_depth);
} if (node->IsType<FunctionEntryNode>()) {
else if (node->IsType<OperatorNode>()) { m_depth++;
m_depth++; for (auto& child : node->children) {
auto* opNode = node->GetAs<OperatorNode>(); GenerateNodeCode(child);
// 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--;
} }
m_depth--;
} }
else if (node->IsType<BranchNode>()) {
private: m_depth++;
int m_depth = 0; // Get condition value
auto conditionNode = node->GetDataInput(0);
int EvaluateOperand(std::shared_ptr<ASTNode> node) { int conditionValue = EvaluateCondition(conditionNode);
if (!node) return 0;
if (node->IsType<VariableNode>()) { FlowVisualizer::PrintBranchDecision(conditionValue > 7,
auto* varNode = node->GetAs<VariableNode>(); std::to_string(conditionValue), m_depth);
return varNode->GetValue<int>();
// Execute appropriate path
if (conditionValue > 7) {
GenerateNodeCode(node->GetChild(0)); // True path
} else {
GenerateNodeCode(node->GetChild(1)); // False path
} }
return 0; m_depth--;
}
else if (node->IsType<PrintNode>()) {
auto* printNode = node->GetAs<PrintNode>();
FlowVisualizer::PrintNodeExecution("Print: " + printNode->GetText(), m_depth);
}
else if (node->IsType<OperatorNode>()) {
m_depth++;
auto* opNode = node->GetAs<OperatorNode>();
// 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);
for (const auto& [port, outputs] : node->dataOutputs) {
for (const auto& target : outputs) {
GenerateNodeCode(target.node, true);
}
}
m_depth--;
}
else if (node->IsType<VariableNode>()) {
m_depth++;
auto* varNode = node->GetAs<VariableNode>();
// FlowVisualizer::PrintNodeExecution("Variable: " + varNode->GetVariableName(), m_depth);
// 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);
}
}
}
m_depth--;
} }
int EvaluateCondition(std::shared_ptr<ASTNode> node) {
if (!node) return 0; }
if (node->IsType<OperatorNode>()) { private:
auto input0 = node->GetDataInput(0); int m_depth = 0;
auto input1 = node->GetDataInput(1);
return EvaluateOperand(input0) + EvaluateOperand(input1); int EvaluateOperand(std::shared_ptr<ASTNode> node) {
} if (!node) return 0;
return 0;
if (node->IsType<VariableNode>()) {
auto* varNode = node->GetAs<VariableNode>();
return varNode->GetValue<int>();
} }
}; return 0;
}
int EvaluateCondition(std::shared_ptr<ASTNode> node) {
if (!node) return 0;
if (node->IsType<OperatorNode>()) {
auto input0 = node->GetDataInput(0);
auto input1 = node->GetDataInput(1);
return EvaluateOperand(input0) + EvaluateOperand(input1);
}
return 0;
}
};

View file

@ -2,16 +2,18 @@
#include "uuid.h" #include "uuid.h"
#include <iostream> #include <iostream>
BaseNode::BaseNode(const std::string &type, const std::string &typeName) BaseNode::BaseNode(const std::string &type, const std::string &typeName, Behavior behavior)
: m_behavior(behavior)
{ {
m_type = type; m_type = type;
m_typeName = typeName; m_typeName = typeName;
m_uuid = Uuid().String(); m_uuid = Uuid().String();
nlohmann::json obj{}; nlohmann::json obj{};
m_internal_data = obj; m_internal_data = obj;
} }
BaseNode::~BaseNode() BaseNode::~BaseNode()
{ {
std::cout << "Deleted base node" << std::endl; std::cout << "Deleted base node" << std::endl;

View file

@ -13,6 +13,12 @@
class BaseNode class BaseNode
{ {
public: public:
enum Behavior
{
BEHAVIOR_EXECUTION,
BEHAVIOR_DATA,
};
struct Port struct Port
{ {
enum Type { enum Type {
@ -57,7 +63,7 @@ public:
std::vector<ConstantValue> values; std::vector<ConstantValue> values;
}; };
BaseNode(const std::string &type, const std::string &typeName); BaseNode(const std::string &type, const std::string &typeName, Behavior behavior = BEHAVIOR_EXECUTION);
virtual ~BaseNode(); virtual ~BaseNode();
static std::string GetEntryLabel(const std::string &id); static std::string GetEntryLabel(const std::string &id);
@ -121,12 +127,20 @@ public:
} }
void SetBehavior(Behavior behavior) {
m_behavior = behavior;
}
Behavior GetBehavior() const {
return m_behavior;
}
private: private:
std::string m_title{"Default title"}; std::string m_title{"Default title"};
std::string m_type; std::string m_type;
std::string m_typeName; std::string m_typeName;
std::string m_uuid; std::string m_uuid;
NodePosition m_pos; NodePosition m_pos;
Behavior m_behavior{BEHAVIOR_EXECUTION};
std::vector<Port> m_inputPorts; std::vector<Port> m_inputPorts;
std::vector<Port> m_outputPorts; std::vector<Port> m_outputPorts;

View file

@ -38,7 +38,7 @@ public:
OperatorNode(const std::string& type = "operator-node", OperatorNode(const std::string& type = "operator-node",
const std::string& typeName = "Operator") const std::string& typeName = "Operator")
: BaseNode(type, typeName) : BaseNode(type, typeName, BaseNode::Behavior::BEHAVIOR_DATA)
, m_operationType(OperationType::ADD) , m_operationType(OperationType::ADD)
{ {
Initialize(); Initialize();

View file

@ -33,6 +33,7 @@ THE SOFTWARE.
#include "print_node.h" #include "print_node.h"
#include "variable_node.h" #include "variable_node.h"
#include "function_entry_node.h" #include "function_entry_node.h"
#include "operator_node.h"
#include "chip32_machine.h" #include "chip32_machine.h"
#include <stdarg.h> #include <stdarg.h>
@ -41,7 +42,7 @@ THE SOFTWARE.
#include "ast_builder.h" #include "ast_builder.h"
#include "assembly_generator.h" #include "assembly_generator.h"
#include "flow_generator.h" #include "flow_generator.h"
#include "assembly_generator_chip32.h"
/* /*
void ProcessASTTree(const ASTBuilder::PathTree& tree, int depth = 0) { void ProcessASTTree(const ASTBuilder::PathTree& tree, int depth = 0) {
std::queue<std::pair<std::shared_ptr<ASTNode>, int>> queue; std::queue<std::pair<std::shared_ptr<ASTNode>, int>> queue;
@ -97,7 +98,19 @@ TEST_CASE( "Check various indentations and typos" ) {
auto functionEntryNode = std::make_shared<FunctionEntryNode>("function-entry-node"); auto functionEntryNode = std::make_shared<FunctionEntryNode>("function-entry-node");
auto variableNode = std::make_shared<VariableNode>("variable-node"); auto variableNode1 = std::make_shared<VariableNode>("variable-node");
variableNode1->SetValue(5);
variableNode1->SetValueType(VariableNode::ValueType::INTEGER);
variableNode1->SetVariableName("X");
auto variableNode2 = std::make_shared<VariableNode>("variable-node");
variableNode2->SetValue(10);
variableNode2->SetValueType(VariableNode::ValueType::INTEGER);
variableNode2->SetVariableName("Y");
auto testNode = std::make_shared<OperatorNode>();
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
std::vector<std::shared_ptr<BaseNode>> nodes; std::vector<std::shared_ptr<BaseNode>> nodes;
@ -106,12 +119,16 @@ TEST_CASE( "Check various indentations and typos" ) {
nodes.push_back(printNodeTrue); nodes.push_back(printNodeTrue);
nodes.push_back(printNodeFalse); nodes.push_back(printNodeFalse);
nodes.push_back(branchNode); nodes.push_back(branchNode);
nodes.push_back(variableNode); nodes.push_back(variableNode1);
nodes.push_back(variableNode2);
nodes.push_back(testNode);
auto cn1 = std::make_shared<Connection>(); auto cn1 = std::make_shared<Connection>();
auto cn2 = std::make_shared<Connection>(); auto cn2 = std::make_shared<Connection>();
auto cn3 = std::make_shared<Connection>(); auto cn3 = std::make_shared<Connection>();
auto cn4 = std::make_shared<Connection>(); auto cn4 = std::make_shared<Connection>();
auto cn5 = std::make_shared<Connection>();
auto cn6 = std::make_shared<Connection>();
std::vector<std::shared_ptr<Connection>> connections; std::vector<std::shared_ptr<Connection>> connections;
@ -119,6 +136,8 @@ TEST_CASE( "Check various indentations and typos" ) {
connections.push_back(cn2); connections.push_back(cn2);
connections.push_back(cn3); connections.push_back(cn3);
connections.push_back(cn4); connections.push_back(cn4);
connections.push_back(cn5);
connections.push_back(cn6);
// Branch True -> print Ok // Branch True -> print Ok
@ -142,13 +161,27 @@ TEST_CASE( "Check various indentations and typos" ) {
cn3->outNodeId = functionEntryNode->GetId(); cn3->outNodeId = functionEntryNode->GetId();
cn3->outPortIndex = 0; cn3->outPortIndex = 0;
// Variable branch -> Branch node (condition input) // Compare test output -> Branch node (condition input)
cn4->inNodeId = branchNode->GetId(); cn4->inNodeId = branchNode->GetId();
cn4->inPortIndex = 1; cn4->inPortIndex = 1;
cn4->outNodeId = variableNode->GetId(); cn4->outNodeId = testNode->GetId();
cn4->outPortIndex = 0; cn4->outPortIndex = 0;
cn4->type = Connection::DATA_LINK; cn4->type = Connection::DATA_LINK;
// Variable 1 -> Compare test node input 1
cn5->inNodeId = testNode->GetId();
cn5->inPortIndex = 0;
cn5->outNodeId = variableNode1->GetId();
cn5->outPortIndex = 0;
cn5->type = Connection::DATA_LINK;
// Variable 1 -> Compare test node input 1
cn6->inNodeId = testNode->GetId();
cn6->inPortIndex = 1;
cn6->outNodeId = variableNode2->GetId();
cn6->outPortIndex = 0;
cn6->type = Connection::DATA_LINK;
// // Création des nœuds // // Création des nœuds
// std::vector<Node> nodes = { // std::vector<Node> nodes = {
@ -188,7 +221,7 @@ TEST_CASE( "Check various indentations and typos" ) {
); );
// Create generator // Create generator
AssemblyGenerator generator(context); AssemblyGeneratorChip32 generator(context);
ASTBuilder builder(nodes, connections); ASTBuilder builder(nodes, connections);
@ -206,20 +239,16 @@ TEST_CASE( "Check various indentations and typos" ) {
// Generate flow in the console // Generate flow in the console
VisualFlowGenerator flowGenerator(context); VisualFlowGenerator flowGenerator(context);
std::string flow = flowGenerator.GenerateAssembly(pathTrees);
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01"); FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTrees);
std::cout << "\nGenerated flow:\n" << flow << std::endl; std::cout << "\nGenerated flow:\n" << flow << std::endl;
// Generate assembly // Generate assembly
std::string assembly = generator.GenerateAssembly(pathTrees); std::string assembly = generator.GenerateAssembly(nodes, pathTrees);
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
// compiler.generateAssembly(); // compiler.generateAssembly();