mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-10 18:33:15 +01:00
Compare commits
3 commits
5c16e2bd94
...
51eac85360
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51eac85360 | ||
|
|
a42fdc81ea | ||
|
|
3c1224e937 |
40 changed files with 863 additions and 902 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -109,7 +109,8 @@
|
|||
"text_encoding": "cpp",
|
||||
"serializers.h": "c",
|
||||
"ni_parser.h": "c",
|
||||
"*.m": "cpp"
|
||||
"*.m": "cpp",
|
||||
"*.inc": "cpp"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -83,9 +83,9 @@ typedef enum
|
|||
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
||||
|
||||
// Comparison
|
||||
OP_CMP_EQ = 28, ///< compare two registers for equality, result in first e.g.: cmp_eq r4, r0, r1 (r4 = (r0 == r1 ? 1 : 0)
|
||||
OP_CMP_GT = 29, ///< compare if first register is greater than the second, result in first e.g.: cmp_gt r4, r0, r1
|
||||
OP_CMP_LT = 30, ///< compare if first register is less than the second, result in first e.g.: cmp_lt r4, r0, r1
|
||||
OP_CMP_EQ = 28, ///< compare two registers for equality, result in first e.g.: eq r4, r0, r1 (r4 = (r0 == r1 ? 1 : 0)
|
||||
OP_CMP_GT = 29, ///< compare if first register is greater than the second, result in first e.g.: gt r4, r0, r1
|
||||
OP_CMP_LT = 30, ///< compare if first register is less than the second, result in first e.g.: lt r4, r0, r1
|
||||
|
||||
INSTRUCTION_COUNT
|
||||
} chip32_instruction_t;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ Purpose: grammar, ram usage and macros, rom code generation
|
|||
void hexdump(void *ptr, int buflen);
|
||||
|
||||
static const std::string test1 = R"(; jump over the data, to our entry label
|
||||
jump .entry
|
||||
|
||||
$imageBird DC8 "example.bmp", 8 ; data
|
||||
$someConstant DC32 12456789
|
||||
|
|
@ -46,7 +45,7 @@ $RamData1 DV32 1 ; one 32-bit integer
|
|||
$MyArray DV8 10 ; array of 10 bytes
|
||||
|
||||
; label definition
|
||||
.entry: ;; comment here should work
|
||||
.main: ;; comment here should work
|
||||
; We create a stupid loop just for RAM variable testing
|
||||
|
||||
lcons r0, 4 ; prepare loop: 4 iterations
|
||||
|
|
@ -183,14 +182,12 @@ static const std::string testPrintf = R"(
|
|||
; ========================================================
|
||||
; We test the printf system call
|
||||
; ========================================================
|
||||
jump .entry
|
||||
|
||||
$printHello DC8 "La réponse est %d"
|
||||
$answer DC32 42
|
||||
|
||||
$counter DV32 10
|
||||
|
||||
.entry:
|
||||
.main:
|
||||
|
||||
; prepapre loop
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
virtual uint32_t GetRegister(int reg) = 0;
|
||||
|
||||
// Variables management
|
||||
virtual void ScanVariable(const std::function<void(Variable& element)>& operation) = 0;
|
||||
virtual void ScanVariable(const std::function<void(std::shared_ptr<Variable> element)>& operation) = 0;
|
||||
virtual void AddVariable() = 0;
|
||||
virtual void DeleteVariable(int i) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,19 +2,219 @@
|
|||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
|
||||
struct Variable {
|
||||
static const uint32_t NameMaxSize = 50;
|
||||
std::string name; // Nom de la 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;
|
||||
int scalePower; // Nombre de bits pour la partie fractionnaire
|
||||
#include "uuid.h"
|
||||
|
||||
Variable(const std::string &n, const std::string &t, int64_t v, int s) {
|
||||
name = n;
|
||||
type = t;
|
||||
value = v;
|
||||
scalePower = s;
|
||||
class Variable
|
||||
{
|
||||
|
||||
public:
|
||||
enum class ValueType {
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
BOOL,
|
||||
STRING
|
||||
};
|
||||
|
||||
enum RandomFlags
|
||||
{
|
||||
CHARSET_ALPHABET_LOWER = 0x1, // "abcdefghijklmnopqrstuvwxyz"
|
||||
CHARSET_ALPHABET_UPPER = 0x2, // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
CHARSET_NUMBERS = 0x4, // "0123456789"
|
||||
CHARSET_SIGNS = 0x8, // "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||||
ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS
|
||||
};
|
||||
|
||||
static const int NameMaxSize = 32; // Max size for the variable name
|
||||
|
||||
Variable() {
|
||||
m_uuid = Uuid().String();
|
||||
m_label = Variable::GenerateRandomString(10, Variable::CHARSET_ALPHABET_LOWER | Variable::CHARSET_ALPHABET_UPPER );
|
||||
}
|
||||
|
||||
Variable (const std::string &name)
|
||||
: Variable()
|
||||
{
|
||||
m_variableName = name;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void SetScalePower(int scalePower) {
|
||||
m_scalePower = scalePower;
|
||||
}
|
||||
|
||||
// Getters
|
||||
std::string GetVariableName() const {
|
||||
return m_variableName;
|
||||
}
|
||||
|
||||
bool IsConstant() const {
|
||||
return m_isConstant;
|
||||
}
|
||||
|
||||
ValueType GetValueType() const {
|
||||
return m_valueType;
|
||||
}
|
||||
|
||||
std::string GetLabel() const {
|
||||
return m_label;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetStringValue() const {
|
||||
return GetValue<std::string>();
|
||||
}
|
||||
|
||||
int GetIntegerValue() const {
|
||||
return GetValue<int>();
|
||||
}
|
||||
|
||||
float GetFloatValue() const {
|
||||
return GetValue<float>();
|
||||
}
|
||||
|
||||
bool GetBoolValue() const {
|
||||
return GetValue<bool>();
|
||||
}
|
||||
|
||||
using VariableValue = std::variant<int, float, bool, std::string>;
|
||||
|
||||
std::string GetUuid() const {
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
bool IsString() const {
|
||||
return m_valueType == ValueType::STRING;
|
||||
}
|
||||
bool IsInteger() const {
|
||||
return m_valueType == ValueType::INTEGER;
|
||||
}
|
||||
bool IsFloat() const {
|
||||
return m_valueType == ValueType::FLOAT;
|
||||
}
|
||||
bool IsBool() const {
|
||||
return m_valueType == ValueType::BOOL;
|
||||
}
|
||||
|
||||
int GetScalePower() const {
|
||||
return m_scalePower;
|
||||
}
|
||||
|
||||
static std::string GenerateRandomString(size_t length, uint32_t flags)
|
||||
{
|
||||
std::string charset = "";
|
||||
|
||||
if (flags & CHARSET_ALPHABET_LOWER)
|
||||
{
|
||||
charset += "abcdefghijklmnopqrstuvwxyz";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_ALPHABET_UPPER)
|
||||
{
|
||||
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_NUMBERS)
|
||||
{
|
||||
charset += "0123456789";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_SIGNS)
|
||||
{
|
||||
charset += "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||||
}
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 generator(rd());
|
||||
std::uniform_int_distribution<> distribution(0, charset.size() - 1);
|
||||
|
||||
std::string result;
|
||||
result.reserve(length);
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
result += charset[distribution(generator)];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_variableName; // nom humain
|
||||
ValueType m_valueType;
|
||||
VariableValue m_value;
|
||||
bool m_isConstant;
|
||||
std::string m_uuid; // pour identifier le variable dans le JSON du projet
|
||||
std::string m_label; // pour la génération assembleur
|
||||
int m_scalePower; // Nombre de bits pour la partie fractionnaire
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,12 +15,10 @@
|
|||
#include "variable_node.h"
|
||||
#include "branch_node.h"
|
||||
#include "operator_node.h"
|
||||
#include "base_node.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class AssemblyGenerator {
|
||||
class AssemblyGenerator : public IVariableVisitor {
|
||||
public:
|
||||
struct GeneratorContext {
|
||||
std::string timestamp;
|
||||
|
|
@ -58,9 +56,8 @@ public:
|
|||
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<std::shared_ptr<ASTNode>>& order, const std::vector<std::shared_ptr<Variable>> &variables)
|
||||
{
|
||||
m_roots = roots;
|
||||
Reset();
|
||||
|
||||
// Generate header comments
|
||||
|
|
@ -68,11 +65,11 @@ public:
|
|||
|
||||
// Generate data section
|
||||
StartSection(Section::DATA);
|
||||
GenerateDataSection(nodes, roots);
|
||||
GenerateDataSection(nodes, variables);
|
||||
|
||||
// Generate text section
|
||||
StartSection(Section::TEXT);
|
||||
GenerateTextSection(roots);
|
||||
GenerateTextSection(order);
|
||||
|
||||
return m_assembly.str();
|
||||
}
|
||||
|
|
@ -90,6 +87,8 @@ protected:
|
|||
|
||||
virtual void GenerateExit() = 0;
|
||||
|
||||
virtual void GenerateVariable(const std::shared_ptr<Variable> v) = 0;
|
||||
|
||||
|
||||
std::string AddStringLiteral(const std::string& text)
|
||||
{
|
||||
|
|
@ -112,7 +111,7 @@ protected:
|
|||
std::vector<std::string> m_stringLiterals;
|
||||
int m_depth{0};
|
||||
Section m_currentSection;
|
||||
std::vector<PathTree> m_roots;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -139,59 +138,47 @@ 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
|
||||
for (const auto& n : nodes) {
|
||||
m_assembly << n->GenerateConstants();
|
||||
n->Accept(*this);
|
||||
}
|
||||
|
||||
// Generate string literals
|
||||
for (const auto& literal : m_stringLiterals) {
|
||||
std::string label = "str_" + std::to_string(m_labelCounter++);
|
||||
m_assembly << label << " db '" << literal << "',0\n"
|
||||
<< label << "_len equ $ - " << label << "\n";
|
||||
}
|
||||
|
||||
// Generate variables
|
||||
for (const auto& t : trees) {
|
||||
CollectVariables(t.root);
|
||||
// generate all variables in RAM
|
||||
for (auto & v : variables)
|
||||
{
|
||||
GenerateVariable(v);
|
||||
}
|
||||
|
||||
m_assembly << "\n\n";
|
||||
}
|
||||
|
||||
void GenerateTextSection(const std::vector<PathTree>& trees) {
|
||||
void GenerateTextSection(const std::vector<std::shared_ptr<ASTNode>>& orderedNodes) {
|
||||
// Program entry point
|
||||
m_assembly << ".main:\n";
|
||||
|
||||
// Process execution paths first
|
||||
for (const auto& tree : trees) {
|
||||
if (tree.isExecutionPath) {
|
||||
GenerateNodeCode(tree.root);
|
||||
}
|
||||
}
|
||||
|
||||
// Process data paths
|
||||
for (const auto& tree : trees) {
|
||||
if (!tree.isExecutionPath) {
|
||||
GenerateNodeCode(tree.root, true);
|
||||
}
|
||||
for (const auto& node : orderedNodes) {
|
||||
GenerateNodeCode(node);
|
||||
}
|
||||
|
||||
// Program exit
|
||||
GenerateExit();
|
||||
}
|
||||
|
||||
void CollectVariables(std::shared_ptr<ASTNode> node) {
|
||||
void CollectVariables(std::shared_ptr<ASTNode> node)
|
||||
{
|
||||
if (!node) return;
|
||||
|
||||
if (node->IsType<VariableNode>()) {
|
||||
auto* varNode = node->GetAs<VariableNode>();
|
||||
std::string varName = varNode->GetVariableName();
|
||||
/*
|
||||
std::string varName = varNode->GetN();
|
||||
if (m_variableAddresses.find(varName) == m_variableAddresses.end()) {
|
||||
m_variableAddresses[varName] = varName;
|
||||
m_assembly << varName << ":\n" << varNode->GenerateAssembly();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Traverse children
|
||||
|
|
|
|||
|
|
@ -21,38 +21,30 @@ public:
|
|||
if (m_context.debugOutput) {
|
||||
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
||||
}
|
||||
// Node label
|
||||
m_assembly << node->node->GetMyEntryLabel() << ":\n";
|
||||
|
||||
if (isDataPath)
|
||||
{
|
||||
|
||||
if (node->IsType<OperatorNode>()) {
|
||||
GenerateOperatorNode(node);
|
||||
}
|
||||
else if (node->IsType<VariableNode>()) {
|
||||
GenerateVariableNode(node);
|
||||
}
|
||||
if (node->IsType<OperatorNode>()) {
|
||||
GenerateOperatorNode(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->IsType<FunctionEntryNode>()) {
|
||||
GenerateFunctionEntry(node);
|
||||
}
|
||||
else if (node->IsType<BranchNode>()) {
|
||||
GenerateBranchNode(node);
|
||||
}
|
||||
else if (node->IsType<PrintNode>()) {
|
||||
GeneratePrintNode(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// // 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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +52,6 @@ public:
|
|||
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void GenerateExit() {
|
||||
AddComment("Program exit");
|
||||
m_assembly << " halt\n";
|
||||
|
|
@ -71,55 +61,22 @@ 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() + ")");
|
||||
|
||||
auto trueBranch = node->GetChild(0);
|
||||
auto falseBranch = node->GetChild(1);
|
||||
|
||||
// Compare result and jump
|
||||
m_assembly << " pop eax\n"
|
||||
<< " cmp eax, 0\n"
|
||||
<< " je " << labelFalse << "\n";
|
||||
m_assembly << " pop r0\n"
|
||||
<< " skipz r0\n"
|
||||
<< " jump " << trueBranch->node->GetMyEntryLabel() << "\n"
|
||||
<< " jump " << falseBranch->node->GetMyEntryLabel() << "\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--;
|
||||
}
|
||||
|
||||
|
|
@ -127,15 +84,19 @@ private:
|
|||
auto* printNode = node->GetAs<PrintNode>();
|
||||
if (!printNode) return;
|
||||
|
||||
std::string text = printNode->GetText();
|
||||
std::string label = AddStringLiteral(text);
|
||||
std::string label = printNode->GetLabel();
|
||||
|
||||
|
||||
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) {
|
||||
|
|
@ -145,44 +106,123 @@ private:
|
|||
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 code for variables usage
|
||||
int reg = 0;
|
||||
for (const auto& [port, inputNode] : node->dataInputs)
|
||||
{
|
||||
// Check if the input node is a variable
|
||||
if (inputNode->IsType<VariableNode>())
|
||||
{
|
||||
auto* varNode = inputNode->GetAs<VariableNode>();
|
||||
if (varNode) {
|
||||
auto var = varNode->GetVariable();
|
||||
// Generate code to load the variable value
|
||||
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
||||
m_assembly << " push r" << reg << "\n";
|
||||
// Assuming we have a function to load the variable value
|
||||
// m_assembly << " load r0, " << varNode->GetVariableName() << "\n";
|
||||
}
|
||||
reg++;
|
||||
}
|
||||
|
||||
|
||||
// m_assembly << " load r0, " << inputNode.node->GetId() << "\n";
|
||||
}
|
||||
|
||||
|
||||
// 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";
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " add r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::SUBTRACT:
|
||||
m_assembly << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " sub eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " sub r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::MULTIPLY:
|
||||
m_assembly << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " imul eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " mul r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::DIVIDE:
|
||||
m_assembly << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " cdq\n"
|
||||
<< " idiv ebx\n"
|
||||
<< " push eax\n";
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " div r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::AND:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " and r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::GREATER_THAN:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " gt r0, r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
default:
|
||||
// Make voluntary bad assembly
|
||||
m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n";
|
||||
break;
|
||||
// Add other operators...
|
||||
}
|
||||
|
||||
m_depth--;
|
||||
}
|
||||
|
||||
virtual void Visit(const std::shared_ptr<Variable> v) override
|
||||
{
|
||||
if (v->IsConstant())
|
||||
{
|
||||
if (v->GetValueType() == Variable::ValueType::STRING)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DC8, \"" << v->GetValue<std::string>() << "\" ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::INTEGER)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DC32, " << v->GetValue<int>() << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::FLOAT)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DC32, " << v->GetValue<float>() << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::BOOL)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DCB, " << (v->GetValue<bool>() ? "1" : "0") << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void GenerateVariable(const std::shared_ptr<Variable> v)
|
||||
{
|
||||
if (v->GetValueType() == Variable::ValueType::STRING)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DV8, \"" << v->GetValue<std::string>() << "\" ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::INTEGER)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DV32, " << v->GetValue<int>() << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::FLOAT)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DV32, " << v->GetValue<float>() << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
else if (v->GetValueType() == Variable::ValueType::BOOL)
|
||||
{
|
||||
m_assembly << "$" << v->GetLabel() << " DVB, " << (v->GetValue<bool>() ? "1" : "0") << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
}
|
||||
/*
|
||||
void GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* varNode = node->GetAs<VariableNode>();
|
||||
if (!varNode) return;
|
||||
|
|
@ -193,7 +233,7 @@ private:
|
|||
m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n"
|
||||
<< " push eax\n";
|
||||
}
|
||||
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,14 @@ public:
|
|||
return dynamic_cast<T*>(node.get());
|
||||
}
|
||||
|
||||
std::string GetId() const {
|
||||
return node->GetId();
|
||||
}
|
||||
|
||||
int GetWeight() const {
|
||||
return node->GetWeight();
|
||||
}
|
||||
|
||||
// Debug information
|
||||
std::string GetDebugString() const {
|
||||
std::string result = "Node: " + node->GetTypeName() + " (ID: " + node->GetId() + ")\n";
|
||||
|
|
@ -136,12 +144,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct PathTree {
|
||||
std::shared_ptr<ASTNode> root;
|
||||
std::shared_ptr<ASTNode> lastNode; // Dernier nœud du PathTree
|
||||
std::vector<std::shared_ptr<Connection>> connections;
|
||||
bool isExecutionPath; // true for main flow, false for input paths
|
||||
};
|
||||
|
||||
class ASTBuilder {
|
||||
public:
|
||||
|
|
@ -150,88 +152,161 @@ public:
|
|||
const std::vector<std::shared_ptr<Connection>>& 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;
|
||||
std::unordered_map<std::string, std::shared_ptr<ASTNode>> nodeMap;
|
||||
for (const auto& node : m_nodes) {
|
||||
nodeMap[node->GetId()] = node;
|
||||
nodeMap[node->GetId()] = std::make_shared<ASTNode>(node);
|
||||
}
|
||||
|
||||
// Find all root nodes (nodes without incoming execution connections)
|
||||
std::unordered_set<std::string> hasIncomingExec;
|
||||
std::unordered_set<std::string> hasIncomingData;
|
||||
|
||||
// Build adjacency list for the nodes from the connections
|
||||
for (const auto& conn : m_connections) {
|
||||
if (conn->type == Connection::EXECUTION_LINKJ) {
|
||||
hasIncomingExec.insert(conn->inNodeId);
|
||||
} else {
|
||||
hasIncomingData.insert(conn->inNodeId);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Collect root nodes
|
||||
std::vector<std::shared_ptr<BaseNode>> execRoots;
|
||||
std::vector<std::shared_ptr<BaseNode>> dataRoots;
|
||||
std::vector<std::shared_ptr<ASTNode>> topologicalOrder = ApplyKahnAlgorithm(nodeMap);
|
||||
|
||||
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))
|
||||
// Maintenant, on va ajouter les connexions de données
|
||||
for (const auto& conn : m_connections)
|
||||
{
|
||||
auto outNode = nodeMap[conn->outNodeId];
|
||||
auto inNode = nodeMap[conn->inNodeId];
|
||||
|
||||
// Keep variables nodes as data inputs
|
||||
if (dynamic_cast<VariableNode*>(outNode->node.get()))
|
||||
{
|
||||
// Check if the node has any outgoing data connections
|
||||
bool hasDataOutput = false;
|
||||
for (const auto& conn : m_connections)
|
||||
{
|
||||
if (conn->type == Connection::DATA_LINK &&
|
||||
conn->outNodeId == node->GetId()) {
|
||||
hasDataOutput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDataOutput && !(dynamic_cast<VariableNode*>(node.get())))
|
||||
{
|
||||
dataRoots.push_back(node);
|
||||
}
|
||||
|
||||
// if (hasDataOutput) {
|
||||
// dataRoots.push_back(node);
|
||||
// }
|
||||
inNode->AddDataInput(conn->inPortIndex, outNode);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PathTree> pathTrees;
|
||||
// Build execution paths
|
||||
BuildExecutionPath(topologicalOrder, nodeMap);
|
||||
|
||||
// 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);
|
||||
}
|
||||
return topologicalOrder;
|
||||
|
||||
// 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:
|
||||
const std::vector<std::shared_ptr<BaseNode>>& m_nodes;
|
||||
const std::vector<std::shared_ptr<Connection>>& m_connections;
|
||||
|
||||
void BuildExecutionPath(std::vector<std::shared_ptr<ASTNode>>& tree,
|
||||
const std::unordered_map<std::string, std::shared_ptr<ASTNode>>& nodeMap)
|
||||
{
|
||||
std::queue<std::shared_ptr<ASTNode>> queue;
|
||||
queue.push(tree.front());
|
||||
|
||||
while (!queue.empty()) {
|
||||
auto current = queue.front();
|
||||
queue.pop();
|
||||
|
||||
// Find execution connections from this node
|
||||
for (const auto& conn : m_connections)
|
||||
{
|
||||
if (conn->outNodeId == current->node->GetId())
|
||||
{
|
||||
auto targetNode = nodeMap.find(conn->inNodeId);
|
||||
if (targetNode != nodeMap.end())
|
||||
{
|
||||
auto childNode = targetNode->second;
|
||||
current->children.push_back(childNode);
|
||||
queue.push(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
@ -246,97 +321,9 @@ 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
|
||||
for (const auto& astNode : m_ast.nodeMap) {
|
||||
assemblyCode << astNode.second->node->GenerateConstants();
|
||||
}
|
||||
// // Generate all constants
|
||||
// for (const auto& astNode : m_ast.nodeMap) {
|
||||
// assemblyCode << astNode.second->node->GenerateConstants();
|
||||
// }
|
||||
|
||||
// After the constants, the main entry point:
|
||||
assemblyCode << ".main:\n";
|
||||
|
|
|
|||
|
|
@ -62,6 +62,13 @@ protected:
|
|||
}
|
||||
|
||||
|
||||
virtual void Visit(const std::shared_ptr<Variable> v) {
|
||||
|
||||
}
|
||||
|
||||
virtual void GenerateVariable(const std::shared_ptr<Variable> v) {
|
||||
|
||||
}
|
||||
|
||||
virtual void GenerateExit() {
|
||||
|
||||
|
|
@ -84,7 +91,7 @@ protected:
|
|||
m_depth++;
|
||||
// Get condition value
|
||||
auto conditionNode = node->GetDataInput(0);
|
||||
int conditionValue = EvaluateCondition(conditionNode);
|
||||
int conditionValue = 0;
|
||||
|
||||
FlowVisualizer::PrintBranchDecision(conditionValue > 7,
|
||||
std::to_string(conditionValue), m_depth);
|
||||
|
|
@ -105,18 +112,16 @@ protected:
|
|||
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);
|
||||
FlowVisualizer::PrintDataFlow("Operand 1", opNode->GetOperatorSymbol(),
|
||||
std::to_string(0), m_depth);
|
||||
FlowVisualizer::PrintDataFlow("Operand 2", opNode->GetOperatorSymbol(),
|
||||
std::to_string(0), m_depth);
|
||||
|
||||
int result = value1 + value2;
|
||||
FlowVisualizer::PrintDataFlow("ADD", "Result",
|
||||
std::to_string(result), m_depth);
|
||||
|
||||
FlowVisualizer::PrintDataFlow(opNode->GetOperatorSymbol(), "Result",
|
||||
std::to_string(0), m_depth);
|
||||
|
||||
for (const auto& [port, outputs] : node->dataOutputs) {
|
||||
for (const auto& target : outputs) {
|
||||
|
|
@ -148,24 +153,4 @@ protected:
|
|||
private:
|
||||
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 "connection.h"
|
||||
#include "sys_lib.h"
|
||||
#include "compiler.h"
|
||||
|
||||
static std::string ChoiceLabel(const std::string &id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ public:
|
|||
MediaNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
|
||||
void SetImage(const std::string &image);
|
||||
std::string_view GetImage() const;
|
||||
|
|
|
|||
|
|
@ -19,44 +19,6 @@ BaseNode::~BaseNode()
|
|||
std::cout << "Deleted base node" << std::endl;
|
||||
}
|
||||
|
||||
std::string BaseNode::GenerateRandomString(size_t length, uint32_t flags)
|
||||
{
|
||||
std::string charset = "";
|
||||
|
||||
if (flags & CHARSET_ALPHABET_LOWER)
|
||||
{
|
||||
charset += "abcdefghijklmnopqrstuvwxyz";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_ALPHABET_UPPER)
|
||||
{
|
||||
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_NUMBERS)
|
||||
{
|
||||
charset += "0123456789";
|
||||
}
|
||||
|
||||
if (flags & CHARSET_SIGNS)
|
||||
{
|
||||
charset += "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||||
}
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 generator(rd());
|
||||
std::uniform_int_distribution<> distribution(0, charset.size() - 1);
|
||||
|
||||
std::string result;
|
||||
result.reserve(length);
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
result += charset[distribution(generator)];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string BaseNode::GetEntryLabel(const std::string &id)
|
||||
{
|
||||
|
|
@ -128,3 +90,13 @@ float BaseNode::GetY() const
|
|||
{
|
||||
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_project.h"
|
||||
#include "story_options.h"
|
||||
#include "variable.h"
|
||||
|
||||
class IVariableVisitor {
|
||||
|
||||
public:
|
||||
virtual void Visit(const std::shared_ptr<Variable> v) = 0;
|
||||
|
||||
};
|
||||
|
||||
class BaseNode
|
||||
{
|
||||
|
|
@ -36,14 +44,6 @@ public:
|
|||
float y;
|
||||
};
|
||||
|
||||
enum RandomFlags
|
||||
{
|
||||
CHARSET_ALPHABET_LOWER = 0x1, // "abcdefghijklmnopqrstuvwxyz"
|
||||
CHARSET_ALPHABET_UPPER = 0x2, // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
CHARSET_NUMBERS = 0x4, // "0123456789"
|
||||
CHARSET_SIGNS = 0x8, // "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||||
ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS
|
||||
};
|
||||
|
||||
struct ConstantValue
|
||||
{
|
||||
|
|
@ -69,11 +69,6 @@ public:
|
|||
static std::string GetEntryLabel(const std::string &id);
|
||||
|
||||
virtual void Initialize() = 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);
|
||||
|
||||
|
|
@ -97,6 +92,15 @@ public:
|
|||
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; }
|
||||
std::string GetId() const { return m_uuid; }
|
||||
|
||||
|
|
@ -110,8 +114,6 @@ public:
|
|||
void SetInternalData(const nlohmann::json &j);
|
||||
nlohmann::json GetInternalData() const;
|
||||
|
||||
static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS);
|
||||
|
||||
void ClearPorts() {
|
||||
m_inputPorts.clear();
|
||||
m_outputPorts.clear();
|
||||
|
|
@ -134,12 +136,21 @@ public:
|
|||
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:
|
||||
std::string m_title{"Default title"};
|
||||
std::string m_type;
|
||||
std::string m_typeName;
|
||||
std::string m_uuid;
|
||||
NodePosition m_pos;
|
||||
int m_weight{0};
|
||||
Behavior m_behavior{BEHAVIOR_EXECUTION};
|
||||
|
||||
std::vector<Port> m_inputPorts;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "story_project.h"
|
||||
#include "connection.h"
|
||||
#include "sys_lib.h"
|
||||
#include "compiler.h"
|
||||
|
||||
|
||||
BranchNode::BranchNode(const std::string &type)
|
||||
|
|
@ -17,37 +16,3 @@ 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::stringstream ss;
|
||||
|
||||
std::list<std::shared_ptr<Connection>> conns;
|
||||
page.GetNodeConnections(conns, GetId());
|
||||
int i = 0;
|
||||
std::list<std::shared_ptr<Connection>>::iterator c = conns.begin();
|
||||
|
||||
if (conns.size() == 2)
|
||||
{
|
||||
ss << R"(; ---------------------------- )"
|
||||
<< GetTitle()
|
||||
<< " Type: Branch"
|
||||
<< "\n";
|
||||
|
||||
ss << "eq r0, r0, r1\n"
|
||||
<< "skipz r0\n"
|
||||
<< "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
|
||||
++c;
|
||||
ss << "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,6 @@ public:
|
|||
BranchNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
virtual std::string GenerateAssembly() const { return ""; }
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "story_project.h"
|
||||
#include "connection.h"
|
||||
#include "sys_lib.h"
|
||||
#include "compiler.h"
|
||||
|
||||
|
||||
CompareNode::CompareNode(const std::string &type)
|
||||
|
|
@ -17,63 +16,3 @@ 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::stringstream ss;
|
||||
|
||||
std::list<std::shared_ptr<Connection>> conns;
|
||||
page.GetNodeConnections(conns, GetId());
|
||||
int i = 0;
|
||||
std::list<std::shared_ptr<Connection>>::iterator c = conns.begin();
|
||||
|
||||
/*
|
||||
|
||||
; Déclaration des variables en RAM
|
||||
$var1 DV32 1 ; Première variable à comparer
|
||||
$var2 DV32 1 ; Deuxième variable à comparer
|
||||
|
||||
; Code principal
|
||||
.compare_ge:
|
||||
; Charger les valeurs des variables dans les registres
|
||||
lcons r1, $var1
|
||||
load r1, @r1, 4 ; Charger 4 bytes (32 bits) de var1 dans r1
|
||||
lcons r2, $var2
|
||||
load r2, @r2, 4 ; Charger 4 bytes (32 bits) de var2 dans r2
|
||||
|
||||
; Comparer r1 >= r2
|
||||
gt r3, r1, r2 ; r3 = 1 si r1 > r2, sinon 0
|
||||
eq r4, r1, r2 ; r4 = 1 si r1 == r2, sinon 0
|
||||
or r0, r3, r4 ; r0 = 1 si r1 > r2 OU r1 == r2, sinon 0
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
if (conns.size() == 2)
|
||||
{
|
||||
ss << R"(; ---------------------------- )"
|
||||
<< GetTitle()
|
||||
<< " Type: Branch"
|
||||
<< "\n";
|
||||
|
||||
ss << "eq r0, r0, r1\n"
|
||||
<< "skipz r0\n"
|
||||
<< "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
|
||||
++c;
|
||||
ss << "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ public:
|
|||
CompareNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
|
||||
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
|
||||
|
||||
#include "execution_node.h"
|
||||
#include "base_node.h"
|
||||
|
||||
|
||||
class FunctionEntryNode : public ExecutionNode
|
||||
class FunctionEntryNode : public BaseNode
|
||||
{
|
||||
public:
|
||||
FunctionEntryNode(const std::string &type)
|
||||
: ExecutionNode(type, "Function Entry Node") {}
|
||||
: BaseNode(type, "Function Entry Node")
|
||||
{
|
||||
SetWeight(100);
|
||||
}
|
||||
|
||||
void Initialize() override {
|
||||
// Initialisation spécifique pour FunctionEntryNode
|
||||
|
|
@ -19,11 +22,6 @@ public:
|
|||
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
|
||||
void PrepareFunctionEntry() {
|
||||
// Logique pour préparer l'entrée de la fonction
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@ public:
|
|||
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
|
||||
void FinalizeFunctionExit() {
|
||||
// Logique pour finaliser la sortie de la fonction
|
||||
|
|
|
|||
|
|
@ -27,17 +27,3 @@ void FunctionNode::Initialize()
|
|||
// m_sound = j["sound"].get<std::string>();
|
||||
}
|
||||
|
||||
std::string FunctionNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string FunctionNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ public:
|
|||
FunctionNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
void StoreInternalData();
|
||||
|
||||
|
|
|
|||
|
|
@ -105,56 +105,6 @@ public:
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string GenerateConstants(IStoryPage& page, IStoryProject& project, int nb_out_conns) override {
|
||||
return ""; // Operators don't generate constants
|
||||
}
|
||||
|
||||
std::string GenerateAssembly() const override {
|
||||
std::stringstream ss;
|
||||
|
||||
switch (m_operationType) {
|
||||
case OperationType::ADD:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " add eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
break;
|
||||
case OperationType::SUBTRACT:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " sub eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
break;
|
||||
case OperationType::MULTIPLY:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " imul eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
break;
|
||||
case OperationType::DIVIDE:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " cdq\n" // Sign extend eax into edx
|
||||
<< " idiv ebx\n"
|
||||
<< " push eax\n"; // Push quotient
|
||||
break;
|
||||
case OperationType::AND:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " and eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
break;
|
||||
case OperationType::OR:
|
||||
ss << " pop ebx\n"
|
||||
<< " pop eax\n"
|
||||
<< " or eax, ebx\n"
|
||||
<< " push eax\n";
|
||||
break;
|
||||
// Add other operators...
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
OperationType m_operationType;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
#include "story_project.h"
|
||||
#include "connection.h"
|
||||
#include "sys_lib.h"
|
||||
#include "compiler.h"
|
||||
|
||||
#include "variable.h"
|
||||
|
||||
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?
|
||||
// Create empty variable in memory
|
||||
auto v = std::make_shared<Variable>(m_label);
|
||||
v->SetTextValue("");
|
||||
m_label = v->GetLabel();
|
||||
m_variables[m_label] = v;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -17,41 +20,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)
|
||||
{
|
||||
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 "i_story_manager.h"
|
||||
#include "execution_node.h"
|
||||
#include "base_node.h"
|
||||
#include "i_script_node.h"
|
||||
#include "i_story_project.h"
|
||||
|
||||
class PrintNode : public ExecutionNode
|
||||
class PrintNode : public BaseNode
|
||||
{
|
||||
public:
|
||||
PrintNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
virtual std::string GenerateConstants() const override;
|
||||
|
||||
std::string GenerateAssembly() const override;
|
||||
|
||||
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 {
|
||||
return m_text;
|
||||
return m_variables.at(m_label)->GetValue<std::string>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_label;
|
||||
std::string m_text; // Text to print
|
||||
std::string m_label; // Label for the string literal
|
||||
uint32_t m_arguments{0}; // number of arguments
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,17 +27,5 @@ void VariableNode::Initialize()
|
|||
// m_sound = j["sound"].get<std::string>();
|
||||
}
|
||||
|
||||
std::string VariableNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
|
||||
{
|
||||
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
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "variable.h"
|
||||
#include "i_story_manager.h"
|
||||
#include "base_node.h"
|
||||
#include "i_script_node.h"
|
||||
|
|
@ -12,92 +12,22 @@ class VariableNode : public BaseNode
|
|||
{
|
||||
public:
|
||||
|
||||
enum class ValueType {
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
BOOL,
|
||||
STRING
|
||||
};
|
||||
|
||||
using VariableValue = std::variant<int, float, bool, std::string>;
|
||||
|
||||
VariableNode(const std::string &type = "variable-node");
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
|
||||
|
||||
virtual std::string GenerateAssembly() const { return ""; }
|
||||
|
||||
void StoreInternalData();
|
||||
|
||||
|
||||
// Setters
|
||||
void SetVariableName(const std::string& name) {
|
||||
m_variableName = name;
|
||||
void SetVariable(const std::shared_ptr<Variable> v) {
|
||||
m_variable = v;
|
||||
}
|
||||
|
||||
void SetConstant(bool isConstant) {
|
||||
m_isConstant = isConstant;
|
||||
std::shared_ptr<Variable> GetVariable() const {
|
||||
return m_variable;
|
||||
}
|
||||
|
||||
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:
|
||||
std::string m_variableName;
|
||||
ValueType m_valueType;
|
||||
VariableValue m_value;
|
||||
bool m_isConstant;
|
||||
std::shared_ptr<Variable> m_variable;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,16 +52,16 @@ public:
|
|||
|
||||
void Build(std::stringstream &code, IStoryProject &project)
|
||||
{
|
||||
// First generate all constants
|
||||
for (const auto & n : m_nodes)
|
||||
{
|
||||
code << n->GenerateConstants(*this, project, OutputsCount(n->GetId())) << "\n";
|
||||
}
|
||||
// // First generate all constants
|
||||
// for (const auto & n : m_nodes)
|
||||
// {
|
||||
// code << n->GenerateConstants(*this, project, OutputsCount(n->GetId())) << "\n";
|
||||
// }
|
||||
|
||||
for (const auto & n : m_nodes)
|
||||
{
|
||||
code << n->Build(*this, project.GetOptions(), OutputsCount(n->GetId())) << "\n";
|
||||
}
|
||||
// for (const auto & n : m_nodes)
|
||||
// {
|
||||
// code << n->Build(*this, project.GetOptions(), OutputsCount(n->GetId())) << "\n";
|
||||
// }
|
||||
}
|
||||
|
||||
virtual void GetNodeConnections(std::list<std::shared_ptr<Connection>> &c, const std::string &nodeId) override
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "story_project.h"
|
||||
#include "json.hpp"
|
||||
#include "media_node.h"
|
||||
// #include "media_node.h"
|
||||
#include "function_node.h"
|
||||
#include "variable_node.h"
|
||||
#include "sys_lib.h"
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
StoryProject::StoryProject(ILogger &log)
|
||||
: m_log(log)
|
||||
{
|
||||
registerNode<MediaNode>("media-node");
|
||||
// registerNode<MediaNode>("media-node");
|
||||
registerNode<FunctionNode>("function-node");
|
||||
registerNode<VariableNode>("variable-node");
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ std::pair<std::list<std::shared_ptr<Connection>>::iterator, std::list<std::share
|
|||
return std::pair<std::list<std::shared_ptr<Connection>>::iterator, std::list<std::shared_ptr<Connection>>::iterator>();
|
||||
}
|
||||
|
||||
void StoryProject::ScanVariable(const std::function<void(Variable& element)>& operation)
|
||||
void StoryProject::ScanVariable(const std::function<void(std::shared_ptr<Variable> element)>& operation)
|
||||
{
|
||||
for (auto &v : m_variables)
|
||||
{
|
||||
|
|
@ -233,7 +233,13 @@ void StoryProject::ScanVariable(const std::function<void(Variable& element)>& op
|
|||
|
||||
void StoryProject::AddVariable()
|
||||
{
|
||||
m_variables.push_back(Variable("var_" + std::to_string(m_variables.size()), "int32_t", 0, 8));
|
||||
auto v = std::make_shared<Variable>("var_" + std::to_string(m_variables.size()));
|
||||
|
||||
v->SetValue(0);
|
||||
v->SetValueType(Variable::ValueType::INTEGER);
|
||||
v->SetConstant(false);
|
||||
|
||||
m_variables.push_back(v);
|
||||
}
|
||||
|
||||
void StoryProject::DeleteVariable(int i)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public:
|
|||
std::pair<std::list<std::shared_ptr<Connection>>::iterator, std::list<std::shared_ptr<Connection>>::iterator> Links(const std::string_view &page_uuid);
|
||||
|
||||
|
||||
void ScanVariable(const std::function<void(Variable& element)>& operation);
|
||||
void ScanVariable(const std::function<void(std::shared_ptr<Variable> element)>& operation);
|
||||
void AddVariable();
|
||||
void DeleteVariable(int i);
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ private:
|
|||
|
||||
std::list<std::shared_ptr<StoryPage>> m_pages;
|
||||
|
||||
std::vector<Variable> m_variables;
|
||||
std::vector<std::shared_ptr<Variable>> m_variables;
|
||||
|
||||
StoryOptions m_storyOptions;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ THE SOFTWARE.
|
|||
#include "function_entry_node.h"
|
||||
#include "operator_node.h"
|
||||
#include "chip32_machine.h"
|
||||
#include "variable.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
|
@ -43,47 +44,7 @@ THE SOFTWARE.
|
|||
#include "assembly_generator.h"
|
||||
#include "flow_generator.h"
|
||||
#include "assembly_generator_chip32.h"
|
||||
/*
|
||||
void ProcessASTTree(const ASTBuilder::PathTree& tree, int depth = 0) {
|
||||
std::queue<std::pair<std::shared_ptr<ASTNode>, int>> queue;
|
||||
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" ) {
|
||||
|
||||
Compiler compiler;
|
||||
|
|
@ -97,21 +58,51 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
auto branchNode = std::make_shared<BranchNode>("branch-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");
|
||||
std::vector<std::shared_ptr<Variable>> variables;
|
||||
auto var1 = std::make_shared<Variable>("X");
|
||||
var1->SetValue(5);
|
||||
var1->SetValueType(Variable::ValueType::INTEGER);
|
||||
|
||||
auto variableNode2 = std::make_shared<VariableNode>("variable-node");
|
||||
variableNode2->SetValue(10);
|
||||
variableNode2->SetValueType(VariableNode::ValueType::INTEGER);
|
||||
variableNode2->SetVariableName("Y");
|
||||
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->SetVariable(var1);
|
||||
|
||||
auto variableNodeY = std::make_shared<VariableNode>("variable-node");
|
||||
variableNodeY->SetVariable(var2);
|
||||
|
||||
auto variableNodeA = std::make_shared<VariableNode>("variable-node");
|
||||
variableNodeA->SetVariable(var3);
|
||||
|
||||
auto variableNodeB = std::make_shared<VariableNode>("variable-node");
|
||||
variableNodeB->SetVariable(var4);
|
||||
|
||||
auto testNode = std::make_shared<OperatorNode>();
|
||||
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;
|
||||
|
||||
|
|
@ -119,9 +110,13 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
nodes.push_back(printNodeTrue);
|
||||
nodes.push_back(printNodeFalse);
|
||||
nodes.push_back(branchNode);
|
||||
nodes.push_back(variableNode1);
|
||||
nodes.push_back(variableNode2);
|
||||
nodes.push_back(variableNodeX);
|
||||
nodes.push_back(variableNodeY);
|
||||
nodes.push_back(variableNodeA);
|
||||
nodes.push_back(variableNodeB);
|
||||
nodes.push_back(testNode);
|
||||
nodes.push_back(addNode);
|
||||
nodes.push_back(subNode);
|
||||
|
||||
auto cn1 = 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 cn5 = 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;
|
||||
|
||||
|
|
@ -138,7 +137,10 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
connections.push_back(cn4);
|
||||
connections.push_back(cn5);
|
||||
connections.push_back(cn6);
|
||||
|
||||
connections.push_back(cn7);
|
||||
connections.push_back(cn8);
|
||||
connections.push_back(cn9);
|
||||
connections.push_back(cn10);
|
||||
|
||||
// Branch True -> print Ok
|
||||
// False -> print Ko
|
||||
|
|
@ -168,47 +170,47 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
cn4->outPortIndex = 0;
|
||||
cn4->type = Connection::DATA_LINK;
|
||||
|
||||
// Variable 1 -> Compare test node input 1
|
||||
// + output 1 -> Compare test node input 1
|
||||
cn5->inNodeId = testNode->GetId();
|
||||
cn5->inPortIndex = 0;
|
||||
cn5->outNodeId = variableNode1->GetId();
|
||||
cn5->outNodeId = addNode->GetId();
|
||||
cn5->outPortIndex = 0;
|
||||
cn5->type = Connection::DATA_LINK;
|
||||
|
||||
// Variable 1 -> Compare test node input 1
|
||||
// - output -> Compare test node input 1
|
||||
cn6->inNodeId = testNode->GetId();
|
||||
cn6->inPortIndex = 1;
|
||||
cn6->outNodeId = variableNode2->GetId();
|
||||
cn6->outNodeId = subNode->GetId();
|
||||
cn6->outPortIndex = 0;
|
||||
cn6->type = Connection::DATA_LINK;
|
||||
|
||||
// ADD NODE INPUTS
|
||||
|
||||
// // Création des nœuds
|
||||
// std::vector<Node> nodes = {
|
||||
// Node(Node::Type::VARIABLE, "i", "node_i"),
|
||||
// Node(Node::Type::CONSTANT, 10, "node_10"),
|
||||
// Node(Node::Type::SUBTRACT, "node_subtract"),
|
||||
// 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")
|
||||
// };
|
||||
cn7->inNodeId = addNode->GetId();
|
||||
cn7->inPortIndex = 0;
|
||||
cn7->outNodeId = variableNodeX->GetId();
|
||||
cn7->outPortIndex = 0;
|
||||
cn7->type = Connection::DATA_LINK;
|
||||
|
||||
// try
|
||||
// {
|
||||
// // Construction de l'AST
|
||||
// compiler.buildAST(nodes, connections);
|
||||
// compiler.printAST();
|
||||
cn8->inNodeId = addNode->GetId();
|
||||
cn8->inPortIndex = 1;
|
||||
cn8->outNodeId = variableNodeY->GetId();
|
||||
cn8->outPortIndex = 0;
|
||||
cn8->type = Connection::DATA_LINK;
|
||||
|
||||
// } catch(const std::exception &e)
|
||||
// {
|
||||
// std::cout << e.what() << std::endl;
|
||||
// }
|
||||
// SUBTRACT NODE INPUTS
|
||||
|
||||
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
|
||||
|
|
@ -225,40 +227,24 @@ TEST_CASE( "Check various indentations and typos" ) {
|
|||
|
||||
|
||||
ASTBuilder builder(nodes, connections);
|
||||
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;
|
||||
}
|
||||
*/
|
||||
auto pathTree = builder.BuildAST();
|
||||
|
||||
// Generate flow in the console
|
||||
VisualFlowGenerator flowGenerator(context);
|
||||
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
|
||||
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTrees);
|
||||
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTree, variables);
|
||||
|
||||
|
||||
std::cout << "\nGenerated flow:\n" << flow << std::endl;
|
||||
|
||||
// Generate assembly
|
||||
std::string assembly = generator.GenerateAssembly(nodes, pathTrees);
|
||||
std::string assembly = generator.GenerateAssembly(nodes, pathTree, variables);
|
||||
|
||||
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
|
||||
|
||||
// compiler.generateAssembly();
|
||||
Chip32::Machine machine;
|
||||
|
||||
// std::cout << compiler.GetCode() << std::endl;
|
||||
machine.QuickExecute(assembly);
|
||||
|
||||
|
||||
// Chip32::Machine machine;
|
||||
|
||||
// machine.QuickExecute(compiler.GetCode());
|
||||
|
||||
// REQUIRE( parseResult == true );
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ set(SRCS
|
|||
src/windows/cpu_window.cpp
|
||||
src/windows/variables_window.cpp
|
||||
|
||||
src/node_editor/media_node_widget.cpp
|
||||
# src/node_editor/media_node_widget.cpp
|
||||
src/node_editor/base_node_widget.cpp
|
||||
src/node_editor/node_editor_window.cpp
|
||||
src/node_editor/function_node_widget.cpp
|
||||
|
|
@ -168,16 +168,17 @@ set(SRCS
|
|||
|
||||
|
||||
# Core engine files
|
||||
../core/story-manager/src/compiler.cpp
|
||||
../core/story-manager/src/story_project.cpp
|
||||
../core/story-manager/src/story_page.cpp
|
||||
../core/story-manager/src/base_node.cpp
|
||||
../core/story-manager/src/media_node.cpp
|
||||
../core/story-manager/src/compare_node.cpp
|
||||
../core/story-manager/src/branch_node.cpp
|
||||
../core/story-manager/src/variable_node.cpp
|
||||
../core/story-manager/src/function_node.cpp
|
||||
../core/story-manager/src/connection.cpp
|
||||
|
||||
|
||||
../core/story-manager/src/nodes/base_node.cpp
|
||||
../core/story-manager/src/nodes/compare_node.cpp
|
||||
../core/story-manager/src/nodes/branch_node.cpp
|
||||
../core/story-manager/src/nodes/variable_node.cpp
|
||||
../core/story-manager/src/nodes/function_node.cpp
|
||||
../core/story-manager/src/nodes/connection.cpp
|
||||
|
||||
../core/story-manager/lib/sys_lib.cpp
|
||||
../core/story-manager/lib/resource.cpp
|
||||
|
||||
|
|
@ -222,6 +223,8 @@ target_include_directories(${STORY_EDITOR_PROJECT} PUBLIC
|
|||
../core/chip32
|
||||
../shared
|
||||
../core/story-manager/src
|
||||
../core/story-manager/src/nodes
|
||||
../core/story-manager/src/compiler
|
||||
../core/story-manager/lib
|
||||
../core/story-manager/interfaces
|
||||
)
|
||||
|
|
|
|||
105
story-editor/imgui.ini
Normal file
105
story-editor/imgui.ini
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
[Window][WindowOverViewport_11111111]
|
||||
Pos=60,26
|
||||
Size=1220,694
|
||||
Collapsed=0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Library Manager]
|
||||
Pos=672,26
|
||||
Size=608,694
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=386,659
|
||||
Size=1152,344
|
||||
Collapsed=0
|
||||
|
||||
[Window][Emulator]
|
||||
Pos=269,26
|
||||
Size=401,694
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
[Window][Code viewer]
|
||||
Pos=269,26
|
||||
Size=401,694
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Resources]
|
||||
Pos=672,26
|
||||
Size=608,694
|
||||
Collapsed=0
|
||||
DockId=0x00000002,1
|
||||
|
||||
[Window][Node editor]
|
||||
Pos=96,129
|
||||
Size=394,407
|
||||
Collapsed=0
|
||||
|
||||
[Window][TOOLBAR]
|
||||
Pos=96,105
|
||||
Size=79,42
|
||||
Collapsed=0
|
||||
|
||||
[Window][Variables]
|
||||
Pos=199,187
|
||||
Size=121,72
|
||||
Collapsed=0
|
||||
|
||||
[Window][CPU]
|
||||
Pos=515,59
|
||||
Size=626,744
|
||||
Collapsed=0
|
||||
|
||||
[Window][RAM view]
|
||||
Pos=378,79
|
||||
Size=738,442
|
||||
Collapsed=0
|
||||
|
||||
[Window][Properties]
|
||||
Pos=754,344
|
||||
Size=626,744
|
||||
Collapsed=0
|
||||
|
||||
[Window][ToolBar]
|
||||
Pos=0,26
|
||||
Size=60,694
|
||||
Collapsed=0
|
||||
|
||||
[Window][QuitConfirm]
|
||||
Pos=479,312
|
||||
Size=321,96
|
||||
Collapsed=0
|
||||
|
||||
[Table][0x7728942D,5]
|
||||
RefScale=20
|
||||
Column 0 Width=44 Sort=0v
|
||||
Column 1 Width=72
|
||||
Column 2 Width=104
|
||||
Column 3 Width=54
|
||||
Column 4 Width=75
|
||||
|
||||
[Table][0x69D69F59,2]
|
||||
RefScale=20
|
||||
Column 0 Width=22 Sort=0v
|
||||
Column 1 Width=68
|
||||
|
||||
[Table][0x30BF8F98,3]
|
||||
RefScale=20
|
||||
Column 0 Width=259 Sort=0v
|
||||
Column 1 Width=88
|
||||
Column 2 Width=124
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=610,694 Split=X
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=397,600 CentralNode=1 Selected=0x63869CAF
|
||||
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=401,600 Selected=0x4B07C626
|
||||
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=608,694 Selected=0x30401527
|
||||
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#include "i_story_project.h"
|
||||
#include "gui.h"
|
||||
#include <imgui_node_editor.h>
|
||||
#include "media_node.h"
|
||||
|
||||
|
||||
class FunctionNodeWidget : public BaseNodeWidget
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ NodeEditorWindow::NodeEditorWindow(IStoryManager &manager)
|
|||
, m_manager(manager)
|
||||
{
|
||||
|
||||
registerNode<MediaNodeWidget>("media-node");
|
||||
// registerNode<MediaNodeWidget>("media-node");
|
||||
registerNode<FunctionNodeWidget>("function-node");
|
||||
registerNode<VariableNodeWidget>("variable-node");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,16 @@ void VariableNodeWidget::DrawProperties()
|
|||
if (ImGui::BeginCombo("Variables list", m_selectedVariable.c_str(), flags))
|
||||
{
|
||||
int i = 0;
|
||||
m_manager.ScanVariable([&i, this] (Variable &var) {
|
||||
m_manager.ScanVariable([&i, this] (std::shared_ptr<Variable> var) {
|
||||
|
||||
// ImGui::PushID(static_cast<int>(i)); // Assure l'unicité des widgets
|
||||
|
||||
const bool is_selected = (m_selectedIndex == i);
|
||||
if (ImGui::Selectable(var.name.c_str(), is_selected))
|
||||
std::string l = var->GetVariableName();
|
||||
if (ImGui::Selectable(l.c_str(), is_selected))
|
||||
{
|
||||
m_selectedIndex = i;
|
||||
m_selectedVariable = var.name;
|
||||
m_selectedVariable = l;
|
||||
}
|
||||
|
||||
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
|
||||
|
|
|
|||
|
|
@ -1096,7 +1096,7 @@ uint32_t MainWindow::GetRegister(int reg)
|
|||
return regVal;
|
||||
}
|
||||
|
||||
void MainWindow::ScanVariable(const std::function<void(Variable& element)>& operation)
|
||||
void MainWindow::ScanVariable(const std::function<void(std::shared_ptr<Variable> element)>& operation)
|
||||
{
|
||||
if (m_story)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ private:
|
|||
virtual uint32_t GetRegister(int reg) override;
|
||||
|
||||
// Variable
|
||||
virtual void ScanVariable(const std::function<void(Variable& element)>& operation) override;
|
||||
virtual void ScanVariable(const std::function<void(std::shared_ptr<Variable> element)>& operation) override;
|
||||
virtual void AddVariable() override;
|
||||
virtual void DeleteVariable(int i);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,47 +42,52 @@ void VariablesWindow::ShowRAMEditor()
|
|||
ImGui::Separator();
|
||||
int i = 0;
|
||||
|
||||
m_story.ScanVariable([&i, this] (Variable &var) {
|
||||
m_story.ScanVariable([&i, this] (std::shared_ptr<Variable> var) {
|
||||
|
||||
ImGui::PushID(static_cast<int>(i)); // Assure l'unicité des widgets
|
||||
if (ImGui::TreeNode((var.name + "###variable").c_str()))
|
||||
std::string l = var->GetVariableName();
|
||||
if (ImGui::TreeNode((l + "###variable").c_str()))
|
||||
{
|
||||
// Modifier le nom de la variable
|
||||
static char buffer[Variable::NameMaxSize];
|
||||
std::strncpy(buffer, var.name.c_str(), sizeof(buffer));
|
||||
std::strncpy(buffer, l.c_str(), sizeof(buffer));
|
||||
buffer[sizeof(buffer) - 1] = '\0'; // Assure la terminaison
|
||||
if (ImGui::InputText("Name", buffer, sizeof(buffer))) {
|
||||
var.name = buffer;
|
||||
var->SetVariableName(buffer);
|
||||
}
|
||||
|
||||
// Choisir le type de la variable
|
||||
const char* types[] = {"Integer", "String"};
|
||||
static int selectedType = (var.type == "Integer") ? 0 : 1;
|
||||
static int selectedType = var->IsInteger() ? 0 : 1; // 0 for Integer, 1 for String
|
||||
if (ImGui::Combo("Type", &selectedType, types, IM_ARRAYSIZE(types))) {
|
||||
var.type = types[selectedType];
|
||||
var->SetValueType(selectedType == 0 ? Variable::ValueType::INTEGER : Variable::ValueType::STRING);
|
||||
}
|
||||
|
||||
if (var.type == "Integer")
|
||||
if (var->IsInteger())
|
||||
{
|
||||
// Modifier l'échelle
|
||||
ImGui::InputInt("Scale Power (10^x)", &var.scalePower);
|
||||
int scalePower = var->GetScalePower();
|
||||
if (ImGui::InputInt("Scale Power (10^x)", &scalePower))
|
||||
{
|
||||
var->SetScalePower(scalePower);
|
||||
}
|
||||
|
||||
// Modifier la valeur entière
|
||||
int intValue = static_cast<int>(var.value);
|
||||
int intValue = static_cast<int>(var->GetIntegerValue());
|
||||
if (ImGui::InputInt("Integer Value", &intValue)) {
|
||||
var.value = static_cast<int64_t>(intValue);
|
||||
var->SetIntegerValue(static_cast<int64_t>(intValue));
|
||||
}
|
||||
|
||||
// Afficher la valeur flottante calculée
|
||||
float floatValue = ScaledToFloat(var.value, var.scalePower);
|
||||
float floatValue = ScaledToFloat(var->GetIntegerValue(), var->GetScalePower());
|
||||
ImGui::Text("Float Value: %.6f", floatValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::strncpy(buffer, var.valueText.c_str(), sizeof(buffer));
|
||||
std::strncpy(buffer, var->GetStringValue().c_str(), sizeof(buffer));
|
||||
if (ImGui::InputText("Text value", buffer, sizeof(buffer)))
|
||||
{
|
||||
var.valueText = buffer;
|
||||
var->SetTextValue(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue