mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Better custom AST builder using kahn algorithm
This commit is contained in:
parent
5c16e2bd94
commit
3c1224e937
27 changed files with 568 additions and 599 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -109,7 +109,8 @@
|
||||||
"text_encoding": "cpp",
|
"text_encoding": "cpp",
|
||||||
"serializers.h": "c",
|
"serializers.h": "c",
|
||||||
"ni_parser.h": "c",
|
"ni_parser.h": "c",
|
||||||
"*.m": "cpp"
|
"*.m": "cpp",
|
||||||
|
"*.inc": "cpp"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,6 @@ Purpose: grammar, ram usage and macros, rom code generation
|
||||||
void hexdump(void *ptr, int buflen);
|
void hexdump(void *ptr, int buflen);
|
||||||
|
|
||||||
static const std::string test1 = R"(; jump over the data, to our entry label
|
static const std::string test1 = R"(; jump over the data, to our entry label
|
||||||
jump .entry
|
|
||||||
|
|
||||||
$imageBird DC8 "example.bmp", 8 ; data
|
$imageBird DC8 "example.bmp", 8 ; data
|
||||||
$someConstant DC32 12456789
|
$someConstant DC32 12456789
|
||||||
|
|
@ -46,7 +45,7 @@ $RamData1 DV32 1 ; one 32-bit integer
|
||||||
$MyArray DV8 10 ; array of 10 bytes
|
$MyArray DV8 10 ; array of 10 bytes
|
||||||
|
|
||||||
; label definition
|
; label definition
|
||||||
.entry: ;; comment here should work
|
.main: ;; comment here should work
|
||||||
; We create a stupid loop just for RAM variable testing
|
; We create a stupid loop just for RAM variable testing
|
||||||
|
|
||||||
lcons r0, 4 ; prepare loop: 4 iterations
|
lcons r0, 4 ; prepare loop: 4 iterations
|
||||||
|
|
@ -183,14 +182,12 @@ static const std::string testPrintf = R"(
|
||||||
; ========================================================
|
; ========================================================
|
||||||
; We test the printf system call
|
; We test the printf system call
|
||||||
; ========================================================
|
; ========================================================
|
||||||
jump .entry
|
|
||||||
|
|
||||||
$printHello DC8 "La réponse est %d"
|
$printHello DC8 "La réponse est %d"
|
||||||
$answer DC32 42
|
$answer DC32 42
|
||||||
|
|
||||||
$counter DV32 10
|
$counter DV32 10
|
||||||
|
|
||||||
.entry:
|
.main:
|
||||||
|
|
||||||
; prepapre loop
|
; prepapre loop
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,128 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
struct Variable {
|
#include "uuid.h"
|
||||||
static const uint32_t NameMaxSize = 50;
|
|
||||||
std::string name; // Nom de la variable
|
class Variable
|
||||||
std::string type; // Type de la variable (par exemple int32_t, int64_t)
|
{
|
||||||
int64_t value; // Valeur stockée en tant qu'entier en virgule fixe
|
|
||||||
std::string valueText;
|
public:
|
||||||
int scalePower; // Nombre de bits pour la partie fractionnaire
|
enum class ValueType {
|
||||||
|
INTEGER,
|
||||||
|
FLOAT,
|
||||||
|
BOOL,
|
||||||
|
STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
|
||||||
|
void SetUuid(const std::string& uuid) {
|
||||||
|
m_uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVariableName(const std::string& name) {
|
||||||
|
m_variableName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetConstant(bool isConstant) {
|
||||||
|
m_isConstant = isConstant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValueType(ValueType type) {
|
||||||
|
m_valueType = type;
|
||||||
|
// Reset value to default for new type
|
||||||
|
switch (type) {
|
||||||
|
case ValueType::INTEGER:
|
||||||
|
m_value = 0;
|
||||||
|
break;
|
||||||
|
case ValueType::FLOAT:
|
||||||
|
m_value = 0.0f;
|
||||||
|
break;
|
||||||
|
case ValueType::BOOL:
|
||||||
|
m_value = false;
|
||||||
|
break;
|
||||||
|
case ValueType::STRING:
|
||||||
|
m_value = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void SetValue(const T& value) {
|
||||||
|
try {
|
||||||
|
m_value = value;
|
||||||
|
} catch (const std::bad_variant_access&) {
|
||||||
|
throw std::runtime_error("[variable.h] SetValue(): Invalid value type for variable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTextValue(const std::string& value) {
|
||||||
|
SetValue<std::string>(value);
|
||||||
|
m_valueType = ValueType::STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetIntegerValue(int value) {
|
||||||
|
SetValue<int>(value);
|
||||||
|
m_valueType = ValueType::INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFloatValue(float value) {
|
||||||
|
SetValue<float>(value);
|
||||||
|
m_valueType = ValueType::FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBoolValue(bool value) {
|
||||||
|
SetValue<bool>(value);
|
||||||
|
m_valueType = ValueType::BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
std::string GetVariableName() const {
|
||||||
|
return m_variableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsConstant() const {
|
||||||
|
return m_isConstant;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType GetValueType() const {
|
||||||
|
return m_valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T GetValue() const {
|
||||||
|
try {
|
||||||
|
return std::get<T>(m_value);
|
||||||
|
} catch (const std::bad_variant_access&) {
|
||||||
|
throw std::runtime_error("[variable.h] GetValue(): Invalid value type requested");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using VariableValue = std::variant<int, float, bool, std::string>;
|
||||||
|
|
||||||
|
std::string GetUuid() const {
|
||||||
|
return m_uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable() {
|
||||||
|
m_uuid = Uuid().String();
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable (const std::string &name)
|
||||||
|
: Variable()
|
||||||
|
{
|
||||||
|
m_variableName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_variableName;
|
||||||
|
ValueType m_valueType;
|
||||||
|
VariableValue m_value;
|
||||||
|
bool m_isConstant;
|
||||||
|
std::string m_uuid;
|
||||||
|
int m_scalePower; // Nombre de bits pour la partie fractionnaire
|
||||||
|
|
||||||
Variable(const std::string &n, const std::string &t, int64_t v, int s) {
|
|
||||||
name = n;
|
|
||||||
type = t;
|
|
||||||
value = v;
|
|
||||||
scalePower = s;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,10 @@
|
||||||
#include "variable_node.h"
|
#include "variable_node.h"
|
||||||
#include "branch_node.h"
|
#include "branch_node.h"
|
||||||
#include "operator_node.h"
|
#include "operator_node.h"
|
||||||
|
#include "base_node.h"
|
||||||
|
|
||||||
|
|
||||||
|
class AssemblyGenerator : public IVariableVisitor {
|
||||||
|
|
||||||
|
|
||||||
class AssemblyGenerator {
|
|
||||||
public:
|
public:
|
||||||
struct GeneratorContext {
|
struct GeneratorContext {
|
||||||
std::string timestamp;
|
std::string timestamp;
|
||||||
|
|
@ -58,9 +56,10 @@ public:
|
||||||
m_currentSection = Section::NONE;
|
m_currentSection = Section::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& roots)
|
std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& roots, const std::vector<std::shared_ptr<Variable>> &variables)
|
||||||
{
|
{
|
||||||
m_roots = roots;
|
m_roots = roots;
|
||||||
|
/*
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
// Generate header comments
|
// Generate header comments
|
||||||
|
|
@ -68,11 +67,31 @@ public:
|
||||||
|
|
||||||
// Generate data section
|
// Generate data section
|
||||||
StartSection(Section::DATA);
|
StartSection(Section::DATA);
|
||||||
GenerateDataSection(nodes, roots);
|
GenerateDataSection(nodes, roots, variables);
|
||||||
|
|
||||||
// Generate text section
|
// Generate text section
|
||||||
StartSection(Section::TEXT);
|
StartSection(Section::TEXT);
|
||||||
GenerateTextSection(roots);
|
GenerateTextSection(roots);
|
||||||
|
*/
|
||||||
|
return m_assembly.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<ASTNode>>& order, const std::vector<std::shared_ptr<Variable>> &variables)
|
||||||
|
{
|
||||||
|
// m_roots = roots;
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
// Generate header comments
|
||||||
|
GenerateHeader();
|
||||||
|
|
||||||
|
// Generate data section
|
||||||
|
StartSection(Section::DATA);
|
||||||
|
GenerateDataSection(nodes, variables);
|
||||||
|
|
||||||
|
// Generate text section
|
||||||
|
StartSection(Section::TEXT);
|
||||||
|
GenerateTextSection(order);
|
||||||
|
|
||||||
return m_assembly.str();
|
return m_assembly.str();
|
||||||
}
|
}
|
||||||
|
|
@ -139,14 +158,19 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateDataSection(const std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& trees) {
|
void GenerateDataSection(const std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<Variable>> &variables)
|
||||||
|
{
|
||||||
|
|
||||||
// Generate all constants
|
// Generate all constants
|
||||||
for (const auto& n : nodes) {
|
for (const auto& n : nodes) {
|
||||||
m_assembly << n->GenerateConstants();
|
n->Accept(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_assembly << "\n\n";
|
||||||
|
|
||||||
|
// Generate all
|
||||||
|
|
||||||
|
/*
|
||||||
// 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++);
|
||||||
|
|
@ -158,12 +182,20 @@ private:
|
||||||
for (const auto& t : trees) {
|
for (const auto& t : trees) {
|
||||||
CollectVariables(t.root);
|
CollectVariables(t.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateTextSection(const std::vector<PathTree>& trees) {
|
void GenerateTextSection(const std::vector<std::shared_ptr<ASTNode>>& orderedNodes) {
|
||||||
// Program entry point
|
// Program entry point
|
||||||
m_assembly << ".main:\n";
|
m_assembly << ".main:\n";
|
||||||
|
|
||||||
|
for (const auto& node : orderedNodes) {
|
||||||
|
GenerateNodeCode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
// Process execution paths first
|
// Process execution paths first
|
||||||
for (const auto& tree : trees) {
|
for (const auto& tree : trees) {
|
||||||
if (tree.isExecutionPath) {
|
if (tree.isExecutionPath) {
|
||||||
|
|
@ -177,6 +209,7 @@ private:
|
||||||
GenerateNodeCode(tree.root, true);
|
GenerateNodeCode(tree.root, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Program exit
|
// Program exit
|
||||||
GenerateExit();
|
GenerateExit();
|
||||||
|
|
@ -187,11 +220,13 @@ private:
|
||||||
|
|
||||||
if (node->IsType<VariableNode>()) {
|
if (node->IsType<VariableNode>()) {
|
||||||
auto* varNode = node->GetAs<VariableNode>();
|
auto* varNode = node->GetAs<VariableNode>();
|
||||||
std::string varName = varNode->GetVariableName();
|
/*
|
||||||
|
std::string varName = varNode->GetN();
|
||||||
if (m_variableAddresses.find(varName) == m_variableAddresses.end()) {
|
if (m_variableAddresses.find(varName) == m_variableAddresses.end()) {
|
||||||
m_variableAddresses[varName] = varName;
|
m_variableAddresses[varName] = varName;
|
||||||
m_assembly << varName << ":\n" << varNode->GenerateAssembly();
|
m_assembly << varName << ":\n" << varNode->GenerateAssembly();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse children
|
// Traverse children
|
||||||
|
|
|
||||||
|
|
@ -21,20 +21,23 @@ public:
|
||||||
if (m_context.debugOutput) {
|
if (m_context.debugOutput) {
|
||||||
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if (isDataPath)
|
if (isDataPath)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (node->IsType<OperatorNode>()) {
|
|
||||||
GenerateOperatorNode(node);
|
// else if (node->IsType<VariableNode>()) {
|
||||||
}
|
// GenerateVariableNode(node);
|
||||||
else if (node->IsType<VariableNode>()) {
|
// }
|
||||||
GenerateVariableNode(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node->IsType<FunctionEntryNode>()) {
|
|
||||||
|
*/
|
||||||
|
if (node->IsType<OperatorNode>()) {
|
||||||
|
GenerateOperatorNode(node);
|
||||||
|
}
|
||||||
|
else if (node->IsType<FunctionEntryNode>()) {
|
||||||
GenerateFunctionEntry(node);
|
GenerateFunctionEntry(node);
|
||||||
}
|
}
|
||||||
else if (node->IsType<BranchNode>()) {
|
else if (node->IsType<BranchNode>()) {
|
||||||
|
|
@ -43,7 +46,7 @@ public:
|
||||||
else if (node->IsType<PrintNode>()) {
|
else if (node->IsType<PrintNode>()) {
|
||||||
GeneratePrintNode(node);
|
GeneratePrintNode(node);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
|
|
||||||
// If we're processing a data path, traverse data outputs
|
// If we're processing a data path, traverse data outputs
|
||||||
if (isDataPath) {
|
if (isDataPath) {
|
||||||
|
|
@ -73,9 +76,9 @@ private:
|
||||||
AddComment("Function Entry");
|
AddComment("Function Entry");
|
||||||
m_depth++;
|
m_depth++;
|
||||||
|
|
||||||
for (auto& child : node->children) {
|
// for (auto& child : node->children) {
|
||||||
GenerateNodeCode(child);
|
// GenerateNodeCode(child);
|
||||||
}
|
// }
|
||||||
|
|
||||||
m_depth--;
|
m_depth--;
|
||||||
}
|
}
|
||||||
|
|
@ -92,14 +95,14 @@ private:
|
||||||
// Generate condition code
|
// Generate condition code
|
||||||
// We search a path tree that have a last node equivalent to our node
|
// We search a path tree that have a last node equivalent to our node
|
||||||
// (this is the input of the condition)
|
// (this is the input of the condition)
|
||||||
|
/*
|
||||||
auto lastNode = std::find_if(m_roots.begin(), m_roots.end(),
|
auto lastNode = std::find_if(m_roots.begin(), m_roots.end(),
|
||||||
[&node](const PathTree& tree) {
|
[&node](const PathTree& tree) {
|
||||||
return tree.lastNode && tree.lastNode->node->GetId() == node->node->GetId();
|
return tree.lastNode && tree.lastNode->node->GetId() == node->node->GetId();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddComment("Last node: " + lastNode->lastNode->node->GetTypeName() + " (ID: " + lastNode->lastNode->node->GetId() + ")");
|
AddComment("Last node: " + lastNode->lastNode->node->GetTypeName() + " (ID: " + lastNode->lastNode->node->GetId() + ")");
|
||||||
|
*/
|
||||||
|
|
||||||
// Compare result and jump
|
// Compare result and jump
|
||||||
m_assembly << " pop eax\n"
|
m_assembly << " pop eax\n"
|
||||||
|
|
@ -127,15 +130,19 @@ private:
|
||||||
auto* printNode = node->GetAs<PrintNode>();
|
auto* printNode = node->GetAs<PrintNode>();
|
||||||
if (!printNode) return;
|
if (!printNode) return;
|
||||||
|
|
||||||
std::string text = printNode->GetText();
|
std::string label = printNode->GetLabel();
|
||||||
std::string label = AddStringLiteral(text);
|
|
||||||
|
|
||||||
|
m_assembly << " push r0\n"
|
||||||
|
<< " push r1\n"
|
||||||
|
<< " lcons r0, $" << label << "\n"
|
||||||
|
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
|
||||||
|
<< " syscall 4\n"
|
||||||
|
<< " pop r1\n"
|
||||||
|
<< " pop r0\n";
|
||||||
|
|
||||||
|
// << ""mov r2, %2 // arguments are in r2, r3, r4 etc.
|
||||||
|
|
||||||
// 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) {
|
void GenerateOperatorNode(std::shared_ptr<ASTNode> node) {
|
||||||
|
|
@ -145,11 +152,12 @@ private:
|
||||||
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
|
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
|
||||||
m_depth++;
|
m_depth++;
|
||||||
|
|
||||||
// Generate code for operands
|
// Generate code for variables
|
||||||
for (const auto& [port, inputNode] : node->dataInputs) {
|
for (const auto& [port, inputNode] : node->dataInputs) {
|
||||||
GenerateNodeCode(inputNode);
|
// m_assembly << " load r0, " << inputNode.node->GetId() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generate operator code
|
// Generate operator code
|
||||||
switch (opNode->GetOperationType()) {
|
switch (opNode->GetOperationType()) {
|
||||||
case OperatorNode::OperationType::ADD:
|
case OperatorNode::OperationType::ADD:
|
||||||
|
|
@ -178,11 +186,91 @@ private:
|
||||||
<< " push eax\n";
|
<< " push eax\n";
|
||||||
break;
|
break;
|
||||||
// Add other operators...
|
// Add other operators...
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
std::string GenerateAssembly() const override {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
switch (m_operationType) {
|
||||||
|
case OperationType::ADD:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " add eax, ebx\n"
|
||||||
|
<< " push eax\n";
|
||||||
|
break;
|
||||||
|
case OperationType::SUBTRACT:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " sub eax, ebx\n"
|
||||||
|
<< " push eax\n";
|
||||||
|
break;
|
||||||
|
case OperationType::MULTIPLY:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " imul eax, ebx\n"
|
||||||
|
<< " push eax\n";
|
||||||
|
break;
|
||||||
|
case OperationType::DIVIDE:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " cdq\n" // Sign extend eax into edx
|
||||||
|
<< " idiv ebx\n"
|
||||||
|
<< " push eax\n"; // Push quotient
|
||||||
|
break;
|
||||||
|
case OperationType::AND:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " and eax, ebx\n"
|
||||||
|
<< " push eax\n";
|
||||||
|
break;
|
||||||
|
case OperationType::OR:
|
||||||
|
ss << " pop ebx\n"
|
||||||
|
<< " pop eax\n"
|
||||||
|
<< " or eax, ebx\n"
|
||||||
|
<< " push eax\n";
|
||||||
|
break;
|
||||||
|
// Add other operators...
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_depth--;
|
m_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Visit(const std::shared_ptr<Variable> v) override
|
||||||
|
{
|
||||||
|
if (v->IsConstant())
|
||||||
|
{
|
||||||
|
if (v->GetValueType() == Variable::ValueType::STRING)
|
||||||
|
{
|
||||||
|
m_assembly << "$" << v->GetVariableName() << " DC8, \"" << v->GetValue<std::string>() << "\"\n";
|
||||||
|
}
|
||||||
|
else if (v->GetValueType() == Variable::ValueType::INTEGER)
|
||||||
|
{
|
||||||
|
m_assembly << "$" << v->GetVariableName() << " DC32, " << v->GetValue<int>() << "\n";
|
||||||
|
}
|
||||||
|
else if (v->GetValueType() == Variable::ValueType::FLOAT)
|
||||||
|
{
|
||||||
|
m_assembly << "$" << v->GetVariableName() << " DC32, " << v->GetValue<float>() << "\n";
|
||||||
|
}
|
||||||
|
else if (v->GetValueType() == Variable::ValueType::BOOL)
|
||||||
|
{
|
||||||
|
m_assembly << "$" << v->GetVariableName() << " DCB, " << (v->GetValue<bool>() ? "1" : "0") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
void GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
void GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
||||||
auto* varNode = node->GetAs<VariableNode>();
|
auto* varNode = node->GetAs<VariableNode>();
|
||||||
if (!varNode) return;
|
if (!varNode) return;
|
||||||
|
|
@ -193,7 +281,7 @@ private:
|
||||||
m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n"
|
m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n"
|
||||||
<< " push eax\n";
|
<< " push eax\n";
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,14 @@ public:
|
||||||
return dynamic_cast<T*>(node.get());
|
return dynamic_cast<T*>(node.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetId() const {
|
||||||
|
return node->GetId();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetWeight() const {
|
||||||
|
return node->GetWeight();
|
||||||
|
}
|
||||||
|
|
||||||
// Debug information
|
// Debug information
|
||||||
std::string GetDebugString() const {
|
std::string GetDebugString() const {
|
||||||
std::string result = "Node: " + node->GetTypeName() + " (ID: " + node->GetId() + ")\n";
|
std::string result = "Node: " + node->GetTypeName() + " (ID: " + node->GetId() + ")\n";
|
||||||
|
|
@ -150,82 +158,44 @@ public:
|
||||||
const std::vector<std::shared_ptr<Connection>>& connections)
|
const std::vector<std::shared_ptr<Connection>>& connections)
|
||||||
: m_nodes(nodes), m_connections(connections) {}
|
: m_nodes(nodes), m_connections(connections) {}
|
||||||
|
|
||||||
std::vector<PathTree> BuildAST() {
|
std::vector<std::shared_ptr<ASTNode>> BuildAST()
|
||||||
// Create node map for quick lookups
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<BaseNode>> nodeMap;
|
|
||||||
for (const auto& node : m_nodes) {
|
|
||||||
nodeMap[node->GetId()] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all root nodes (nodes without incoming execution connections)
|
|
||||||
std::unordered_set<std::string> hasIncomingExec;
|
|
||||||
std::unordered_set<std::string> hasIncomingData;
|
|
||||||
|
|
||||||
for (const auto& conn : m_connections) {
|
|
||||||
if (conn->type == Connection::EXECUTION_LINKJ) {
|
|
||||||
hasIncomingExec.insert(conn->inNodeId);
|
|
||||||
} else {
|
|
||||||
hasIncomingData.insert(conn->inNodeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect root nodes
|
|
||||||
std::vector<std::shared_ptr<BaseNode>> execRoots;
|
|
||||||
std::vector<std::shared_ptr<BaseNode>> dataRoots;
|
|
||||||
|
|
||||||
for (const auto& node : m_nodes) {
|
|
||||||
if (hasIncomingExec.find(node->GetId()) == hasIncomingExec.end()) {
|
|
||||||
if (dynamic_cast<FunctionEntryNode*>(node.get())) {
|
|
||||||
execRoots.push_back(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Nodes that have data outputs but no data inputs are data path roots
|
|
||||||
if ((hasIncomingData.find(node->GetId()) == hasIncomingData.end()) ||
|
|
||||||
AreAllInputsVariables(node, nodeMap))
|
|
||||||
{
|
{
|
||||||
// Check if the node has any outgoing data connections
|
// Create node map for quick lookups
|
||||||
bool hasDataOutput = false;
|
std::unordered_map<std::string, std::shared_ptr<ASTNode>> nodeMap;
|
||||||
|
for (const auto& node : m_nodes) {
|
||||||
|
nodeMap[node->GetId()] = std::make_shared<ASTNode>(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build adjacency list for the nodes from the connections
|
||||||
|
for (const auto& conn : m_connections) {
|
||||||
|
|
||||||
|
// Don't add the variables nodes, as they are input data nodes.
|
||||||
|
auto rawNode = nodeMap[conn->outNodeId].get()->node;
|
||||||
|
|
||||||
|
if (dynamic_cast<VariableNode*>(rawNode.get())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_adjList[conn->outNodeId].push_back(conn->inNodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<ASTNode>> topologicalOrder = ApplyKahnAlgorithm(nodeMap);
|
||||||
|
|
||||||
|
// Maintenant, on va ajouter les connexions de données
|
||||||
for (const auto& conn : m_connections)
|
for (const auto& conn : m_connections)
|
||||||
{
|
{
|
||||||
if (conn->type == Connection::DATA_LINK &&
|
auto outNode = nodeMap[conn->outNodeId];
|
||||||
conn->outNodeId == node->GetId()) {
|
auto inNode = nodeMap[conn->inNodeId];
|
||||||
hasDataOutput = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasDataOutput && !(dynamic_cast<VariableNode*>(node.get())))
|
// Keep variables nodes as data inputs
|
||||||
|
if (dynamic_cast<VariableNode*>(outNode->node.get()))
|
||||||
{
|
{
|
||||||
dataRoots.push_back(node);
|
inNode->AddDataInput(conn->inPortIndex, outNode);
|
||||||
}
|
|
||||||
|
|
||||||
// if (hasDataOutput) {
|
|
||||||
// dataRoots.push_back(node);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PathTree> pathTrees;
|
return topologicalOrder;
|
||||||
|
|
||||||
// Build execution path trees
|
|
||||||
for (const auto& root : execRoots) {
|
|
||||||
PathTree tree;
|
|
||||||
tree.root = std::make_shared<ASTNode>(root);
|
|
||||||
tree.isExecutionPath = true;
|
|
||||||
BuildExecutionPath(tree, nodeMap);
|
|
||||||
pathTrees.push_back(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build data path trees
|
|
||||||
for (const auto& root : dataRoots) {
|
|
||||||
PathTree tree;
|
|
||||||
tree.root = std::make_shared<ASTNode>(root);
|
|
||||||
tree.isExecutionPath = false;
|
|
||||||
BuildDataPath(tree, nodeMap);
|
|
||||||
pathTrees.push_back(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pathTrees;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -233,6 +203,89 @@ private:
|
||||||
const std::vector<std::shared_ptr<Connection>>& m_connections;
|
const std::vector<std::shared_ptr<Connection>>& m_connections;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<ASTNode>> ApplyKahnAlgorithm(const std::unordered_map<std::string, std::shared_ptr<ASTNode>> &nodeMap)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Pour le container de la queue, on utilise un comparateur pour trier les noeuds par poids
|
||||||
|
// Cela permet de prioriser les noeuds avec un poids plus faible
|
||||||
|
auto compare = [](const std::shared_ptr<ASTNode>& a, const std::shared_ptr<ASTNode>& b) {
|
||||||
|
return a->GetWeight() < b->GetWeight();
|
||||||
|
};
|
||||||
|
std::priority_queue<std::shared_ptr<ASTNode>, std::vector<std::shared_ptr<ASTNode>>, decltype(compare)> queue(compare);
|
||||||
|
|
||||||
|
// std::queue<std::string> q;
|
||||||
|
std::unordered_map<std::string, int> inDegree;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<ASTNode>> res;
|
||||||
|
int visitedCount = 0;
|
||||||
|
|
||||||
|
// Calculate indegree
|
||||||
|
for (auto p: m_adjList)
|
||||||
|
{
|
||||||
|
std::string u = p.first;
|
||||||
|
|
||||||
|
// On initialise à zéro si le node n'est pas dans la liste
|
||||||
|
if (inDegree.find(u) == inDegree.end())
|
||||||
|
{
|
||||||
|
inDegree[u] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto v: p.second)
|
||||||
|
{
|
||||||
|
inDegree[v]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert vertices with 0 indegree in queue
|
||||||
|
for (auto i: inDegree)
|
||||||
|
{
|
||||||
|
if (i.second == 0)
|
||||||
|
{
|
||||||
|
queue.push(nodeMap.at(i.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the queue
|
||||||
|
while(!queue.empty())
|
||||||
|
{
|
||||||
|
auto x = queue.top();
|
||||||
|
queue.pop();
|
||||||
|
visitedCount++;
|
||||||
|
|
||||||
|
res.push_back(x);
|
||||||
|
|
||||||
|
// Reduce indegree of neighbours
|
||||||
|
for (auto dest: m_adjList[x->GetId()])
|
||||||
|
{
|
||||||
|
inDegree[dest]--;
|
||||||
|
if (inDegree[dest] == 0)
|
||||||
|
{
|
||||||
|
queue.push(nodeMap.at(dest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitedCount != nodeMap.size()) {
|
||||||
|
// cout << "There exists a cycle in the graph";
|
||||||
|
// throw std::runtime_error("Graph has a cycle");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug: print in the console all the nodes in topological order
|
||||||
|
std::cout << "Topological order: \n\n";
|
||||||
|
for (const auto& a : res)
|
||||||
|
{
|
||||||
|
std::cout << a->node->GetTypeName() << " (" << a->GetId() << ") \n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ids (UUID strings) of nodes
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> m_adjList;
|
||||||
|
|
||||||
|
|
||||||
bool AreAllInputsVariables(const std::shared_ptr<BaseNode>& node, const std::unordered_map<std::string, std::shared_ptr<BaseNode>>& nodeMap) const
|
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)
|
for (const auto& conn : m_connections)
|
||||||
|
|
@ -249,94 +302,6 @@ private:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildExecutionPath(PathTree& tree,
|
|
||||||
const std::unordered_map<std::string,
|
|
||||||
std::shared_ptr<BaseNode>>& nodeMap) {
|
|
||||||
std::queue<std::shared_ptr<ASTNode>> queue;
|
|
||||||
queue.push(tree.root);
|
|
||||||
|
|
||||||
while (!queue.empty()) {
|
|
||||||
auto current = queue.front();
|
|
||||||
queue.pop();
|
|
||||||
|
|
||||||
// Find execution connections from this node
|
|
||||||
for (const auto& conn : m_connections) {
|
|
||||||
if (conn->type == Connection::EXECUTION_LINKJ &&
|
|
||||||
conn->outNodeId == current->node->GetId()) {
|
|
||||||
auto targetNode = nodeMap.find(conn->inNodeId);
|
|
||||||
if (targetNode != nodeMap.end()) {
|
|
||||||
auto childNode = std::make_shared<ASTNode>(targetNode->second);
|
|
||||||
current->children.push_back(childNode);
|
|
||||||
queue.push(childNode);
|
|
||||||
tree.connections.push_back(conn);
|
|
||||||
|
|
||||||
// For each execution node, find its data inputs
|
|
||||||
BuildDataInputs(childNode, nodeMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildDataPath(PathTree& tree,
|
|
||||||
const std::unordered_map<std::string,
|
|
||||||
std::shared_ptr<BaseNode>>& nodeMap) {
|
|
||||||
std::queue<std::shared_ptr<ASTNode>> queue;
|
|
||||||
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();
|
|
||||||
|
|
||||||
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
|
|
||||||
for (const auto& conn : m_connections) {
|
|
||||||
if (conn->type == Connection::DATA_LINK &&
|
|
||||||
conn->outNodeId == current->node->GetId()) {
|
|
||||||
auto targetNode = nodeMap.find(conn->inNodeId);
|
|
||||||
if (targetNode != nodeMap.end()) {
|
|
||||||
auto childNode = std::make_shared<ASTNode>(targetNode->second);
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
const std::unordered_map<std::string,
|
|
||||||
std::shared_ptr<BaseNode>>& nodeMap) {
|
|
||||||
for (const auto& conn : m_connections) {
|
|
||||||
if (conn->type == Connection::DATA_LINK &&
|
|
||||||
conn->inNodeId == node->node->GetId()) {
|
|
||||||
auto sourceNode = nodeMap.find(conn->outNodeId);
|
|
||||||
if (sourceNode != nodeMap.end()) {
|
|
||||||
auto inputNode = std::make_shared<ASTNode>(sourceNode->second);
|
|
||||||
node->dataInputs[conn->inPortIndex] = inputNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -188,10 +188,10 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate all constants
|
// // Generate all constants
|
||||||
for (const auto& astNode : m_ast.nodeMap) {
|
// for (const auto& astNode : m_ast.nodeMap) {
|
||||||
assemblyCode << astNode.second->node->GenerateConstants();
|
// assemblyCode << astNode.second->node->GenerateConstants();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// After the constants, the main entry point:
|
// After the constants, the main entry point:
|
||||||
assemblyCode << ".main:\n";
|
assemblyCode << ".main:\n";
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void Visit(const std::shared_ptr<Variable> v) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void GenerateExit() {
|
virtual void GenerateExit() {
|
||||||
|
|
||||||
|
|
@ -84,7 +88,7 @@ protected:
|
||||||
m_depth++;
|
m_depth++;
|
||||||
// Get condition value
|
// Get condition value
|
||||||
auto conditionNode = node->GetDataInput(0);
|
auto conditionNode = node->GetDataInput(0);
|
||||||
int conditionValue = EvaluateCondition(conditionNode);
|
int conditionValue = 0;
|
||||||
|
|
||||||
FlowVisualizer::PrintBranchDecision(conditionValue > 7,
|
FlowVisualizer::PrintBranchDecision(conditionValue > 7,
|
||||||
std::to_string(conditionValue), m_depth);
|
std::to_string(conditionValue), m_depth);
|
||||||
|
|
@ -105,18 +109,16 @@ protected:
|
||||||
m_depth++;
|
m_depth++;
|
||||||
auto* opNode = node->GetAs<OperatorNode>();
|
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("Operand 1", opNode->GetOperatorSymbol(),
|
||||||
FlowVisualizer::PrintDataFlow("ADD", "Result",
|
std::to_string(0), m_depth);
|
||||||
std::to_string(result), m_depth);
|
FlowVisualizer::PrintDataFlow("Operand 2", opNode->GetOperatorSymbol(),
|
||||||
|
std::to_string(0), m_depth);
|
||||||
|
|
||||||
|
|
||||||
|
FlowVisualizer::PrintDataFlow(opNode->GetOperatorSymbol(), "Result",
|
||||||
|
std::to_string(0), m_depth);
|
||||||
|
|
||||||
for (const auto& [port, outputs] : node->dataOutputs) {
|
for (const auto& [port, outputs] : node->dataOutputs) {
|
||||||
for (const auto& target : outputs) {
|
for (const auto& target : outputs) {
|
||||||
|
|
@ -148,24 +150,4 @@ protected:
|
||||||
private:
|
private:
|
||||||
int m_depth = 0;
|
int m_depth = 0;
|
||||||
|
|
||||||
int EvaluateOperand(std::shared_ptr<ASTNode> node) {
|
|
||||||
if (!node) 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,7 +2,6 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
#include "compiler.h"
|
|
||||||
|
|
||||||
static std::string ChoiceLabel(const std::string &id)
|
static std::string ChoiceLabel(const std::string &id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,13 @@ float BaseNode::GetY() const
|
||||||
{
|
{
|
||||||
return m_pos.y;
|
return m_pos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseNode::Accept(IVariableVisitor &visitor)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (auto &v : m_variables)
|
||||||
|
{
|
||||||
|
visitor.Visit(v.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,14 @@
|
||||||
#include "i_story_page.h"
|
#include "i_story_page.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_project.h"
|
||||||
#include "story_options.h"
|
#include "story_options.h"
|
||||||
|
#include "variable.h"
|
||||||
|
|
||||||
|
class IVariableVisitor {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Visit(const std::shared_ptr<Variable> v) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class BaseNode
|
class BaseNode
|
||||||
{
|
{
|
||||||
|
|
@ -70,10 +78,6 @@ public:
|
||||||
|
|
||||||
virtual void Initialize() = 0;
|
virtual void Initialize() = 0;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) = 0;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) = 0;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) = 0;
|
|
||||||
|
|
||||||
virtual std::string GenerateConstants() const { return ""; }
|
|
||||||
virtual std::string GenerateAssembly() const = 0;
|
|
||||||
|
|
||||||
void SetPosition(float x, float y);
|
void SetPosition(float x, float y);
|
||||||
|
|
||||||
|
|
@ -97,6 +101,15 @@ public:
|
||||||
return m_typeName;
|
return m_typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetWeight(int w) {
|
||||||
|
m_weight = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetWeight() const {
|
||||||
|
return m_weight;
|
||||||
|
}
|
||||||
|
|
||||||
void SetId(const std::string &id) { m_uuid = id; }
|
void SetId(const std::string &id) { m_uuid = id; }
|
||||||
std::string GetId() const { return m_uuid; }
|
std::string GetId() const { return m_uuid; }
|
||||||
|
|
||||||
|
|
@ -134,12 +147,21 @@ public:
|
||||||
return m_behavior;
|
return m_behavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Accept(IVariableVisitor &visitor);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Easy access the variables for children nodes
|
||||||
|
// Key is the variable name, or whatever the node use to identify the variable
|
||||||
|
std::map<std::string, std::shared_ptr<Variable>> m_variables;
|
||||||
|
|
||||||
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;
|
||||||
|
int m_weight{0};
|
||||||
Behavior m_behavior{BEHAVIOR_EXECUTION};
|
Behavior m_behavior{BEHAVIOR_EXECUTION};
|
||||||
|
|
||||||
std::vector<Port> m_inputPorts;
|
std::vector<Port> m_inputPorts;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
#include "compiler.h"
|
|
||||||
|
|
||||||
|
|
||||||
BranchNode::BranchNode(const std::string &type)
|
BranchNode::BranchNode(const std::string &type)
|
||||||
|
|
@ -17,15 +16,8 @@ void BranchNode::Initialize()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BranchNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string BranchNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
std::string BranchNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ public:
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
|
||||||
|
|
||||||
virtual std::string GenerateAssembly() const { return ""; }
|
virtual std::string GenerateAssembly() const { return ""; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
#include "compiler.h"
|
|
||||||
|
|
||||||
|
|
||||||
CompareNode::CompareNode(const std::string &type)
|
CompareNode::CompareNode(const std::string &type)
|
||||||
|
|
@ -17,15 +16,8 @@ void CompareNode::Initialize()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CompareNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CompareNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
std::string CompareNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ public:
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "base_node.h"
|
|
||||||
|
|
||||||
class ExecutionNode : public BaseNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ExecutionNode(const std::string &type, const std::string &typeName)
|
|
||||||
: BaseNode(type, typeName) {}
|
|
||||||
|
|
||||||
void Initialize() override {
|
|
||||||
// Initialisation spécifique pour ExecutionNode
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
|
|
||||||
return GetMyEntryLabel() + ":\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GenerateAssembly() const override {
|
|
||||||
return GetMyEntryLabel() + ":\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
|
|
||||||
// Génération des constantes pour ExecutionNode
|
|
||||||
return "ExecutionNode Constants";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajoutez des méthodes spécifiques pour gérer les entrées et sorties d'exécution
|
|
||||||
void AddExecutionInput() {
|
|
||||||
// Logique pour ajouter une entrée d'exécution
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddExecutionOutput() {
|
|
||||||
// Logique pour ajouter une sortie d'exécution
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "execution_node.h"
|
#include "base_node.h"
|
||||||
|
|
||||||
|
|
||||||
class FunctionEntryNode : public ExecutionNode
|
class FunctionEntryNode : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionEntryNode(const std::string &type)
|
FunctionEntryNode(const std::string &type)
|
||||||
: ExecutionNode(type, "Function Entry Node") {}
|
: BaseNode(type, "Function Entry Node")
|
||||||
|
{
|
||||||
|
SetWeight(100);
|
||||||
|
}
|
||||||
|
|
||||||
void Initialize() override {
|
void Initialize() override {
|
||||||
// Initialisation spécifique pour FunctionEntryNode
|
// Initialisation spécifique pour FunctionEntryNode
|
||||||
|
|
@ -19,11 +22,6 @@ public:
|
||||||
return GetMyEntryLabel() + ":\n";
|
return GetMyEntryLabel() + ":\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
|
|
||||||
// Génération des constantes pour FunctionEntryNode
|
|
||||||
return "FunctionEntryNode Constants";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajoutez des méthodes spécifiques pour gérer l'entrée de la fonction
|
// Ajoutez des méthodes spécifiques pour gérer l'entrée de la fonction
|
||||||
void PrepareFunctionEntry() {
|
void PrepareFunctionEntry() {
|
||||||
// Logique pour préparer l'entrée de la fonction
|
// Logique pour préparer l'entrée de la fonction
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,6 @@ public:
|
||||||
return "FunctionExitNode Build";
|
return "FunctionExitNode Build";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
|
|
||||||
// Génération des constantes pour FunctionExitNode
|
|
||||||
return "FunctionExitNode Constants";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction
|
// Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction
|
||||||
void FinalizeFunctionExit() {
|
void FinalizeFunctionExit() {
|
||||||
// Logique pour finaliser la sortie de la fonction
|
// Logique pour finaliser la sortie de la fonction
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,3 @@ std::string FunctionNode::Build(IStoryPage &page, const StoryOptions &options, i
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FunctionNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ public:
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
|
||||||
|
|
||||||
void StoreInternalData();
|
void StoreInternalData();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,56 +105,6 @@ public:
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateConstants(IStoryPage& page, IStoryProject& project, int nb_out_conns) override {
|
|
||||||
return ""; // Operators don't generate constants
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GenerateAssembly() const override {
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
switch (m_operationType) {
|
|
||||||
case OperationType::ADD:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " add eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
case OperationType::SUBTRACT:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " sub eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
case OperationType::MULTIPLY:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " imul eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
case OperationType::DIVIDE:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " cdq\n" // Sign extend eax into edx
|
|
||||||
<< " idiv ebx\n"
|
|
||||||
<< " push eax\n"; // Push quotient
|
|
||||||
break;
|
|
||||||
case OperationType::AND:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " and eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
case OperationType::OR:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " or eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
// Add other operators...
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OperationType m_operationType;
|
OperationType m_operationType;
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,17 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
#include "compiler.h"
|
|
||||||
|
|
||||||
|
|
||||||
PrintNode::PrintNode(const std::string &type)
|
PrintNode::PrintNode(const std::string &type)
|
||||||
: ExecutionNode(type, "Print Node")
|
: BaseNode(type, "Print Node")
|
||||||
{
|
{
|
||||||
m_label = GenerateRandomString(10, BaseNode::CHARSET_ALPHABET_LOWER | BaseNode::CHARSET_ALPHABET_UPPER );// Should be enough to avoid collision?
|
m_label = GenerateRandomString(10, BaseNode::CHARSET_ALPHABET_LOWER | BaseNode::CHARSET_ALPHABET_UPPER );// Should be enough to avoid collision?
|
||||||
|
|
||||||
|
// Create empty variable in memory
|
||||||
|
auto v = std::make_shared<Variable>(m_label);
|
||||||
|
v->SetTextValue("");
|
||||||
|
m_variables[m_label] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,41 +21,9 @@ void PrintNode::Initialize()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "$" << m_label << " DC8, " << m_text << "\n";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintNode::GenerateConstants() const
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "$" << m_label << " DC8, \"" << m_text << "\"\n";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PrintNode::GenerateAssembly() const
|
|
||||||
{
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
ss << ExecutionNode::GenerateAssembly()
|
|
||||||
<< " push r0\n"
|
|
||||||
<< " push r1\n"
|
|
||||||
<< " lcons r0, $" << m_label << "\n"
|
|
||||||
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
|
|
||||||
<< " syscall 4\n"
|
|
||||||
<< " pop r1\n"
|
|
||||||
<< " pop r0\n";
|
|
||||||
|
|
||||||
// << ""mov r2, %2 // arguments are in r2, r3, r4 etc.
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,33 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "i_story_manager.h"
|
#include "i_story_manager.h"
|
||||||
#include "execution_node.h"
|
#include "base_node.h"
|
||||||
#include "i_script_node.h"
|
#include "i_script_node.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_project.h"
|
||||||
|
|
||||||
class PrintNode : public ExecutionNode
|
class PrintNode : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PrintNode(const std::string &type);
|
PrintNode(const std::string &type);
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
|
||||||
|
|
||||||
virtual std::string GenerateConstants() const override;
|
|
||||||
|
|
||||||
std::string GenerateAssembly() const override;
|
|
||||||
|
|
||||||
void SetText(const std::string &text) {
|
void SetText(const std::string &text) {
|
||||||
m_text = text;
|
|
||||||
|
m_variables.at(m_label)->SetValue<std::string>(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetLabel() const {
|
||||||
|
return m_label;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetText() const {
|
std::string GetText() const {
|
||||||
return m_text;
|
return m_variables.at(m_label)->GetValue<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_label;
|
std::string m_label; // Label for the string literal
|
||||||
std::string m_text; // Text to print
|
|
||||||
uint32_t m_arguments{0}; // number of arguments
|
uint32_t m_arguments{0}; // number of arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,3 @@ std::string VariableNode::Build(IStoryPage &page, const StoryOptions &options, i
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VariableNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
|
#include "variable.h"
|
||||||
#include "i_story_manager.h"
|
#include "i_story_manager.h"
|
||||||
#include "base_node.h"
|
#include "base_node.h"
|
||||||
#include "i_script_node.h"
|
#include "i_script_node.h"
|
||||||
|
|
@ -12,92 +12,25 @@ class VariableNode : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class ValueType {
|
|
||||||
INTEGER,
|
|
||||||
FLOAT,
|
|
||||||
BOOL,
|
|
||||||
STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
using VariableValue = std::variant<int, float, bool, std::string>;
|
|
||||||
|
|
||||||
VariableNode(const std::string &type = "variable-node");
|
VariableNode(const std::string &type = "variable-node");
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
|
||||||
|
|
||||||
virtual std::string GenerateAssembly() const { return ""; }
|
virtual std::string GenerateAssembly() const { return ""; }
|
||||||
|
|
||||||
void StoreInternalData();
|
void StoreInternalData();
|
||||||
|
|
||||||
|
void SetVariableUuid(const std::string &uuid) {
|
||||||
// Setters
|
m_variableUuid = uuid;
|
||||||
void SetVariableName(const std::string& name) {
|
|
||||||
m_variableName = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetConstant(bool isConstant) {
|
std::string GetVariableUuid() const {
|
||||||
m_isConstant = isConstant;
|
return m_variableUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetValueType(ValueType type) {
|
|
||||||
m_valueType = type;
|
|
||||||
// Reset value to default for new type
|
|
||||||
switch (type) {
|
|
||||||
case ValueType::INTEGER:
|
|
||||||
m_value = 0;
|
|
||||||
break;
|
|
||||||
case ValueType::FLOAT:
|
|
||||||
m_value = 0.0f;
|
|
||||||
break;
|
|
||||||
case ValueType::BOOL:
|
|
||||||
m_value = false;
|
|
||||||
break;
|
|
||||||
case ValueType::STRING:
|
|
||||||
m_value = "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void SetValue(const T& value) {
|
|
||||||
try {
|
|
||||||
m_value = value;
|
|
||||||
} catch (const std::bad_variant_access&) {
|
|
||||||
throw std::runtime_error("Invalid value type for variable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
std::string GetVariableName() const {
|
|
||||||
return m_variableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsConstant() const {
|
|
||||||
return m_isConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueType GetValueType() const {
|
|
||||||
return m_valueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T GetValue() const {
|
|
||||||
try {
|
|
||||||
return std::get<T>(m_value);
|
|
||||||
} catch (const std::bad_variant_access&) {
|
|
||||||
throw std::runtime_error("Invalid value type requested");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_variableName;
|
std::string m_variableUuid;
|
||||||
ValueType m_valueType;
|
|
||||||
VariableValue m_value;
|
|
||||||
bool m_isConstant;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ public:
|
||||||
|
|
||||||
void Build(std::stringstream &code, IStoryProject &project)
|
void Build(std::stringstream &code, IStoryProject &project)
|
||||||
{
|
{
|
||||||
// First generate all constants
|
// // First generate all constants
|
||||||
for (const auto & n : m_nodes)
|
// for (const auto & n : m_nodes)
|
||||||
{
|
// {
|
||||||
code << n->GenerateConstants(*this, project, OutputsCount(n->GetId())) << "\n";
|
// code << n->GenerateConstants(*this, project, OutputsCount(n->GetId())) << "\n";
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ THE SOFTWARE.
|
||||||
#include "function_entry_node.h"
|
#include "function_entry_node.h"
|
||||||
#include "operator_node.h"
|
#include "operator_node.h"
|
||||||
#include "chip32_machine.h"
|
#include "chip32_machine.h"
|
||||||
|
#include "variable.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -43,47 +44,7 @@ THE SOFTWARE.
|
||||||
#include "assembly_generator.h"
|
#include "assembly_generator.h"
|
||||||
#include "flow_generator.h"
|
#include "flow_generator.h"
|
||||||
#include "assembly_generator_chip32.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;
|
|
||||||
queue.push({tree.root, depth});
|
|
||||||
std::unordered_set<std::string> visited;
|
|
||||||
|
|
||||||
while (!queue.empty()) {
|
|
||||||
auto [node, currentDepth] = queue.front();
|
|
||||||
queue.pop();
|
|
||||||
|
|
||||||
if (visited.find(node->node->GetId()) != visited.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
visited.insert(node->node->GetId());
|
|
||||||
|
|
||||||
std::string indent(currentDepth * 2, ' ');
|
|
||||||
std::cout << indent << "Node: " << node->node->GetTypeName()
|
|
||||||
<< " (ID: " << node->node->GetId() << ")" << std::endl;
|
|
||||||
|
|
||||||
// Print data inputs
|
|
||||||
for (const auto& [portIndex, inputNode] : node->dataInputs) {
|
|
||||||
std::cout << indent << " Input at port " << portIndex
|
|
||||||
<< " from: " << inputNode->node->GetTypeName() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print data outputs
|
|
||||||
for (const auto& [portIndex, outputs] : node->dataOutputs) {
|
|
||||||
for (const auto& [targetNode, targetPort] : outputs) {
|
|
||||||
std::cout << indent << " Output from port " << portIndex
|
|
||||||
<< " to: " << targetNode->node->GetTypeName()
|
|
||||||
<< " port " << targetPort << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add children to queue
|
|
||||||
for (const auto& child : node->children) {
|
|
||||||
queue.push({child, currentDepth + 1});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
TEST_CASE( "Check various indentations and typos" ) {
|
TEST_CASE( "Check various indentations and typos" ) {
|
||||||
|
|
||||||
Compiler compiler;
|
Compiler compiler;
|
||||||
|
|
@ -98,20 +59,50 @@ 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 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");
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
variableNode2->SetValue(10);
|
auto var1 = std::make_shared<Variable>("X");
|
||||||
variableNode2->SetValueType(VariableNode::ValueType::INTEGER);
|
var1->SetValue(5);
|
||||||
variableNode2->SetVariableName("Y");
|
var1->SetValueType(Variable::ValueType::INTEGER);
|
||||||
|
|
||||||
|
auto var2 = std::make_shared<Variable>("Y");
|
||||||
|
var2->SetValue(10);
|
||||||
|
var2->SetValueType(Variable::ValueType::INTEGER);
|
||||||
|
|
||||||
|
auto var3 = std::make_shared<Variable>("A");
|
||||||
|
var3->SetValue(7);
|
||||||
|
var3->SetValueType(Variable::ValueType::INTEGER);
|
||||||
|
|
||||||
|
auto var4 = std::make_shared<Variable>("B");
|
||||||
|
var4->SetValue(2);
|
||||||
|
var4->SetValueType(Variable::ValueType::INTEGER);
|
||||||
|
|
||||||
|
|
||||||
|
variables.push_back(var1);
|
||||||
|
variables.push_back(var2);
|
||||||
|
variables.push_back(var3);
|
||||||
|
variables.push_back(var4);
|
||||||
|
|
||||||
|
auto variableNodeX = std::make_shared<VariableNode>("variable-node");
|
||||||
|
variableNodeX->SetVariableUuid(var1->GetUuid());
|
||||||
|
|
||||||
|
auto variableNodeY = std::make_shared<VariableNode>("variable-node");
|
||||||
|
variableNodeY->SetVariableUuid(var2->GetUuid());
|
||||||
|
|
||||||
|
auto variableNodeA = std::make_shared<VariableNode>("variable-node");
|
||||||
|
variableNodeA->SetVariableUuid(var3->GetUuid());
|
||||||
|
|
||||||
|
auto variableNodeB = std::make_shared<VariableNode>("variable-node");
|
||||||
|
variableNodeB->SetVariableUuid(var4->GetUuid());
|
||||||
|
|
||||||
auto testNode = std::make_shared<OperatorNode>();
|
auto testNode = std::make_shared<OperatorNode>();
|
||||||
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
|
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
|
||||||
|
|
||||||
|
auto addNode = std::make_shared<OperatorNode>();
|
||||||
|
addNode->SetOperationType(OperatorNode::OperationType::ADD);
|
||||||
|
|
||||||
|
auto subNode = std::make_shared<OperatorNode>();
|
||||||
|
subNode->SetOperationType(OperatorNode::OperationType::SUBTRACT);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<BaseNode>> nodes;
|
std::vector<std::shared_ptr<BaseNode>> nodes;
|
||||||
|
|
||||||
|
|
@ -119,9 +110,13 @@ 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(variableNode1);
|
nodes.push_back(variableNodeX);
|
||||||
nodes.push_back(variableNode2);
|
nodes.push_back(variableNodeY);
|
||||||
|
nodes.push_back(variableNodeA);
|
||||||
|
nodes.push_back(variableNodeB);
|
||||||
nodes.push_back(testNode);
|
nodes.push_back(testNode);
|
||||||
|
nodes.push_back(addNode);
|
||||||
|
nodes.push_back(subNode);
|
||||||
|
|
||||||
auto cn1 = std::make_shared<Connection>();
|
auto cn1 = std::make_shared<Connection>();
|
||||||
auto cn2 = std::make_shared<Connection>();
|
auto cn2 = std::make_shared<Connection>();
|
||||||
|
|
@ -129,6 +124,10 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
auto cn4 = std::make_shared<Connection>();
|
auto cn4 = std::make_shared<Connection>();
|
||||||
auto cn5 = std::make_shared<Connection>();
|
auto cn5 = std::make_shared<Connection>();
|
||||||
auto cn6 = std::make_shared<Connection>();
|
auto cn6 = std::make_shared<Connection>();
|
||||||
|
auto cn7 = std::make_shared<Connection>();
|
||||||
|
auto cn8 = std::make_shared<Connection>();
|
||||||
|
auto cn9 = std::make_shared<Connection>();
|
||||||
|
auto cn10 = std::make_shared<Connection>();
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Connection>> connections;
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
|
@ -138,7 +137,10 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
connections.push_back(cn4);
|
connections.push_back(cn4);
|
||||||
connections.push_back(cn5);
|
connections.push_back(cn5);
|
||||||
connections.push_back(cn6);
|
connections.push_back(cn6);
|
||||||
|
connections.push_back(cn7);
|
||||||
|
connections.push_back(cn8);
|
||||||
|
connections.push_back(cn9);
|
||||||
|
connections.push_back(cn10);
|
||||||
|
|
||||||
// Branch True -> print Ok
|
// Branch True -> print Ok
|
||||||
// False -> print Ko
|
// False -> print Ko
|
||||||
|
|
@ -168,47 +170,47 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
cn4->outPortIndex = 0;
|
cn4->outPortIndex = 0;
|
||||||
cn4->type = Connection::DATA_LINK;
|
cn4->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
// Variable 1 -> Compare test node input 1
|
// + output 1 -> Compare test node input 1
|
||||||
cn5->inNodeId = testNode->GetId();
|
cn5->inNodeId = testNode->GetId();
|
||||||
cn5->inPortIndex = 0;
|
cn5->inPortIndex = 0;
|
||||||
cn5->outNodeId = variableNode1->GetId();
|
cn5->outNodeId = addNode->GetId();
|
||||||
cn5->outPortIndex = 0;
|
cn5->outPortIndex = 0;
|
||||||
cn5->type = Connection::DATA_LINK;
|
cn5->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
// Variable 1 -> Compare test node input 1
|
// - output -> Compare test node input 1
|
||||||
cn6->inNodeId = testNode->GetId();
|
cn6->inNodeId = testNode->GetId();
|
||||||
cn6->inPortIndex = 1;
|
cn6->inPortIndex = 1;
|
||||||
cn6->outNodeId = variableNode2->GetId();
|
cn6->outNodeId = subNode->GetId();
|
||||||
cn6->outPortIndex = 0;
|
cn6->outPortIndex = 0;
|
||||||
cn6->type = Connection::DATA_LINK;
|
cn6->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
|
// ADD NODE INPUTS
|
||||||
|
|
||||||
// // Création des nœuds
|
cn7->inNodeId = addNode->GetId();
|
||||||
// std::vector<Node> nodes = {
|
cn7->inPortIndex = 0;
|
||||||
// Node(Node::Type::VARIABLE, "i", "node_i"),
|
cn7->outNodeId = variableNodeX->GetId();
|
||||||
// Node(Node::Type::CONSTANT, 10, "node_10"),
|
cn7->outPortIndex = 0;
|
||||||
// Node(Node::Type::SUBTRACT, "node_subtract"),
|
cn7->type = Connection::DATA_LINK;
|
||||||
// Node(Node::Type::CONSTANT, 1, "node_1"),
|
|
||||||
// Node(Node::Type::ADD, "node_add"),
|
|
||||||
// Node(Node::Type::ASSIGN, "i", "node_assign"),
|
|
||||||
// Node(Node::Type::VARIABLE, "conditionVar", "node_condVar"),
|
|
||||||
// Node(Node::Type::CONSTANT, 2, "node_2"),
|
|
||||||
// Node(Node::Type::MULTIPLY, "node_multiply"),
|
|
||||||
// Node(Node::Type::ASSIGN, "i", "node_assign_multiply"),
|
|
||||||
// Node(Node::Type::BRANCH, "node_branch"),
|
|
||||||
// Node(Node::Type::LOOP, "node_loop")
|
|
||||||
// };
|
|
||||||
|
|
||||||
// try
|
cn8->inNodeId = addNode->GetId();
|
||||||
// {
|
cn8->inPortIndex = 1;
|
||||||
// // Construction de l'AST
|
cn8->outNodeId = variableNodeY->GetId();
|
||||||
// compiler.buildAST(nodes, connections);
|
cn8->outPortIndex = 0;
|
||||||
// compiler.printAST();
|
cn8->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
// } catch(const std::exception &e)
|
// SUBTRACT NODE INPUTS
|
||||||
// {
|
|
||||||
// std::cout << e.what() << std::endl;
|
cn9->inNodeId = subNode->GetId();
|
||||||
// }
|
cn9->inPortIndex = 0;
|
||||||
|
cn9->outNodeId = variableNodeA->GetId();
|
||||||
|
cn9->outPortIndex = 0;
|
||||||
|
cn9->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
|
cn10->inNodeId = subNode->GetId();
|
||||||
|
cn10->inPortIndex = 1;
|
||||||
|
cn10->outNodeId = variableNodeB->GetId();
|
||||||
|
cn10->outPortIndex = 0;
|
||||||
|
cn10->type = Connection::DATA_LINK;
|
||||||
|
|
||||||
|
|
||||||
// Create generator context with current time and user
|
// Create generator context with current time and user
|
||||||
|
|
@ -227,34 +229,19 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
ASTBuilder builder(nodes, connections);
|
ASTBuilder builder(nodes, connections);
|
||||||
auto pathTrees = builder.BuildAST();
|
auto pathTrees = builder.BuildAST();
|
||||||
|
|
||||||
/*
|
|
||||||
// Process each path tree
|
|
||||||
for (const auto& tree : pathTrees) {
|
|
||||||
std::cout << (tree.isExecutionPath ? "Execution" : "Data")
|
|
||||||
<< " Path Tree:" << std::endl;
|
|
||||||
ProcessASTTree(tree);
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Generate flow in the console
|
// Generate flow in the console
|
||||||
VisualFlowGenerator flowGenerator(context);
|
VisualFlowGenerator flowGenerator(context);
|
||||||
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::string flow = flowGenerator.GenerateAssembly(nodes, pathTrees, variables);
|
||||||
|
|
||||||
|
|
||||||
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(nodes, pathTrees);
|
std::string assembly = generator.GenerateAssembly(nodes, pathTrees, variables);
|
||||||
|
|
||||||
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
|
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
|
||||||
|
|
||||||
// compiler.generateAssembly();
|
|
||||||
|
|
||||||
// std::cout << compiler.GetCode() << std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
// Chip32::Machine machine;
|
// Chip32::Machine machine;
|
||||||
|
|
||||||
// machine.QuickExecute(compiler.GetCode());
|
// machine.QuickExecute(compiler.GetCode());
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue