First version of AST/flow/assembly generation base classes, arch seems ok

This commit is contained in:
anthony@rabine.fr 2025-04-09 10:32:26 +02:00
parent b9a946eab4
commit 183e5d0727
29 changed files with 1806 additions and 644 deletions

View file

@ -1,306 +0,0 @@
#include <iostream>
#include <vector>
#include <cctype>
#include <memory>
#include <fstream>
enum class TokenType {
FUNC, IDENTIFIER, INT, CONST, VAR, IF, ELSE, WHILE, NUMBER, ASSIGN, PLUS, MINUS, MULT, DIV, SEMICOLON,
LPAREN, RPAREN, LBRACE, RBRACE, END, GREATER, LESS, EQUAL, NOTEQUAL
};
struct Token {
TokenType type;
std::string value;
};
class Lexer {
public:
Lexer(const std::string& input) : input(input), pos(0) {}
std::vector<Token> tokenize() {
std::vector<Token> tokens;
while (pos < input.size()) {
if (std::isspace(input[pos])) {
++pos;
} else if (std::isalpha(input[pos])) {
std::string ident = readIdentifier();
if (ident == "func") {
tokens.push_back({TokenType::FUNC, ident});
} else if (ident == "int") {
tokens.push_back({TokenType::INT, ident});
} else if (ident == "const") {
tokens.push_back({TokenType::CONST, ident});
} else if (ident == "var") {
tokens.push_back({TokenType::VAR, ident});
} else if (ident == "if") {
tokens.push_back({TokenType::IF, ident});
} else if (ident == "else") {
tokens.push_back({TokenType::ELSE, ident});
} else if (ident == "while") {
tokens.push_back({TokenType::WHILE, ident});
} else {
tokens.push_back({TokenType::IDENTIFIER, ident});
}
} else if (std::isdigit(input[pos])) {
tokens.push_back({TokenType::NUMBER, readNumber()});
} else {
switch (input[pos]) {
case '(': tokens.push_back({TokenType::LPAREN, "("}); break;
case ')': tokens.push_back({TokenType::RPAREN, ")"}); break;
case '{': tokens.push_back({TokenType::LBRACE, "{"}); break;
case '}': tokens.push_back({TokenType::RBRACE, "}"}); break;
case '=': tokens.push_back({TokenType::ASSIGN, "="}); break;
case '+': tokens.push_back({TokenType::PLUS, "+"}); break;
case '-': tokens.push_back({TokenType::MINUS, "-"}); break;
case '*': tokens.push_back({TokenType::MULT, "*"}); break;
case '/': tokens.push_back({TokenType::DIV, "/"}); break;
case ';': tokens.push_back({TokenType::SEMICOLON, ";"}); break;
case '>': tokens.push_back({TokenType::GREATER, ">"}); break;
case '<': tokens.push_back({TokenType::LESS, "<"}); break;
default: std::cerr << "Caractère inattendu : " << input[pos] << std::endl;
}
++pos;
}
}
tokens.push_back({TokenType::END, ""});
return tokens;
}
private:
std::string input;
size_t pos;
std::string readIdentifier() {
size_t start = pos;
while (pos < input.size() && std::isalnum(input[pos])) ++pos;
return input.substr(start, pos - start);
}
std::string readNumber() {
size_t start = pos;
while (pos < input.size() && std::isdigit(input[pos])) ++pos;
return input.substr(start, pos - start);
}
};
// AST Nodes
struct ASTNode {
virtual ~ASTNode() = default;
virtual void print(int indent = 0) const = 0;
virtual void generateAssembly(std::ofstream& out) const = 0;
};
struct ExpressionNode : public ASTNode {
std::string value;
ExpressionNode(std::string value) : value(std::move(value)) {}
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "Number: " << value << std::endl;
}
void generateAssembly(std::ofstream& out) const override {
out << "\tmov eax, " << value << "\n";
}
};
struct BinaryOpNode : public ASTNode {
std::unique_ptr<ASTNode> left;
std::unique_ptr<ASTNode> right;
TokenType op;
BinaryOpNode(std::unique_ptr<ASTNode> left, TokenType op, std::unique_ptr<ASTNode> right)
: left(std::move(left)), op(op), right(std::move(right)) {}
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "BinaryOp: ";
left->print(indent + 2);
std::cout << std::string(indent + 2, ' ') << (op == TokenType::PLUS ? "+" :
op == TokenType::MINUS ? "-" :
op == TokenType::MULT ? "*" : "/") << std::endl;
right->print(indent + 2);
}
void generateAssembly(std::ofstream& out) const override {
left->generateAssembly(out);
out << "\tpush eax\n";
right->generateAssembly(out);
out << "\tpop ebx\n";
switch (op) {
case TokenType::PLUS: out << "\tadd eax, ebx\n"; break;
case TokenType::MINUS: out << "\tsub eax, ebx\n"; break;
case TokenType::MULT: out << "\timul eax, ebx\n"; break;
case TokenType::DIV: out << "\tcdq\n\tidiv ebx\n"; break;
default: break;
}
}
};
struct AssignmentNode : public ASTNode {
std::string varName;
std::unique_ptr<ASTNode> expression;
AssignmentNode(std::string varName, std::unique_ptr<ASTNode> expression)
: varName(std::move(varName)), expression(std::move(expression)) {}
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "Assignment: " << varName << " = " << std::endl;
expression->print(indent + 2);
}
void generateAssembly(std::ofstream& out) const override {
expression->generateAssembly(out);
out << "\tmov [" << varName << "], eax\n";
}
};
struct FunctionNode : public ASTNode {
std::string name;
std::vector<std::unique_ptr<ASTNode>> body;
FunctionNode(std::string name) : name(std::move(name)) {}
void print(int indent = 0) const override {
std::cout << "Function: " << name << std::endl;
for (const auto& stmt : body) {
stmt->print(indent + 2);
}
}
void generateAssembly(std::ofstream& out) const override {
out << "." << name << ":\n";
for (const auto& stmt : body) {
stmt->generateAssembly(out);
}
out << "\tret\n";
}
};
struct StatementNode : public ASTNode {
};
struct VariableDeclarationNode : public StatementNode {
std::string name;
std::unique_ptr<ExpressionNode> value;
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "VarDecl: " << name << std::endl;
}
void generateAssembly(std::ofstream& out) const override {}
};
struct IfNode : public StatementNode {
std::unique_ptr<ExpressionNode> condition;
std::vector<std::unique_ptr<ASTNode>> thenBranch;
std::vector<std::unique_ptr<ASTNode>> elseBranch;
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "If Statement" << std::endl;
}
void generateAssembly(std::ofstream& out) const override {}
};
struct WhileNode : public StatementNode {
std::unique_ptr<ExpressionNode> condition;
std::vector<std::unique_ptr<ASTNode>> body;
void print(int indent = 0) const override {
std::cout << std::string(indent, ' ') << "While Statement" << std::endl;
}
void generateAssembly(std::ofstream& out) const override {}
};
class Parser {
public:
Parser(const std::vector<Token>& tokens) : tokens(tokens), pos(0) {}
std::unique_ptr<ASTNode> parse() {
if (match(TokenType::FUNC)) {
consume(TokenType::FUNC);
std::string funcName = consume(TokenType::IDENTIFIER).value;
consume(TokenType::LPAREN);
consume(TokenType::RPAREN);
consume(TokenType::LBRACE);
std::vector<std::unique_ptr<StatementNode>> body;
while (!match(TokenType::RBRACE)) {
body.push_back(parseStatement());
}
consume(TokenType::RBRACE);
return std::make_unique<FunctionNode>(funcName);
}
return nullptr;
}
private:
const std::vector<Token>& tokens;
size_t pos;
bool match(TokenType type) {
return pos < tokens.size() && tokens[pos].type == type;
}
Token consume(TokenType type) {
if (match(type)) {
return tokens[pos++];
}
std::cout << "type: " << (int)type << std::endl;
throw std::runtime_error("Unexpected token: expected " + std::to_string(static_cast<int>(type)) +
", got " + std::to_string(static_cast<int>(tokens[pos].type)) +
" (" + tokens[pos].value + ")");
}
std::unique_ptr<StatementNode> parseStatement() { return nullptr; }
};
int main() {
std::string code = R"(
def MaFonction()
var x
x = 5 + 3
)";
Lexer lexer(code);
std::vector<Token> tokens = lexer.tokenize();
for (const auto& token : tokens) {
std::cout << "Token: " << static_cast<int>(token.type) << " (" << token.value << ")\n";
}
try {
Parser parser(tokens);
std::unique_ptr<ASTNode> ast = parser.parse();
if (ast) {
ast->print();
std::ofstream outFile("output.asm");
if (outFile.is_open()) {
ast->generateAssembly(outFile);
outFile.close();
std::cout << "Code assembleur généré dans output.asm" << std::endl;
} else {
std::cerr << "Erreur lors de l'ouverture du fichier" << std::endl;
}
} else {
std::cerr << "Erreur de parsing" << std::endl;
}
} catch(const std::exception &e) {
std::cerr << "Erreur de parsing: " << e.what() << std::endl;
}
return 0;
}

View file

@ -1,250 +0,0 @@
#pragma once
#include "sys_lib.h"
#include "i_story_project.h"
#include "base_node.h"
#include "connection.h"
struct AstNode
{
std::shared_ptr<BaseNode> node; // pointeur vers le noeud en cours
std::vector<std::shared_ptr<AstNode>> inputs;
std::shared_ptr<AstNode> condition; // Pour les boucles et les branchements
std::vector<std::shared_ptr<AstNode>> body; // Pour les boucles et les branchements
std::shared_ptr<AstNode> elseBody; // Pour les branchements
std::pair<int, int> position;
};
// AST (Arbre de syntaxe abstraite)
struct AST {
std::map<std::string, int> variables; // Stockage des variables (adresses mémoire)
std::string assemblyCode;
int labelCounter = 0;
std::map<std::string, std::shared_ptr<AstNode>> nodeMap;
// Fonction pour générer un label unique
std::string generateLabel(AST& ast) {
return "label" + std::to_string(ast.labelCounter++);
}
};
class Compiler
{
public:
Compiler() = default;
~Compiler() = default;
static std::string FileToConstant(const std::string &FileName, const std::string &extension, IStoryProject &project);
// Fonction pour construire l'AST à partir des nœuds et des connexions
void buildAST(std::vector<std::shared_ptr<BaseNode>>& nodes, std::vector<std::shared_ptr<Connection>>& connections) {
m_ast.nodeMap.clear();
// Créer une map pour accéder aux nœuds par ID
int x = 0, y = 0;
for (auto& node : nodes) {
auto astNode = std::make_shared<AstNode>();
astNode->position = {x, y};
x += 1; // Espacement horizontal
if (x > 20) { // Nouvelle ligne
x = 0;
y += 1; // Espacement vertical
}
astNode->node = node;
m_ast.nodeMap[node->GetId()] = astNode;
}
// Construire les connexions entre les nœuds
for (auto& connection : connections) {
std::shared_ptr<AstNode> outNode = m_ast.nodeMap[connection->outNodeId];
std::shared_ptr<AstNode> inNode = m_ast.nodeMap[connection->inNodeId];
inNode->inputs.push_back(outNode); // Ajoute le noeud de sortie en entrée du noeud d'entrée
}
// Gestion des conditions et des corps de boucles/branches
for (auto& node : nodes) {
std::string nodeType = node->GetTypeName();
if (nodeType == "LOOP" || nodeType == "BRANCH") {
for (auto& connection : connections) {
if (connection->inNodeId == node->GetId()) {
if (connection->inPortIndex == 0) { // Condition
m_ast.nodeMap[node->GetId()]->condition = m_ast.nodeMap[connection->outNodeId];
} else if (connection->inPortIndex == 1) { // Body
m_ast.nodeMap[node->GetId()]->body.push_back(m_ast.nodeMap[connection->outNodeId]);
} else if (nodeType == "BRANCH" && connection->inPortIndex == 2) { // ElseBody
// if (m_ast.nodeMap[node->GetId()]->elseBody == nullptr) {
// auto dummyNode = std::make_shared<BaseNode>("DummyNode");
// auto dummyAstNode = std::make_shared<AstNode>();
// dummyAstNode->node = dummyNode;
// m_ast.nodeMap[node->GetId()]->elseBody = dummyAstNode;
// }
m_ast.nodeMap[node->GetId()]->elseBody->body.push_back(m_ast.nodeMap[connection->outNodeId]);
}
}
}
}
}
}
void displayNodeSchema() {
// Définir une taille fixe pour la grille
const int gridWidth = 20; // 20 cases de large
int gridHeight = 0;
// Calculer la hauteur nécessaire pour la grille
for (const auto& astNode : m_ast.nodeMap) {
gridHeight = std::max(gridHeight, astNode.second->position.second + 1);
}
// Créer une grille pour la console
std::vector<std::vector<std::string>> grid(gridHeight, std::vector<std::string>(gridWidth, " "));
// Placer les nœuds dans la grille
for (const auto& astNode : m_ast.nodeMap) {
auto pos = astNode.second->position;
std::string nodeName = astNode.second->node->GetTypeName();
// Tronquer le nom du nœud à 3 caractères
if (nodeName.length() > 3) {
nodeName = nodeName.substr(0, 3);
} else {
// Ajouter des espaces pour centrer le nom dans la case
nodeName.insert(nodeName.end(), 3 - nodeName.length(), ' ');
}
// Placer le nom du nœud dans la grille
grid[pos.second][pos.first] = nodeName;
}
// Dessiner les connexions
for (const auto& astNode : m_ast.nodeMap) {
for (const auto& input : astNode.second->inputs) {
auto outPos = input->position;
auto inPos = astNode.second->position;
// Dessiner une ligne entre les nœuds
int startX = outPos.first + 1; // Commencer après le nom du nœud
int startY = outPos.second;
int endX = inPos.first;
int endY = inPos.second;
// Ligne horizontale
for (int i = startX; i <= endX; ++i) {
if (i < gridWidth) {
grid[startY][i][0] = '-'; // Dessiner la ligne dans la première position de la case
}
}
// Ligne verticale
for (int i = std::min(startY, endY); i <= std::max(startY, endY); ++i) {
if (i < gridHeight) {
grid[i][endX][0] = '|'; // Dessiner la ligne dans la première position de la case
}
}
}
}
// Afficher la grille avec des séparateurs verticaux
for (const auto& row : grid) {
for (size_t i = 0; i < row.size(); ++i) {
std::cout << row[i];
if (i < row.size() - 1) {
std::cout << "|"; // Séparateur vertical
}
}
std::cout << std::endl;
}
}
void generateAssembly() {
std::string assemblyCode;
std::map<std::string, std::string> labels;
// 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";
// Générer des labels uniques pour les nœuds
for (const auto& nodePair : m_ast.nodeMap) {
std::string label = m_ast.generateLabel(m_ast);
labels[nodePair.first] = label;
// Générer du code pour chaque type de nœud
std::string nodeType = nodePair.second->node->GetTypeName();
if (nodeType == "LOOP") {
// Générer du code pour une boucle
assemblyCode += " ; Loop start\n";
// Ajouter des instructions pour la condition de la boucle
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps de la boucle
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Loop body\n";
// Ajouter des instructions pour chaque nœud du corps
}
assemblyCode += " jump " + label + "\n"; // Retour au début de la boucle
} else if (nodeType == "BRANCH") {
// Générer du code pour un branchement
assemblyCode += " ; Branch start\n";
// Ajouter des instructions pour la condition du branchement
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipnz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps du branchement
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Branch body\n";
// Ajouter des instructions pour chaque nœud du corps
}
// Ajouter des instructions pour le corps du else
if (nodePair.second->elseBody) {
assemblyCode += " ; Else body\n";
// Ajouter des instructions pour chaque nœud du corps du else
}
} else {
// Générer du code pour d'autres types de nœuds
assemblyCode += " ; Other node type: " + nodeType + "\n";
assemblyCode += nodePair.second->node->GenerateAssembly();
// Ajouter des instructions spécifiques au type de nœud
}
}
// Ajouter le code assembleur généré à l'AST
m_ast.assemblyCode = assemblyCode;
}
std::string GetCode() const {
return m_ast.assemblyCode;
}
private:
AST m_ast;
};

View file

@ -0,0 +1,363 @@
#pragma once
#include <memory>
#include <sstream>
#include <unordered_map>
#include <stack>
#include <vector>
#include <iomanip>
#include <chrono>
#include <ctime>
#include "ast_builder.h"
#include "print_node.h"
#include "function_entry_node.h"
#include "variable_node.h"
#include "branch_node.h"
#include "operator_node.h"
class AssemblyGenerator {
public:
struct GeneratorContext {
std::string timestamp;
std::string username;
bool debugOutput;
bool optimizeCode;
int stackSize;
GeneratorContext(const std::string& ts = "2025-04-08 12:09:01",
const std::string& user = "arabine",
bool debug = true,
bool optimize = true,
int stack = 1024)
: timestamp(ts)
, username(user)
, debugOutput(debug)
, optimizeCode(optimize)
, stackSize(stack)
{}
};
AssemblyGenerator(const GeneratorContext& context = GeneratorContext())
: m_context(context)
{
Reset();
}
void Reset() {
m_assembly.str("");
m_labelCounter = 0;
m_variableAddresses.clear();
m_currentStackOffset = 0;
m_stringLiterals.clear();
m_depth = 0;
m_currentSection = Section::NONE;
}
std::string GenerateAssembly(const std::vector<PathTree>& roots) {
Reset();
// Generate header comments
GenerateHeader();
// Generate data section
StartSection(Section::DATA);
GenerateDataSection(roots);
// Generate bss section for uninitialized data
StartSection(Section::BSS);
GenerateBssSection();
// Generate text section
StartSection(Section::TEXT);
GenerateTextSection(roots);
return m_assembly.str();
}
protected:
enum class Section {
NONE,
DATA,
BSS,
TEXT
};
virtual void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) {
if (!node) return;
if (m_context.debugOutput) {
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
}
if (node->IsType<FunctionEntryNode>()) {
GenerateFunctionEntry(node);
}
else if (node->IsType<BranchNode>()) {
GenerateBranchNode(node);
}
else if (node->IsType<PrintNode>()) {
GeneratePrintNode(node);
}
else if (node->IsType<OperatorNode>()) {
GenerateOperatorNode(node);
}
else if (node->IsType<VariableNode>()) {
GenerateVariableNode(node);
}
// If we're processing a data path, traverse data outputs
if (isDataPath) {
for (const auto& [port, outputs] : node->dataOutputs) {
for (const auto& target : outputs) {
GenerateNodeCode(target.node, true);
}
}
}
}
private:
GeneratorContext m_context;
std::stringstream m_assembly;
int m_labelCounter;
std::unordered_map<std::string, std::string> m_variableAddresses;
int m_currentStackOffset;
std::vector<std::string> m_stringLiterals;
int m_depth;
Section m_currentSection;
void GenerateHeader() {
m_assembly << "; Assembly generated by Visual Node Editor\n"
<< "; Generation time: " << m_context.timestamp << "\n"
<< "; Generated by: " << m_context.username << "\n"
<< "; Optimization: " << (m_context.optimizeCode ? "enabled" : "disabled") << "\n"
<< "\n";
}
void StartSection(Section section) {
if (m_currentSection == section) return;
m_currentSection = section;
switch (section) {
case Section::DATA:
m_assembly << "section .data\n";
break;
case Section::BSS:
m_assembly << "section .bss\n";
break;
case Section::TEXT:
m_assembly << "section .text\n"
<< "global _start\n\n";
break;
default:
break;
}
}
void GenerateDataSection(const std::vector<PathTree>& trees) {
// 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);
}
}
void GenerateBssSection() {
m_assembly << " stack_space resb " << m_context.stackSize << "\n";
}
void GenerateTextSection(const std::vector<PathTree>& trees) {
// Program entry point
m_assembly << "_start:\n";
// Setup stack frame
m_assembly << " mov ebp, esp\n"
<< " sub esp, " << m_context.stackSize << "\n\n";
// 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);
}
}
// Program exit
GenerateExit();
}
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
AddComment("Function Entry");
m_depth++;
for (auto& child : node->children) {
GenerateNodeCode(child);
}
m_depth--;
}
void GenerateBranchNode(std::shared_ptr<ASTNode> node) {
std::string labelTrue = GenerateUniqueLabel("true");
std::string labelFalse = GenerateUniqueLabel("false");
std::string labelEnd = GenerateUniqueLabel("end");
AddComment("Branch condition evaluation");
m_depth++;
// Generate condition code
if (auto conditionNode = node->GetDataInput(0)) {
GenerateNodeCode(conditionNode);
}
// Compare result and jump
m_assembly << " pop eax\n"
<< " cmp eax, 0\n"
<< " je " << labelFalse << "\n";
// True branch
m_assembly << labelTrue << ":\n";
if (node->GetChildCount() > 0) {
GenerateNodeCode(node->GetChild(0));
}
m_assembly << " jmp " << labelEnd << "\n";
// False branch
m_assembly << labelFalse << ":\n";
if (node->GetChildCount() > 1) {
GenerateNodeCode(node->GetChild(1));
}
m_assembly << labelEnd << ":\n";
m_depth--;
}
void GeneratePrintNode(std::shared_ptr<ASTNode> node) {
auto* printNode = node->GetAs<PrintNode>();
if (!printNode) return;
std::string text = printNode->GetText();
std::string label = AddStringLiteral(text);
// System call to write
m_assembly << " mov edx, " << label << "_len\n"
<< " mov ecx, " << label << "\n"
<< " mov ebx, 1\n" // stdout
<< " mov eax, 4\n" // sys_write
<< " int 0x80\n";
}
void GenerateOperatorNode(std::shared_ptr<ASTNode> node) {
auto* opNode = node->GetAs<OperatorNode>();
if (!opNode) return;
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
m_depth++;
// Generate code for operands
for (const auto& [port, inputNode] : node->dataInputs) {
GenerateNodeCode(inputNode);
}
// Generate operator code
switch (opNode->GetOperationType()) {
case OperatorNode::OperationType::ADD:
m_assembly << " pop ebx\n"
<< " pop eax\n"
<< " add eax, ebx\n"
<< " push eax\n";
break;
case OperatorNode::OperationType::SUBTRACT:
m_assembly << " pop ebx\n"
<< " pop eax\n"
<< " sub eax, ebx\n"
<< " push eax\n";
break;
case OperatorNode::OperationType::MULTIPLY:
m_assembly << " pop ebx\n"
<< " pop eax\n"
<< " imul eax, ebx\n"
<< " push eax\n";
break;
case OperatorNode::OperationType::DIVIDE:
m_assembly << " pop ebx\n"
<< " pop eax\n"
<< " cdq\n"
<< " idiv ebx\n"
<< " push eax\n";
break;
// Add other operators...
}
m_depth--;
}
void GenerateVariableNode(std::shared_ptr<ASTNode> node) {
auto* varNode = node->GetAs<VariableNode>();
if (!varNode) return;
std::string varName = varNode->GetVariableName();
AddComment("Load variable: " + varName);
m_assembly << " mov eax, [" << m_variableAddresses[varName] << "]\n"
<< " push eax\n";
}
void GenerateExit() {
AddComment("Program exit");
m_assembly << " mov eax, 1\n" // sys_exit
<< " mov ebx, 0\n" // return 0
<< " int 0x80\n";
}
void CollectVariables(std::shared_ptr<ASTNode> node) {
if (!node) return;
if (node->IsType<VariableNode>()) {
auto* varNode = node->GetAs<VariableNode>();
std::string varName = varNode->GetVariableName();
if (m_variableAddresses.find(varName) == m_variableAddresses.end()) {
m_variableAddresses[varName] = varName;
m_assembly << varName << ":\n" << varNode->GenerateAssembly();
}
}
// Traverse children
for (auto& child : node->children) {
CollectVariables(child);
}
// Traverse data inputs
for (const auto& [port, inputNode] : node->dataInputs) {
CollectVariables(inputNode);
}
}
std::string AddStringLiteral(const std::string& text) {
std::string label = "str_" + std::to_string(m_stringLiterals.size());
m_stringLiterals.push_back(text);
return label;
}
std::string GenerateUniqueLabel(const std::string& prefix) {
return prefix + "_" + std::to_string(m_labelCounter++);
}
void AddComment(const std::string& comment) {
if (m_context.debugOutput) {
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
}
}
};

View file

@ -0,0 +1,293 @@
#pragma once
#include "base_node.h"
#include "connection.h"
#include "function_entry_node.h"
#include <unordered_map>
#include <unordered_set>
#include <queue>
class ASTNode {
public:
// Structure to represent a data connection target
struct DataTarget {
std::shared_ptr<ASTNode> node;
unsigned int portIndex;
};
explicit ASTNode(std::shared_ptr<BaseNode> node)
: node(node) {}
// The actual node from the visual editor
std::shared_ptr<BaseNode> node;
// Execution flow children (for EXECUTION_LINKJ connections)
std::vector<std::shared_ptr<ASTNode>> children;
// Data inputs: port_index -> source node
std::unordered_map<unsigned int, std::shared_ptr<ASTNode>> dataInputs;
// Data outputs: output_port_index -> vector of (target node, target port)
std::unordered_map<unsigned int, std::vector<DataTarget>> dataOutputs;
// Helper methods
bool HasDataInput(unsigned int portIndex) const {
return dataInputs.find(portIndex) != dataInputs.end();
}
bool HasDataOutput(unsigned int portIndex) const {
return dataOutputs.find(portIndex) != dataOutputs.end();
}
std::shared_ptr<ASTNode> GetDataInput(unsigned int portIndex) const {
auto it = dataInputs.find(portIndex);
if (it != dataInputs.end()) {
return it->second;
}
return nullptr;
}
const std::vector<DataTarget>& GetDataOutputs(unsigned int portIndex) const {
static const std::vector<DataTarget> empty;
auto it = dataOutputs.find(portIndex);
if (it != dataOutputs.end()) {
return it->second;
}
return empty;
}
// Add a data input connection
void AddDataInput(unsigned int portIndex, std::shared_ptr<ASTNode> sourceNode) {
dataInputs[portIndex] = sourceNode;
}
// Add a data output connection
void AddDataOutput(unsigned int sourcePort, std::shared_ptr<ASTNode> targetNode, unsigned int targetPort) {
DataTarget target{targetNode, targetPort};
dataOutputs[sourcePort].push_back(target);
}
// Add an execution child
void AddChild(std::shared_ptr<ASTNode> child) {
children.push_back(child);
}
// Get execution path child count
size_t GetChildCount() const {
return children.size();
}
// Get child at specific index
std::shared_ptr<ASTNode> GetChild(size_t index) const {
if (index < children.size()) {
return children[index];
}
return nullptr;
}
// Utility method to check if this is a specific node type
template<typename T>
bool IsType() const {
return dynamic_cast<const T*>(node.get()) != nullptr;
}
// Get node as specific type
template<typename T>
T* GetAs() const {
return dynamic_cast<T*>(node.get());
}
// Debug information
std::string GetDebugString() const {
std::string result = "Node: " + node->GetTypeName() + " (ID: " + node->GetId() + ")\n";
// Add data inputs info
for (const auto& [port, input] : dataInputs) {
result += " Input port " + std::to_string(port) +
" <- " + input->node->GetTypeName() + "\n";
}
// Add data outputs info
for (const auto& [port, outputs] : dataOutputs) {
for (const auto& target : outputs) {
result += " Output port " + std::to_string(port) +
" -> " + target.node->node->GetTypeName() +
" (port " + std::to_string(target.portIndex) + ")\n";
}
}
// Add execution children info
for (size_t i = 0; i < children.size(); ++i) {
result += " Child " + std::to_string(i) + ": " +
children[i]->node->GetTypeName() + "\n";
}
return result;
}
};
struct PathTree {
std::shared_ptr<ASTNode> root;
std::vector<std::shared_ptr<Connection>> connections;
bool isExecutionPath; // true for main flow, false for input paths
};
class ASTBuilder {
public:
ASTBuilder(const std::vector<std::shared_ptr<BaseNode>>& nodes,
const std::vector<std::shared_ptr<Connection>>& connections)
: m_nodes(nodes), m_connections(connections) {}
std::vector<PathTree> 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()) {
// 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) {
dataRoots.push_back(node);
}
}
}
std::vector<PathTree> pathTrees;
// 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:
const std::vector<std::shared_ptr<BaseNode>>& m_nodes;
const std::vector<std::shared_ptr<Connection>>& m_connections;
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;
while (!queue.empty()) {
auto current = queue.front();
queue.pop();
if (visited.find(current->node->GetId()) != visited.end()) {
continue;
}
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);
current->dataOutputs[conn->outPortIndex].push_back(
{childNode, conn->inPortIndex});
queue.push(childNode);
tree.connections.push_back(conn);
}
}
}
}
}
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;
}
}
}
}
};

View file

@ -0,0 +1,442 @@
#pragma once
#include "sys_lib.h"
#include "i_story_project.h"
#include "base_node.h"
#include "connection.h"
#include "function_entry_node.h"
struct AstNode
{
std::shared_ptr<BaseNode> node; // pointeur vers le noeud en cours
std::vector<std::shared_ptr<AstNode>> inputs;
std::shared_ptr<AstNode> condition; // Pour les boucles et les branchements
std::vector<std::shared_ptr<AstNode>> body; // Pour les boucles et les branchements
std::shared_ptr<AstNode> elseBody; // Pour les branchements
std::pair<int, int> position;
};
// AST (Arbre de syntaxe abstraite)
struct AST {
std::map<std::string, int> variables; // Stockage des variables (adresses mémoire)
std::string assemblyCode;
int labelCounter = 0;
std::map<std::string, std::shared_ptr<AstNode>> nodeMap;
// Fonction pour générer un label unique
std::string generateLabel(AST& ast) {
return "label" + std::to_string(ast.labelCounter++);
}
};
class Compiler
{
public:
Compiler() = default;
~Compiler() = default;
static std::string FileToConstant(const std::string &FileName, const std::string &extension, IStoryProject &project);
// Fonction pour construire l'AST à partir des nœuds et des connexions
void buildAST(std::vector<std::shared_ptr<BaseNode>>& nodes, std::vector<std::shared_ptr<Connection>>& connections) {
m_ast.nodeMap.clear();
// Créer une map pour accéder aux nœuds par ID
int x = 0, y = 0;
for (auto& node : nodes) {
auto astNode = std::make_shared<AstNode>();
astNode->position = {x, y};
x += 1; // Espacement horizontal
if (x > 20) { // Nouvelle ligne
x = 0;
y += 1; // Espacement vertical
}
astNode->node = node;
m_ast.nodeMap[node->GetId()] = astNode;
}
// Analyser les connexions pour établir les relations entre les nœuds
for (const auto& connection : connections) {
auto outNode = m_ast.nodeMap[connection->outNodeId];
auto inNode = m_ast.nodeMap[connection->inNodeId];
// // Utiliser les indices des ports pour établir les connexions
// if (outNode->inputs.size() <= connection->inPortIndex) {
// outNode->inputs.resize(connection->inPortIndex + 1);
// }
// outNode->inputs[connection->inPortIndex] = inNode;
// Gérer les sorties en utilisant connection->outPortIndex
if (outNode->body.size() <= connection->outPortIndex) {
outNode->body.resize(connection->outPortIndex + 1);
}
outNode->body[connection->outPortIndex] = inNode;
}
}
void printAST(const AST& ast, const std::shared_ptr<AstNode>& node, const std::string& prefix = "", bool isLast = true) {
// Afficher le nœud actuel
std::cout << prefix;
std::cout << (isLast ? "└──" : "├──");
// Afficher les informations du nœud
std::cout << "Node: " << node->node->GetTypeName() << " (" << node->node->GetId() << ")" << std::endl;
// Préparer le préfixe pour les enfants
std::string newPrefix = prefix + (isLast ? " " : "");
// Parcourir les entrées (inputs) du nœud
// for (size_t i = 0; i < node->inputs.size(); ++i) {
// bool isLastInput = (i == node->inputs.size() - 1);
// printAST(ast, node->inputs[i], newPrefix, isLastInput);
// }
// Parcourir les sorties (body) du nœud
for (size_t i = 0; i < node->body.size(); ++i) {
bool isLastBody = (i == node->body.size() - 1);
printAST(ast, node->body[i], newPrefix, isLastBody);
}
// Parcourir le conditionnel (condition) du nœud, s'il existe
if (node->condition) {
printAST(ast, node->condition, newPrefix, true);
}
// Parcourir le corps du else (elseBody) du nœud, s'il existe
if (node->elseBody) {
printAST(ast, node->elseBody, newPrefix, true);
}
}
void printAST() {
// Trouver le nœud de type "function-entry-node"
std::shared_ptr<AstNode> entryNode;
for (const auto& pair : m_ast.nodeMap) {
if (pair.second->node->GetType() == "function-entry-node") {
entryNode = pair.second;
break;
}
}
if (!entryNode) {
std::cerr << "No function-entry-node found in the AST." << std::endl;
return;
}
// Commencer l'affichage de l'arbre à partir du nœud d'entrée
printAST(m_ast, entryNode);
}
void generateAssembly() {
std::ostringstream assemblyCode;
std::map<std::string, std::string> labels;
// Trouver le nœud de type "function-entry-node"
std::shared_ptr<AstNode> entryNode;
for (const auto& pair : m_ast.nodeMap) {
if (pair.second->node->GetType() == "function-entry-node") {
entryNode = pair.second;
break;
}
}
if (!entryNode) {
throw std::runtime_error("No function-entry-node found in the AST.");
}
// Fonction récursive pour générer le code assembleur
std::function<void(const std::shared_ptr<AstNode>&)> generateCode = [&](const std::shared_ptr<AstNode>& node) {
if (node->node->GetType() == "print") {
// Générer le code pour un nœud de type "print"
assemblyCode << "PRINT ";
// Supposons que le nœud print a une entrée qui est une variable
if (!node->inputs.empty()) {
assemblyCode << node->inputs[0]->node->GetTitle();
}
assemblyCode << std::endl;
} else if (node->node->GetType() == "variable-node") {
// Générer le code pour un nœud de type "variable-node"
assemblyCode << "LOAD " << node->node->GetTitle() << " INTO REGISTER" << std::endl;
} else if (node->node->GetType() == "branch-node") {
// Générer le code pour un nœud de type "branch-node"
assemblyCode << "BRANCH TO LABEL_" << node->node->GetId() << std::endl;
// Générer le code pour les sorties du nœud branch
for (const auto& outputNode : node->body) {
generateCode(outputNode);
}
} else if (node->node->GetType() == "function-entry-node") {
// Générer le code pour un nœud de type "function-entry-node"
assemblyCode << "FUNCTION ENTRY POINT" << std::endl;
// Générer le code pour les nœuds connectés à ce nœud
for (const auto& inputNode : node->inputs) {
generateCode(inputNode);
}
}
};
// 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";
// Commencer la génération de code à partir du nœud d'entrée
generateCode(entryNode);
// Stocker le code assembleur généré dans l'AST
m_ast.assemblyCode = assemblyCode.str();
}
std::string GetCode() const {
return m_ast.assemblyCode;
}
private:
AST m_ast;
};
/*
class AssemblyGenerator {
public:
AssemblyGenerator() {
Reset();
}
void Reset() {
m_assembly.str("");
m_labelCounter = 0;
m_variableAddresses.clear();
m_currentStackOffset = 0;
}
std::string GenerateAssembly(const std::vector<std::shared_ptr<ASTNode>>& roots) {
Reset();
// Generate data section
m_assembly << "section .data\n";
// Add string constants for print nodes
m_assembly << "msg_good db 'Good!',0xa,0\n";
m_assembly << "msg_bad db 'Bad :(',0xa,0\n";
// Generate code section
m_assembly << "\nsection .text\n";
m_assembly << "global _start\n\n";
m_assembly << "_start:\n";
// Generate entry point code
for (const auto& root : roots) {
GenerateNodeCode(root);
}
// Add exit syscall
m_assembly << " mov eax, 1\n"; // exit syscall
m_assembly << " mov ebx, 0\n"; // return 0
m_assembly << " int 0x80\n";
return m_assembly.str();
}
private:
std::stringstream m_assembly;
int m_labelCounter;
std::unordered_map<std::string, int> m_variableAddresses;
int m_currentStackOffset;
std::string GenerateUniqueLabel(const std::string& prefix) {
return prefix + "_" + std::to_string(m_labelCounter++);
}
void GenerateNodeCode(std::shared_ptr<ASTNode> node) {
if (!node) return;
if (node->IsType<FunctionEntryNode>()) {
// Generate code for function entry
m_assembly << " ; Function Entry\n";
for (auto& child : node->children) {
GenerateNodeCode(child);
}
}
else if (node->IsType<BranchNode>()) {
GenerateBranchCode(node);
}
else if (node->IsType<PrintNode>()) {
GeneratePrintCode(node);
}
else if (node->IsType<VariableNode>()) {
GenerateVariableCode(node);
}
else if (node->IsType<OperatorNode>()) {
GenerateOperatorCode(node);
}
}
void GenerateBranchCode(std::shared_ptr<ASTNode> node) {
std::string labelTrue = GenerateUniqueLabel("true");
std::string labelFalse = GenerateUniqueLabel("false");
std::string labelEnd = GenerateUniqueLabel("end");
m_assembly << " ; Branch condition evaluation\n";
// Generate condition code
if (auto conditionNode = node->GetDataInput(0)) {
GenerateNodeCode(conditionNode);
}
m_assembly << " pop eax\n";
m_assembly << " cmp eax, 0\n";
m_assembly << " je " << labelFalse << "\n";
// True branch
m_assembly << labelTrue << ":\n";
if (node->GetChildCount() > 0) {
GenerateNodeCode(node->GetChild(0));
}
m_assembly << " jmp " << labelEnd << "\n";
// False branch
m_assembly << labelFalse << ":\n";
if (node->GetChildCount() > 1) {
GenerateNodeCode(node->GetChild(1));
}
m_assembly << labelEnd << ":\n";
}
void GeneratePrintCode(std::shared_ptr<ASTNode> node) {
auto* printNode = node->GetAs<PrintNode>();
if (!printNode) return;
m_assembly << " ; Print message\n";
if (printNode->GetText() == "Good!") {
m_assembly << " mov edx, 6\n"; // message length
m_assembly << " mov ecx, msg_good\n";
} else {
m_assembly << " mov edx, 6\n"; // message length
m_assembly << " mov ecx, msg_bad\n";
}
m_assembly << " mov ebx, 1\n"; // file descriptor (stdout)
m_assembly << " mov eax, 4\n"; // sys_write
m_assembly << " int 0x80\n";
}
void GenerateVariableCode(std::shared_ptr<ASTNode> node) {
auto* varNode = node->GetAs<VariableNode>();
if (!varNode) return;
// For this example, we'll just push a value onto the stack
std::string varName = varNode->GetVariableName();
if (m_variableAddresses.find(varName) == m_variableAddresses.end()) {
m_variableAddresses[varName] = m_currentStackOffset;
m_currentStackOffset += 4;
}
m_assembly << " ; Load variable " << varName << "\n";
m_assembly << " mov eax, [ebp-" << m_variableAddresses[varName] << "]\n";
m_assembly << " push eax\n";
}
void GenerateOperatorCode(std::shared_ptr<ASTNode> node) {
auto* opNode = node->GetAs<OperatorNode>();
if (!opNode) return;
// Generate code for operands
for (const auto& [port, inputNode] : node->dataInputs) {
GenerateNodeCode(inputNode);
}
m_assembly << " ; Operator " << static_cast<int>(opNode->GetOperationType()) << "\n";
switch (opNode->GetOperationType()) {
case OperatorNode::ADD:
m_assembly << " pop ebx\n";
m_assembly << " pop eax\n";
m_assembly << " add eax, ebx\n";
m_assembly << " push eax\n";
break;
case OperatorNode::SUBTRACT:
m_assembly << " pop ebx\n";
m_assembly << " pop eax\n";
m_assembly << " sub eax, ebx\n";
m_assembly << " push eax\n";
break;
// Add other operators...
}
}
};
*/
/*
// Générer des labels uniques pour les nœuds
for (const auto& nodePair : m_ast.nodeMap) {
std::string label = m_ast.generateLabel(m_ast);
labels[nodePair.first] = label;
// Générer du code pour chaque type de nœud
std::string nodeType = nodePair.second->node->GetTypeName();
if (nodeType == "LOOP") {
// Générer du code pour une boucle
assemblyCode += " ; Loop start\n";
// Ajouter des instructions pour la condition de la boucle
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps de la boucle
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Loop body\n";
// Ajouter des instructions pour chaque nœud du corps
}
assemblyCode += " jump " + label + "\n"; // Retour au début de la boucle
} else if (nodeType == "BRANCH") {
// Générer du code pour un branchement
assemblyCode += " ; Branch start\n";
// Ajouter des instructions pour la condition du branchement
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipnz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps du branchement
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Branch body\n";
// Ajouter des instructions pour chaque nœud du corps
}
// Ajouter des instructions pour le corps du else
if (nodePair.second->elseBody) {
assemblyCode += " ; Else body\n";
// Ajouter des instructions pour chaque nœud du corps du else
}
} else {
// Générer du code pour d'autres types de nœuds
assemblyCode += " ; Other node type: " + nodeType + "\n";
assemblyCode += nodePair.second->node->GenerateAssembly();
// Ajouter des instructions spécifiques au type de nœud
}
}
*/

View file

@ -0,0 +1,135 @@
#pragma once
#include "assembly_generator.h"
#include <iostream>
#include <iomanip>
#include <chrono>
class FlowVisualizer {
public:
static void PrintHeader(const std::string& user, const std::string& timestamp) {
std::cout << "==========================================================\n";
std::cout << "AST Flow Visualization\n";
std::cout << "User: " << user << "\n";
std::cout << "Time: " << timestamp << "\n";
std::cout << "==========================================================\n\n";
}
static void PrintNodeExecution(const std::string& nodeName, int depth = 0) {
PrintTimestamp();
std::cout << std::string(depth * 2, ' ') << "→ Executing: " << nodeName << "\n";
}
static void PrintDataFlow(const std::string& from, const std::string& to,
const std::string& value, int depth = 0) {
PrintTimestamp();
std::cout << std::string(depth * 2, ' ') << " ┌─ Data: " << from
<< "" << to << " (value: " << value << ")\n";
}
static void PrintBranchDecision(bool condition, const std::string& value, int depth = 0) {
PrintTimestamp();
std::cout << std::string(depth * 2, ' ') << " ├─ Branch: "
<< (condition ? "TRUE" : "FALSE") << " (condition: " << value << ")\n";
}
private:
static void PrintTimestamp() {
auto now = std::chrono::system_clock::now();
auto now_c = std::chrono::system_clock::to_time_t(now);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) % 1000;
std::cout << "[" << std::put_time(std::localtime(&now_c), "%H:%M:%S")
<< "." << std::setfill('0') << std::setw(3) << ms.count() << "] ";
}
};
class VisualFlowGenerator : public AssemblyGenerator {
public:
VisualFlowGenerator(const GeneratorContext& context)
: AssemblyGenerator(context)
{
}
protected:
void GenerateNodeCode(std::shared_ptr<ASTNode> node, bool isDataPath = false) override {
if (!node) return;
FlowVisualizer::PrintNodeExecution(node->node->GetTypeName(), m_depth);
if (node->IsType<FunctionEntryNode>()) {
m_depth++;
for (auto& child : node->children) {
GenerateNodeCode(child);
}
m_depth--;
}
else if (node->IsType<BranchNode>()) {
m_depth++;
// Get condition value
auto conditionNode = node->GetDataInput(0);
int conditionValue = EvaluateCondition(conditionNode);
FlowVisualizer::PrintBranchDecision(conditionValue > 7,
std::to_string(conditionValue), m_depth);
// Execute appropriate path
if (conditionValue > 7) {
GenerateNodeCode(node->GetChild(0)); // True path
} else {
GenerateNodeCode(node->GetChild(1)); // False path
}
m_depth--;
}
else if (node->IsType<PrintNode>()) {
auto* printNode = node->GetAs<PrintNode>();
FlowVisualizer::PrintNodeExecution("Print: " + printNode->GetText(), m_depth);
}
else if (node->IsType<OperatorNode>()) {
m_depth++;
auto* opNode = node->GetAs<OperatorNode>();
// Evaluate operands
int value1 = EvaluateOperand(node->GetDataInput(0));
int value2 = EvaluateOperand(node->GetDataInput(1));
FlowVisualizer::PrintDataFlow("Operand 1", "ADD",
std::to_string(value1), m_depth);
FlowVisualizer::PrintDataFlow("Operand 2", "ADD",
std::to_string(value2), m_depth);
int result = value1 + value2;
FlowVisualizer::PrintDataFlow("ADD", "Result",
std::to_string(result), m_depth);
m_depth--;
}
}
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;
}
};

View file

@ -13,30 +13,50 @@
class BaseNode class BaseNode
{ {
public: public:
struct Port
{
enum Type {
EXECUTION_PORT,
DATA_PORT
};
Port::Type type{EXECUTION_PORT};
std::string label;
};
struct NodePosition struct NodePosition
{ {
float x; float x;
float y; float y;
}; };
/*
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!@#$%^&*()_+-=[]{}|;:,.<>?";
*/
enum RandomFlags enum RandomFlags
{ {
CHARSET_ALPHABET_LOWER = 0x1, CHARSET_ALPHABET_LOWER = 0x1, // "abcdefghijklmnopqrstuvwxyz"
CHARSET_ALPHABET_UPPER = 0x2, CHARSET_ALPHABET_UPPER = 0x2, // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
CHARSET_NUMBERS = 0x4, CHARSET_NUMBERS = 0x4, // "0123456789"
CHARSET_SIGNS = 0x8, CHARSET_SIGNS = 0x8, // "!@#$%^&*()_+-=[]{}|;:,.<>?";
ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS
}; };
struct ConstantValue
{
enum Type {
TYPE_STRING,
TYPE_INT,
};
std::string stringVal;
int intVal{0};
ConstantValue::Type type{TYPE_INT};
};
struct Constant
{
std::string label;
int elementSize; // in bits: 8, 16 or 32
std::vector<ConstantValue> values;
};
BaseNode(const std::string &type, const std::string &typeName); BaseNode(const std::string &type, const std::string &typeName);
virtual ~BaseNode(); virtual ~BaseNode();
@ -86,6 +106,21 @@ public:
static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS); static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS);
void ClearPorts() {
m_inputPorts.clear();
m_outputPorts.clear();
}
// Port management
void AddInputPort(Port::Type type, const std::string& label) {
m_inputPorts.push_back({type, label});
}
void AddOutputPort(Port::Type type, const std::string& label) {
m_outputPorts.push_back({type, label});
}
private: private:
std::string m_title{"Default title"}; std::string m_title{"Default title"};
std::string m_type; std::string m_type;
@ -93,6 +128,9 @@ private:
std::string m_uuid; std::string m_uuid;
NodePosition m_pos; NodePosition m_pos;
std::vector<Port> m_inputPorts;
std::vector<Port> m_outputPorts;
nlohmann::json m_internal_data{{}}; nlohmann::json m_internal_data{{}};
}; };

View file

@ -15,6 +15,7 @@ public:
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(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
virtual std::string GenerateAssembly() const { return ""; }
private: private:
}; };

View file

@ -5,6 +5,13 @@
struct Connection struct Connection
{ {
enum Type
{
EXECUTION_LINKJ,
DATA_LINK
};
Connection() Connection()
: outPortIndex(0) : outPortIndex(0)
, inPortIndex(0) , inPortIndex(0)
@ -16,6 +23,7 @@ struct Connection
} }
Connection::Type type{Connection::EXECUTION_LINKJ};
std::string outNodeId; std::string outNodeId;
unsigned int outPortIndex{0}; unsigned int outPortIndex{0};
std::string inNodeId; std::string inNodeId;

View file

@ -6,8 +6,8 @@
class FunctionEntryNode : public ExecutionNode class FunctionEntryNode : public ExecutionNode
{ {
public: public:
FunctionEntryNode(const std::string &type, const std::string &typeName) FunctionEntryNode(const std::string &type)
: ExecutionNode(type, typeName) {} : ExecutionNode(type, "Function Entry Node") {}
void Initialize() override { void Initialize() override {
// Initialisation spécifique pour FunctionEntryNode // Initialisation spécifique pour FunctionEntryNode

View file

@ -0,0 +1,240 @@
#pragma once
#include "base_node.h"
#pragma once
#include "base_node.h"
#include <sstream>
#include <stdexcept>
#include <unordered_map>
class OperatorNode : public BaseNode
{
public:
enum class OperationType {
ADD, // Addition (+)
SUBTRACT, // Subtraction (-)
MULTIPLY, // Multiplication (*)
DIVIDE, // Division (/)
MODULO, // Modulo (%)
AND, // Logical AND (&&)
OR, // Logical OR (||)
NOT, // Logical NOT (!)
XOR, // Logical XOR (^)
EQUAL, // Equal to (==)
NOT_EQUAL, // Not equal to (!=)
GREATER_THAN, // Greater than (>)
LESS_THAN, // Less than (<)
GREATER_EQUAL, // Greater than or equal (>=)
LESS_EQUAL, // Less than or equal (<=)
BITWISE_AND, // Bitwise AND (&)
BITWISE_OR, // Bitwise OR (|)
BITWISE_XOR, // Bitwise XOR (^)
BITWISE_NOT, // Bitwise NOT (~)
LEFT_SHIFT, // Left shift (<<)
RIGHT_SHIFT // Right shift (>>)
};
OperatorNode(const std::string& type = "operator-node",
const std::string& typeName = "Operator")
: BaseNode(type, typeName)
, m_operationType(OperationType::ADD)
{
Initialize();
}
void Initialize() override {
// Define input ports based on operator type
UpdatePorts();
}
// Set the operator type and update ports accordingly
void SetOperationType(OperationType type) {
m_operationType = type;
UpdatePorts();
}
OperationType GetOperationType() const {
return m_operationType;
}
// Get the symbol representation of the operator
std::string GetOperatorSymbol() const {
static const std::unordered_map<OperationType, std::string> symbolMap = {
{OperationType::ADD, "+"},
{OperationType::SUBTRACT, "-"},
{OperationType::MULTIPLY, "*"},
{OperationType::DIVIDE, "/"},
{OperationType::MODULO, "%"},
{OperationType::AND, "&&"},
{OperationType::OR, "||"},
{OperationType::NOT, "!"},
{OperationType::XOR, "^"},
{OperationType::EQUAL, "=="},
{OperationType::NOT_EQUAL, "!="},
{OperationType::GREATER_THAN, ">"},
{OperationType::LESS_THAN, "<"},
{OperationType::GREATER_EQUAL, ">="},
{OperationType::LESS_EQUAL, "<="},
{OperationType::BITWISE_AND, "&"},
{OperationType::BITWISE_OR, "|"},
{OperationType::BITWISE_XOR, "^"},
{OperationType::BITWISE_NOT, "~"},
{OperationType::LEFT_SHIFT, "<<"},
{OperationType::RIGHT_SHIFT, ">>"}
};
auto it = symbolMap.find(m_operationType);
return it != symbolMap.end() ? it->second : "?";
}
std::string Build(IStoryPage& page, const StoryOptions& options, int nb_out_conns) override {
std::stringstream ss;
ss << "// Operator: " << GetOperatorSymbol() << "\n";
// For unary operators
if (IsUnaryOperator()) {
ss << GetOperatorSymbol() << "operand";
}
// For binary operators
else {
ss << "operand1 " << GetOperatorSymbol() << " operand2";
}
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;
bool IsUnaryOperator() const {
return m_operationType == OperationType::NOT ||
m_operationType == OperationType::BITWISE_NOT;
}
void UpdatePorts() {
// Clear existing ports
ClearPorts();
// Add input ports based on operator type
if (IsUnaryOperator()) {
AddInputPort(Port::DATA_PORT, "in");
} else {
AddInputPort(Port::DATA_PORT, "in1");
AddInputPort(Port::DATA_PORT, "in2");
}
// Add output port
AddOutputPort(Port::DATA_PORT, "out");
}
static std::string OperatorTypeToString(OperationType type) {
static const std::unordered_map<OperationType, std::string> typeMap = {
{OperationType::ADD, "add"},
{OperationType::SUBTRACT, "subtract"},
{OperationType::MULTIPLY, "multiply"},
{OperationType::DIVIDE, "divide"},
{OperationType::MODULO, "modulo"},
{OperationType::AND, "and"},
{OperationType::OR, "or"},
{OperationType::NOT, "not"},
{OperationType::XOR, "xor"},
{OperationType::EQUAL, "equal"},
{OperationType::NOT_EQUAL, "not_equal"},
{OperationType::GREATER_THAN, "greater_than"},
{OperationType::LESS_THAN, "less_than"},
{OperationType::GREATER_EQUAL, "greater_equal"},
{OperationType::LESS_EQUAL, "less_equal"},
{OperationType::BITWISE_AND, "bitwise_and"},
{OperationType::BITWISE_OR, "bitwise_or"},
{OperationType::BITWISE_XOR, "bitwise_xor"},
{OperationType::BITWISE_NOT, "bitwise_not"},
{OperationType::LEFT_SHIFT, "left_shift"},
{OperationType::RIGHT_SHIFT, "right_shift"}
};
auto it = typeMap.find(type);
return it != typeMap.end() ? it->second : "unknown";
}
static OperationType StringToOperationType(const std::string& str) {
static const std::unordered_map<std::string, OperationType> typeMap = {
{"add", OperationType::ADD},
{"subtract", OperationType::SUBTRACT},
{"multiply", OperationType::MULTIPLY},
{"divide", OperationType::DIVIDE},
{"modulo", OperationType::MODULO},
{"and", OperationType::AND},
{"or", OperationType::OR},
{"not", OperationType::NOT},
{"xor", OperationType::XOR},
{"equal", OperationType::EQUAL},
{"not_equal", OperationType::NOT_EQUAL},
{"greater_than", OperationType::GREATER_THAN},
{"less_than", OperationType::LESS_THAN},
{"greater_equal", OperationType::GREATER_EQUAL},
{"less_equal", OperationType::LESS_EQUAL},
{"bitwise_and", OperationType::BITWISE_AND},
{"bitwise_or", OperationType::BITWISE_OR},
{"bitwise_xor", OperationType::BITWISE_XOR},
{"bitwise_not", OperationType::BITWISE_NOT},
{"left_shift", OperationType::LEFT_SHIFT},
{"right_shift", OperationType::RIGHT_SHIFT}
};
auto it = typeMap.find(str);
return it != typeMap.end() ? it->second : OperationType::ADD;
}
};

View file

@ -22,6 +22,11 @@ public:
void SetText(const std::string &text) { void SetText(const std::string &text) {
m_text = text; m_text = text;
} }
std::string GetText() const {
return m_text;
}
private: private:
std::string m_label; std::string m_label;
std::string m_text; // Text to print std::string m_text; // Text to print

View file

@ -0,0 +1,103 @@
#pragma once
#include <string>
#include <variant>
#include "i_story_manager.h"
#include "base_node.h"
#include "i_script_node.h"
#include "i_story_project.h"
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 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("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;
};

View file

@ -1,31 +0,0 @@
#pragma once
#include "base_node.h"
class OperatorNode : public BaseNode
{
public:
OperatorNode(const std::string &type, const std::string &typeName)
: BaseNode(type, typeName) {}
void Initialize() override {
// Initialisation spécifique pour DataNode
}
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
// Logique de construction pour DataNode
return "DataNode Build";
}
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
// Génération des constantes pour DataNode
return "DataNode Constants";
}
// Ajoutez des méthodes spécifiques pour gérer les données directement
void ProcessData() {
// Logique pour traiter les données directement
}
};

View file

@ -1,23 +0,0 @@
#pragma once
#include <string>
#include "i_story_manager.h"
#include "base_node.h"
#include "i_script_node.h"
#include "i_story_project.h"
class VariableNode : public BaseNode
{
public:
VariableNode(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();
private:
};

View file

@ -8,11 +8,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
main.cpp main.cpp
test_ast.cpp test_ast.cpp
../src/base_node.cpp
../src/branch_node.cpp
../src/print_node.cpp ../src/nodes/base_node.cpp
../src/variable_node.cpp ../src/nodes/branch_node.cpp
../src/connection.cpp ../src/nodes/print_node.cpp
../src/nodes/variable_node.cpp
../src/nodes/connection.cpp
../../chip32/chip32_assembler.cpp ../../chip32/chip32_assembler.cpp
../../chip32/chip32_vm.c ../../chip32/chip32_vm.c
@ -24,4 +26,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE
../interfaces ../interfaces
../lib ../lib
../../../shared ../../../shared
../src/nodes
../src/compiler
) )

View file

@ -32,33 +32,124 @@ THE SOFTWARE.
#include "branch_node.h" #include "branch_node.h"
#include "print_node.h" #include "print_node.h"
#include "variable_node.h" #include "variable_node.h"
#include "function_entry_node.h"
#include "chip32_machine.h" #include "chip32_machine.h"
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include "ast_builder.h"
#include "assembly_generator.h"
#include "flow_generator.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;
auto printNode = std::make_shared<PrintNode>("print-node"); auto printNodeTrue = std::make_shared<PrintNode>("print-node");
printNodeTrue->SetText("Good!");
printNode->SetText("Hello from OST"); auto printNodeFalse = std::make_shared<PrintNode>("print-node");
printNodeFalse->SetText("Bad :(");
// auto branchNode = std::make_shared<BranchNode>("branch-node"); auto branchNode = std::make_shared<BranchNode>("branch-node");
auto functionEntryNode = std::make_shared<FunctionEntryNode>("function-entry-node");
auto variableNode = std::make_shared<VariableNode>("variable-node");
std::vector<std::shared_ptr<BaseNode>> nodes; std::vector<std::shared_ptr<BaseNode>> nodes;
nodes.push_back(printNode); nodes.push_back(functionEntryNode);
// nodes.push_back(branchNode); nodes.push_back(printNodeTrue);
nodes.push_back(printNodeFalse);
nodes.push_back(branchNode);
nodes.push_back(variableNode);
auto cn1 = std::make_shared<Connection>();
auto cn2 = std::make_shared<Connection>();
auto cn3 = std::make_shared<Connection>();
auto cn4 = std::make_shared<Connection>();
std::vector<std::shared_ptr<Connection>> connections; std::vector<std::shared_ptr<Connection>> connections;
auto cn1 = std::make_shared<Connection>(); connections.push_back(cn1);
connections.push_back(cn2);
connections.push_back(cn3);
connections.push_back(cn4);
// Branch True -> print Ok
// False -> print Ko
// True path
cn1->inNodeId = printNodeTrue->GetId();
cn1->inPortIndex = 0;
cn1->outNodeId = branchNode->GetId();
cn1->outPortIndex = 0;
// False path
cn2->inNodeId = printNodeFalse->GetId();
cn2->inPortIndex = 0;
cn2->outNodeId = branchNode->GetId();
cn2->outPortIndex = 1;
// Function entry -> Branch node
cn3->inNodeId = branchNode->GetId();
cn3->inPortIndex = 0;
cn3->outNodeId = functionEntryNode->GetId();
cn3->outPortIndex = 0;
// Variable branch -> Branch node (condition input)
cn4->inNodeId = branchNode->GetId();
cn4->inPortIndex = 1;
cn4->outNodeId = variableNode->GetId();
cn4->outPortIndex = 0;
cn4->type = Connection::DATA_LINK;
// // Création des nœuds // // Création des nœuds
// std::vector<Node> nodes = { // std::vector<Node> nodes = {
// Node(Node::Type::VARIABLE, "i", "node_i"), // Node(Node::Type::VARIABLE, "i", "node_i"),
@ -75,20 +166,69 @@ TEST_CASE( "Check various indentations and typos" ) {
// Node(Node::Type::LOOP, "node_loop") // Node(Node::Type::LOOP, "node_loop")
// }; // };
// try
// {
// // Construction de l'AST
// compiler.buildAST(nodes, connections);
// compiler.printAST();
// } catch(const std::exception &e)
// {
// std::cout << e.what() << std::endl;
// }
// Construction de l'AST // Create generator context with current time and user
compiler.buildAST(nodes, connections); AssemblyGenerator::GeneratorContext context(
compiler.displayNodeSchema(); "2025-04-08 12:09:01", // Current UTC time
"arabine", // Current user
true, // Enable debug output
true, // Enable optimizations
1024 // Stack size
);
compiler.generateAssembly(); // Create generator
AssemblyGenerator generator(context);
std::cout << compiler.GetCode() << std::endl;
Chip32::Machine machine; ASTBuilder builder(nodes, connections);
auto pathTrees = builder.BuildAST();
machine.QuickExecute(compiler.GetCode()); /*
// 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
VisualFlowGenerator flowGenerator(context);
std::string flow = flowGenerator.GenerateAssembly(pathTrees);
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
std::cout << "\nGenerated flow:\n" << flow << std::endl;
// Generate assembly
std::string assembly = generator.GenerateAssembly(pathTrees);
// compiler.generateAssembly();
// std::cout << compiler.GetCode() << std::endl;
// Chip32::Machine machine;
// machine.QuickExecute(compiler.GetCode());
// REQUIRE( parseResult == true ); // REQUIRE( parseResult == true );