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 "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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
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)
|
// 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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue