mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Good architecture between AST and assembly generation, still WIP
This commit is contained in:
parent
183e5d0727
commit
5c16e2bd94
8 changed files with 465 additions and 289 deletions
|
|
@ -16,6 +16,10 @@
|
|||
#include "branch_node.h"
|
||||
#include "operator_node.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class AssemblyGenerator {
|
||||
public:
|
||||
struct GeneratorContext {
|
||||
|
|
@ -26,7 +30,7 @@ public:
|
|||
int stackSize;
|
||||
|
||||
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 optimize = true,
|
||||
int stack = 1024)
|
||||
|
|
@ -54,7 +58,9 @@ public:
|
|||
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();
|
||||
|
||||
// Generate header comments
|
||||
|
|
@ -62,11 +68,7 @@ public:
|
|||
|
||||
// Generate data section
|
||||
StartSection(Section::DATA);
|
||||
GenerateDataSection(roots);
|
||||
|
||||
// Generate bss section for uninitialized data
|
||||
StartSection(Section::BSS);
|
||||
GenerateBssSection();
|
||||
GenerateDataSection(nodes, roots);
|
||||
|
||||
// Generate text section
|
||||
StartSection(Section::TEXT);
|
||||
|
|
@ -79,59 +81,46 @@ protected:
|
|||
enum class Section {
|
||||
NONE,
|
||||
DATA,
|
||||
BSS,
|
||||
TEXT
|
||||
};
|
||||
|
||||
virtual void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) {
|
||||
if (!node) return;
|
||||
virtual void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) = 0;
|
||||
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
||||
virtual void AddComment(const std::string& comment) = 0;
|
||||
|
||||
virtual void GenerateExit() = 0;
|
||||
|
||||
|
||||
std::string AddStringLiteral(const std::string& text)
|
||||
{
|
||||
std::string label = "str_" + std::to_string(m_stringLiterals.size());
|
||||
m_stringLiterals.push_back(text);
|
||||
return label;
|
||||
}
|
||||
|
||||
if (node->IsType<FunctionEntryNode>()) {
|
||||
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);
|
||||
std::string GenerateUniqueLabel(const std::string& prefix)
|
||||
{
|
||||
return prefix + "_" + std::to_string(m_labelCounter++);
|
||||
}
|
||||
|
||||
// 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:
|
||||
protected:
|
||||
GeneratorContext m_context;
|
||||
std::stringstream m_assembly;
|
||||
int m_labelCounter;
|
||||
std::unordered_map<std::string, std::string> m_variableAddresses;
|
||||
int m_currentStackOffset;
|
||||
std::vector<std::string> m_stringLiterals;
|
||||
int m_depth;
|
||||
int m_depth{0};
|
||||
Section m_currentSection;
|
||||
std::vector<PathTree> m_roots;
|
||||
|
||||
private:
|
||||
|
||||
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";
|
||||
AddComment("Assembly generated by Visual Node Editor");
|
||||
AddComment("Generation time: " + m_context.timestamp);
|
||||
AddComment("Generated by: " + m_context.username);
|
||||
AddComment("Optimization: " + m_context.optimizeCode ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
void StartSection(Section section) {
|
||||
|
|
@ -140,21 +129,24 @@ private:
|
|||
m_currentSection = section;
|
||||
switch (section) {
|
||||
case Section::DATA:
|
||||
m_assembly << "section .data\n";
|
||||
break;
|
||||
case Section::BSS:
|
||||
m_assembly << "section .bss\n";
|
||||
AddComment("======================= DATA =======================");
|
||||
break;
|
||||
case Section::TEXT:
|
||||
m_assembly << "section .text\n"
|
||||
<< "global _start\n\n";
|
||||
AddComment("======================= CODE =======================");
|
||||
break;
|
||||
default:
|
||||
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
|
||||
for (const auto& literal : m_stringLiterals) {
|
||||
std::string label = "str_" + std::to_string(m_labelCounter++);
|
||||
|
|
@ -168,17 +160,9 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void GenerateBssSection() {
|
||||
m_assembly << " stack_space resb " << m_context.stackSize << "\n";
|
||||
}
|
||||
|
||||
void GenerateTextSection(const std::vector<PathTree>& trees) {
|
||||
// Program entry point
|
||||
m_assembly << "_start:\n";
|
||||
|
||||
// Setup stack frame
|
||||
m_assembly << " mov ebp, esp\n"
|
||||
<< " sub esp, " << m_context.stackSize << "\n\n";
|
||||
m_assembly << ".main:\n";
|
||||
|
||||
// Process execution paths first
|
||||
for (const auto& tree : trees) {
|
||||
|
|
@ -198,130 +182,6 @@ private:
|
|||
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) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
};
|
||||
199
core/story-manager/src/compiler/assembly_generator_chip32.h
Normal file
199
core/story-manager/src/compiler/assembly_generator_chip32.h
Normal 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";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -32,6 +32,14 @@ public:
|
|||
// Data outputs: output_port_index -> vector of (target node, target port)
|
||||
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
|
||||
bool HasDataInput(unsigned int portIndex) const {
|
||||
return dataInputs.find(portIndex) != dataInputs.end();
|
||||
|
|
@ -130,6 +138,7 @@ public:
|
|||
|
||||
struct PathTree {
|
||||
std::shared_ptr<ASTNode> root;
|
||||
std::shared_ptr<ASTNode> lastNode; // Dernier nœud du PathTree
|
||||
std::vector<std::shared_ptr<Connection>> connections;
|
||||
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
|
||||
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
|
||||
bool hasDataOutput = false;
|
||||
for (const auto& conn : m_connections) {
|
||||
for (const auto& conn : m_connections)
|
||||
{
|
||||
if (conn->type == Connection::DATA_LINK &&
|
||||
conn->outNodeId == node->GetId()) {
|
||||
hasDataOutput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasDataOutput) {
|
||||
|
||||
if (hasDataOutput && !(dynamic_cast<VariableNode*>(node.get())))
|
||||
{
|
||||
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<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,
|
||||
const std::unordered_map<std::string,
|
||||
std::shared_ptr<BaseNode>>& nodeMap) {
|
||||
|
|
@ -250,6 +285,8 @@ private:
|
|||
queue.push(tree.root);
|
||||
std::unordered_set<std::string> visited;
|
||||
|
||||
std::shared_ptr<ASTNode> currentLastNode = nullptr;
|
||||
|
||||
while (!queue.empty()) {
|
||||
auto current = queue.front();
|
||||
queue.pop();
|
||||
|
|
@ -257,6 +294,8 @@ private:
|
|||
if (visited.find(current->node->GetId()) != visited.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
currentLastNode = current; // Met à jour le dernier nœud visité
|
||||
visited.insert(current->node->GetId());
|
||||
|
||||
// Find data connections from this node
|
||||
|
|
@ -266,14 +305,24 @@ private:
|
|||
auto targetNode = nodeMap.find(conn->inNodeId);
|
||||
if (targetNode != nodeMap.end()) {
|
||||
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);
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public:
|
|||
std::cout << "AST Flow Visualization\n";
|
||||
std::cout << "User: " << user << "\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) {
|
||||
|
|
@ -56,7 +56,19 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override {
|
||||
|
||||
virtual void AddComment(const std::string& comment) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void GenerateExit() {
|
||||
|
||||
}
|
||||
|
||||
void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override
|
||||
{
|
||||
if (!node) return;
|
||||
|
||||
FlowVisualizer::PrintNodeExecution(node->node->GetTypeName(), m_depth);
|
||||
|
|
@ -105,8 +117,32 @@ public:
|
|||
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--;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
#include "uuid.h"
|
||||
#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_typeName = typeName;
|
||||
|
|
@ -12,6 +13,7 @@ BaseNode::BaseNode(const std::string &type, const std::string &typeName)
|
|||
m_internal_data = obj;
|
||||
}
|
||||
|
||||
|
||||
BaseNode::~BaseNode()
|
||||
{
|
||||
std::cout << "Deleted base node" << std::endl;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@
|
|||
class BaseNode
|
||||
{
|
||||
public:
|
||||
enum Behavior
|
||||
{
|
||||
BEHAVIOR_EXECUTION,
|
||||
BEHAVIOR_DATA,
|
||||
};
|
||||
|
||||
struct Port
|
||||
{
|
||||
enum Type {
|
||||
|
|
@ -57,7 +63,7 @@ public:
|
|||
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();
|
||||
|
||||
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:
|
||||
std::string m_title{"Default title"};
|
||||
std::string m_type;
|
||||
std::string m_typeName;
|
||||
std::string m_uuid;
|
||||
NodePosition m_pos;
|
||||
Behavior m_behavior{BEHAVIOR_EXECUTION};
|
||||
|
||||
std::vector<Port> m_inputPorts;
|
||||
std::vector<Port> m_outputPorts;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
OperatorNode(const std::string& type = "operator-node",
|
||||
const std::string& typeName = "Operator")
|
||||
: BaseNode(type, typeName)
|
||||
: BaseNode(type, typeName, BaseNode::Behavior::BEHAVIOR_DATA)
|
||||
, m_operationType(OperationType::ADD)
|
||||
{
|
||||
Initialize();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ THE SOFTWARE.
|
|||
#include "print_node.h"
|
||||
#include "variable_node.h"
|
||||
#include "function_entry_node.h"
|
||||
#include "operator_node.h"
|
||||
#include "chip32_machine.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
|
@ -41,7 +42,7 @@ THE SOFTWARE.
|
|||
#include "ast_builder.h"
|
||||
#include "assembly_generator.h"
|
||||
#include "flow_generator.h"
|
||||
|
||||
#include "assembly_generator_chip32.h"
|
||||
/*
|
||||
void ProcessASTTree(const ASTBuilder::PathTree& tree, int depth = 0) {
|
||||
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 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;
|
||||
|
|
@ -106,12 +119,16 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
nodes.push_back(printNodeTrue);
|
||||
nodes.push_back(printNodeFalse);
|
||||
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 cn2 = std::make_shared<Connection>();
|
||||
auto cn3 = 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;
|
||||
|
||||
|
|
@ -119,6 +136,8 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
connections.push_back(cn2);
|
||||
connections.push_back(cn3);
|
||||
connections.push_back(cn4);
|
||||
connections.push_back(cn5);
|
||||
connections.push_back(cn6);
|
||||
|
||||
|
||||
// Branch True -> print Ok
|
||||
|
|
@ -142,13 +161,27 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
cn3->outNodeId = functionEntryNode->GetId();
|
||||
cn3->outPortIndex = 0;
|
||||
|
||||
// Variable branch -> Branch node (condition input)
|
||||
// Compare test output -> Branch node (condition input)
|
||||
cn4->inNodeId = branchNode->GetId();
|
||||
cn4->inPortIndex = 1;
|
||||
cn4->outNodeId = variableNode->GetId();
|
||||
cn4->outNodeId = testNode->GetId();
|
||||
cn4->outPortIndex = 0;
|
||||
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
|
||||
// std::vector<Node> nodes = {
|
||||
|
|
@ -188,7 +221,7 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
);
|
||||
|
||||
// Create generator
|
||||
AssemblyGenerator generator(context);
|
||||
AssemblyGeneratorChip32 generator(context);
|
||||
|
||||
|
||||
ASTBuilder builder(nodes, connections);
|
||||
|
|
@ -206,20 +239,16 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
|
||||
// Generate flow in the console
|
||||
VisualFlowGenerator flowGenerator(context);
|
||||
std::string flow = flowGenerator.GenerateAssembly(pathTrees);
|
||||
|
||||
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
|
||||
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTrees);
|
||||
|
||||
|
||||
std::cout << "\nGenerated flow:\n" << flow << std::endl;
|
||||
|
||||
// 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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue