First working assembly from nodes (cli), youpi

This commit is contained in:
anthony@rabine.fr 2025-04-22 23:20:44 +02:00
parent 3c1224e937
commit a42fdc81ea
12 changed files with 229 additions and 302 deletions

View file

@ -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;

View file

@ -17,6 +17,25 @@ public:
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
};
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
@ -93,6 +112,10 @@ public:
return m_valueType;
}
std::string GetLabel() const {
return m_label;
}
template<typename T>
T GetValue() const {
try {
@ -108,22 +131,51 @@ public:
return m_uuid;
}
Variable() {
m_uuid = Uuid().String();
static std::string GenerateRandomString(size_t length, uint32_t flags)
{
std::string charset = "";
if (flags & CHARSET_ALPHABET_LOWER)
{
charset += "abcdefghijklmnopqrstuvwxyz";
}
Variable (const std::string &name)
: Variable()
if (flags & CHARSET_ALPHABET_UPPER)
{
m_variableName = name;
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;
std::string m_variableName; // nom humain
ValueType m_valueType;
VariableValue m_value;
bool m_isConstant;
std::string m_uuid;
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
};

View file

@ -56,30 +56,8 @@ public:
m_currentSection = Section::NONE;
}
std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<PathTree>& roots, const std::vector<std::shared_ptr<Variable>> &variables)
{
m_roots = roots;
/*
Reset();
// Generate header comments
GenerateHeader();
// Generate data section
StartSection(Section::DATA);
GenerateDataSection(nodes, roots, variables);
// Generate text section
StartSection(Section::TEXT);
GenerateTextSection(roots);
*/
return m_assembly.str();
}
std::string GenerateAssembly(std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<ASTNode>>& order, const std::vector<std::shared_ptr<Variable>> &variables)
{
// m_roots = roots;
Reset();
// Generate header comments
@ -109,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)
{
@ -131,7 +111,7 @@ protected:
std::vector<std::string> m_stringLiterals;
int m_depth{0};
Section m_currentSection;
std::vector<PathTree> m_roots;
private:
@ -160,30 +140,18 @@ private:
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) {
n->Accept(*this);
}
// generate all variables in RAM
for (auto & v : variables)
{
GenerateVariable(v);
}
m_assembly << "\n\n";
// Generate all
/*
// 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 GenerateTextSection(const std::vector<std::shared_ptr<ASTNode>>& orderedNodes) {
@ -194,28 +162,12 @@ private:
GenerateNodeCode(node);
}
/*
// 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 CollectVariables(std::shared_ptr<ASTNode> node) {
void CollectVariables(std::shared_ptr<ASTNode> node)
{
if (!node) return;
if (node->IsType<VariableNode>()) {

View file

@ -21,19 +21,9 @@ public:
if (m_context.debugOutput) {
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
}
/*
if (isDataPath)
{
// Node label
m_assembly << node->node->GetMyEntryLabel() << ":\n";
// else if (node->IsType<VariableNode>()) {
// GenerateVariableNode(node);
// }
}
else
{
*/
if (node->IsType<OperatorNode>()) {
GenerateOperatorNode(node);
}
@ -46,16 +36,15 @@ public:
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);
// }
// }
// }
}
@ -63,8 +52,6 @@ public:
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
}
virtual void GenerateExit() {
AddComment("Program exit");
m_assembly << " halt\n";
@ -74,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--;
}
@ -152,8 +106,27 @@ private:
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
m_depth++;
// Generate code for variables
for (const auto& [port, inputNode] : node->dataInputs) {
// 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";
}
@ -161,87 +134,45 @@ private:
// 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;
// Add other operators...
/*
std::string GenerateAssembly() const override {
std::stringstream ss;
switch (m_operationType) {
case OperationType::ADD:
ss << " pop ebx\n"
<< " pop eax\n"
<< " add eax, ebx\n"
<< " push eax\n";
case OperatorNode::OperationType::AND:
m_assembly << " pop r0\n"
<< " pop r1\n"
<< " and r0, r1\n"
<< " push r0\n";
break;
case OperationType::SUBTRACT:
ss << " pop ebx\n"
<< " pop eax\n"
<< " sub eax, ebx\n"
<< " push eax\n";
case OperatorNode::OperationType::GREATER_THAN:
m_assembly << " pop r0\n"
<< " pop r1\n"
<< " gt r0, r0, r1\n"
<< " push r0\n";
break;
case OperationType::MULTIPLY:
ss << " pop ebx\n"
<< " pop eax\n"
<< " imul eax, ebx\n"
<< " push eax\n";
default:
// Make voluntary bad assembly
m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n";
break;
case OperationType::DIVIDE:
ss << " pop ebx\n"
<< " pop eax\n"
<< " cdq\n" // Sign extend eax into edx
<< " idiv ebx\n"
<< " push eax\n"; // Push quotient
break;
case OperationType::AND:
ss << " pop ebx\n"
<< " pop eax\n"
<< " and eax, ebx\n"
<< " push eax\n";
break;
case OperationType::OR:
ss << " pop ebx\n"
<< " pop eax\n"
<< " or eax, ebx\n"
<< " push eax\n";
break;
// Add other operators...
}
return ss.str();
}
*/
}
m_depth--;
@ -253,23 +184,44 @@ private:
{
if (v->GetValueType() == Variable::ValueType::STRING)
{
m_assembly << "$" << v->GetVariableName() << " DC8, \"" << v->GetValue<std::string>() << "\"\n";
m_assembly << "$" << v->GetLabel() << " DC8, \"" << v->GetValue<std::string>() << "\" ; " << v->GetVariableName() << "\n";
}
else if (v->GetValueType() == Variable::ValueType::INTEGER)
{
m_assembly << "$" << v->GetVariableName() << " DC32, " << v->GetValue<int>() << "\n";
m_assembly << "$" << v->GetLabel() << " DC32, " << v->GetValue<int>() << " ; " << v->GetVariableName() << "\n";
}
else if (v->GetValueType() == Variable::ValueType::FLOAT)
{
m_assembly << "$" << v->GetVariableName() << " DC32, " << v->GetValue<float>() << "\n";
m_assembly << "$" << v->GetLabel() << " DC32, " << v->GetValue<float>() << " ; " << v->GetVariableName() << "\n";
}
else if (v->GetValueType() == Variable::ValueType::BOOL)
{
m_assembly << "$" << v->GetVariableName() << " DCB, " << (v->GetValue<bool>() ? "1" : "0") << "\n";
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>();

View file

@ -144,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:
@ -194,6 +188,9 @@ public:
}
}
// Build execution paths
BuildExecutionPath(topologicalOrder, nodeMap);
return topologicalOrder;
}
@ -202,7 +199,32 @@ 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)
{

View file

@ -66,6 +66,9 @@ protected:
}
virtual void GenerateVariable(const std::shared_ptr<Variable> v) {
}
virtual void GenerateExit() {

View file

@ -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)
{

View file

@ -44,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
{
@ -123,8 +115,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();

View file

@ -14,8 +14,6 @@ public:
virtual void Initialize() override;
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
virtual std::string GenerateAssembly() const { return ""; }
private:
};

View file

@ -2,16 +2,15 @@
#include "story_project.h"
#include "connection.h"
#include "sys_lib.h"
#include "variable.h"
PrintNode::PrintNode(const std::string &type)
: 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;
}

View file

@ -17,20 +17,18 @@ public:
virtual void Initialize() override;
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
virtual std::string GenerateAssembly() const { return ""; }
void StoreInternalData();
void SetVariableUuid(const std::string &uuid) {
m_variableUuid = uuid;
void SetVariable(const std::shared_ptr<Variable> v) {
m_variable = v;
}
std::string GetVariableUuid() const {
return m_variableUuid;
std::shared_ptr<Variable> GetVariable() const {
return m_variable;
}
private:
std::string m_variableUuid;
std::shared_ptr<Variable> m_variable;
};

View file

@ -84,16 +84,16 @@ TEST_CASE( "Check various indentations and typos" ) {
variables.push_back(var4);
auto variableNodeX = std::make_shared<VariableNode>("variable-node");
variableNodeX->SetVariableUuid(var1->GetUuid());
variableNodeX->SetVariable(var1);
auto variableNodeY = std::make_shared<VariableNode>("variable-node");
variableNodeY->SetVariableUuid(var2->GetUuid());
variableNodeY->SetVariable(var2);
auto variableNodeA = std::make_shared<VariableNode>("variable-node");
variableNodeA->SetVariableUuid(var3->GetUuid());
variableNodeA->SetVariable(var3);
auto variableNodeB = std::make_shared<VariableNode>("variable-node");
variableNodeB->SetVariableUuid(var4->GetUuid());
variableNodeB->SetVariable(var4);
auto testNode = std::make_shared<OperatorNode>();
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
@ -227,25 +227,24 @@ TEST_CASE( "Check various indentations and typos" ) {
ASTBuilder builder(nodes, connections);
auto pathTrees = builder.BuildAST();
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, variables);
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, variables);
std::string assembly = generator.GenerateAssembly(nodes, pathTree, variables);
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
// Chip32::Machine machine;
Chip32::Machine machine;
// machine.QuickExecute(compiler.GetCode());
machine.QuickExecute(assembly);
// REQUIRE( parseResult == true );
}