mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
First working assembly from nodes (cli), youpi
This commit is contained in:
parent
3c1224e937
commit
a42fdc81ea
12 changed files with 229 additions and 302 deletions
|
|
@ -83,9 +83,9 @@ typedef enum
|
||||||
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
||||||
|
|
||||||
// Comparison
|
// 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_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.: cmp_gt r4, r0, r1
|
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.: cmp_lt 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
|
INSTRUCTION_COUNT
|
||||||
} chip32_instruction_t;
|
} chip32_instruction_t;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,25 @@ public:
|
||||||
STRING
|
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
|
// Setters
|
||||||
|
|
||||||
|
|
@ -93,6 +112,10 @@ public:
|
||||||
return m_valueType;
|
return m_valueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetLabel() const {
|
||||||
|
return m_label;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T GetValue() const {
|
T GetValue() const {
|
||||||
try {
|
try {
|
||||||
|
|
@ -108,22 +131,51 @@ public:
|
||||||
return m_uuid;
|
return m_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable() {
|
static std::string GenerateRandomString(size_t length, uint32_t flags)
|
||||||
m_uuid = Uuid().String();
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable (const std::string &name)
|
|
||||||
: Variable()
|
|
||||||
{
|
{
|
||||||
m_variableName = name;
|
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:
|
private:
|
||||||
std::string m_variableName;
|
std::string m_variableName; // nom humain
|
||||||
ValueType m_valueType;
|
ValueType m_valueType;
|
||||||
VariableValue m_value;
|
VariableValue m_value;
|
||||||
bool m_isConstant;
|
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
|
int m_scalePower; // Nombre de bits pour la partie fractionnaire
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -56,30 +56,8 @@ public:
|
||||||
m_currentSection = Section::NONE;
|
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)
|
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();
|
Reset();
|
||||||
|
|
||||||
// Generate header comments
|
// Generate header comments
|
||||||
|
|
@ -109,6 +87,8 @@ protected:
|
||||||
|
|
||||||
virtual void GenerateExit() = 0;
|
virtual void GenerateExit() = 0;
|
||||||
|
|
||||||
|
virtual void GenerateVariable(const std::shared_ptr<Variable> v) = 0;
|
||||||
|
|
||||||
|
|
||||||
std::string AddStringLiteral(const std::string& text)
|
std::string AddStringLiteral(const std::string& text)
|
||||||
{
|
{
|
||||||
|
|
@ -131,7 +111,7 @@ protected:
|
||||||
std::vector<std::string> m_stringLiterals;
|
std::vector<std::string> m_stringLiterals;
|
||||||
int m_depth{0};
|
int m_depth{0};
|
||||||
Section m_currentSection;
|
Section m_currentSection;
|
||||||
std::vector<PathTree> m_roots;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
@ -160,30 +140,18 @@ private:
|
||||||
|
|
||||||
void GenerateDataSection(const std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<Variable>> &variables)
|
void GenerateDataSection(const std::vector<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<Variable>> &variables)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Generate all constants
|
// Generate all constants
|
||||||
for (const auto& n : nodes) {
|
for (const auto& n : nodes) {
|
||||||
n->Accept(*this);
|
n->Accept(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate all variables in RAM
|
||||||
|
for (auto & v : variables)
|
||||||
|
{
|
||||||
|
GenerateVariable(v);
|
||||||
|
}
|
||||||
|
|
||||||
m_assembly << "\n\n";
|
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) {
|
void GenerateTextSection(const std::vector<std::shared_ptr<ASTNode>>& orderedNodes) {
|
||||||
|
|
@ -194,28 +162,12 @@ private:
|
||||||
GenerateNodeCode(node);
|
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
|
// Program exit
|
||||||
GenerateExit();
|
GenerateExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectVariables(std::shared_ptr<ASTNode> node) {
|
void CollectVariables(std::shared_ptr<ASTNode> node)
|
||||||
|
{
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
if (node->IsType<VariableNode>()) {
|
if (node->IsType<VariableNode>()) {
|
||||||
|
|
|
||||||
|
|
@ -21,50 +21,37 @@ public:
|
||||||
if (m_context.debugOutput) {
|
if (m_context.debugOutput) {
|
||||||
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
AddComment("Node: " + node->node->GetTypeName() + " (ID: " + node->node->GetId() + ")");
|
||||||
}
|
}
|
||||||
/*
|
// Node label
|
||||||
if (isDataPath)
|
m_assembly << node->node->GetMyEntryLabel() << ":\n";
|
||||||
{
|
|
||||||
|
|
||||||
|
if (node->IsType<OperatorNode>()) {
|
||||||
// else if (node->IsType<VariableNode>()) {
|
GenerateOperatorNode(node);
|
||||||
// GenerateVariableNode(node);
|
}
|
||||||
// }
|
else if (node->IsType<FunctionEntryNode>()) {
|
||||||
|
GenerateFunctionEntry(node);
|
||||||
|
}
|
||||||
|
else if (node->IsType<BranchNode>()) {
|
||||||
|
GenerateBranchNode(node);
|
||||||
|
}
|
||||||
|
else if (node->IsType<PrintNode>()) {
|
||||||
|
GeneratePrintNode(node);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
*/
|
// // If we're processing a data path, traverse data outputs
|
||||||
if (node->IsType<OperatorNode>()) {
|
// if (isDataPath) {
|
||||||
GenerateOperatorNode(node);
|
// for (const auto& [port, outputs] : node->dataOutputs) {
|
||||||
}
|
// for (const auto& target : outputs) {
|
||||||
else if (node->IsType<FunctionEntryNode>()) {
|
// GenerateNodeCode(target.node, true);
|
||||||
GenerateFunctionEntry(node);
|
// }
|
||||||
}
|
// }
|
||||||
else if (node->IsType<BranchNode>()) {
|
|
||||||
GenerateBranchNode(node);
|
|
||||||
}
|
|
||||||
else if (node->IsType<PrintNode>()) {
|
|
||||||
GeneratePrintNode(node);
|
|
||||||
}
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// If we're processing a data path, traverse data outputs
|
|
||||||
if (isDataPath) {
|
|
||||||
for (const auto& [port, outputs] : node->dataOutputs) {
|
|
||||||
for (const auto& target : outputs) {
|
|
||||||
GenerateNodeCode(target.node, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void AddComment(const std::string& comment) {
|
virtual void AddComment(const std::string& comment) {
|
||||||
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
|
m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void GenerateExit() {
|
virtual void GenerateExit() {
|
||||||
AddComment("Program exit");
|
AddComment("Program exit");
|
||||||
m_assembly << " halt\n";
|
m_assembly << " halt\n";
|
||||||
|
|
@ -74,55 +61,22 @@ private:
|
||||||
|
|
||||||
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
|
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
|
||||||
AddComment("Function Entry");
|
AddComment("Function Entry");
|
||||||
m_depth++;
|
|
||||||
|
|
||||||
// for (auto& child : node->children) {
|
|
||||||
// GenerateNodeCode(child);
|
|
||||||
// }
|
|
||||||
|
|
||||||
m_depth--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateBranchNode(std::shared_ptr<ASTNode> node)
|
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");
|
AddComment("Branch condition evaluation");
|
||||||
m_depth++;
|
m_depth++;
|
||||||
|
|
||||||
// Generate condition code
|
auto trueBranch = node->GetChild(0);
|
||||||
// We search a path tree that have a last node equivalent to our node
|
auto falseBranch = node->GetChild(1);
|
||||||
// (this is the input of the condition)
|
|
||||||
/*
|
|
||||||
auto lastNode = std::find_if(m_roots.begin(), m_roots.end(),
|
|
||||||
[&node](const PathTree& tree) {
|
|
||||||
return tree.lastNode && tree.lastNode->node->GetId() == node->node->GetId();
|
|
||||||
});
|
|
||||||
|
|
||||||
AddComment("Last node: " + lastNode->lastNode->node->GetTypeName() + " (ID: " + lastNode->lastNode->node->GetId() + ")");
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Compare result and jump
|
// Compare result and jump
|
||||||
m_assembly << " pop eax\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " cmp eax, 0\n"
|
<< " skipz r0\n"
|
||||||
<< " je " << labelFalse << "\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--;
|
m_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,8 +106,27 @@ private:
|
||||||
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
|
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
|
||||||
m_depth++;
|
m_depth++;
|
||||||
|
|
||||||
// Generate code for variables
|
// Generate code for variables usage
|
||||||
for (const auto& [port, inputNode] : node->dataInputs) {
|
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";
|
// m_assembly << " load r0, " << inputNode.node->GetId() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,87 +134,45 @@ private:
|
||||||
// Generate operator code
|
// Generate operator code
|
||||||
switch (opNode->GetOperationType()) {
|
switch (opNode->GetOperationType()) {
|
||||||
case OperatorNode::OperationType::ADD:
|
case OperatorNode::OperationType::ADD:
|
||||||
m_assembly << " pop ebx\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " pop eax\n"
|
<< " pop r1\n"
|
||||||
<< " add eax, ebx\n"
|
<< " add r0, r1\n"
|
||||||
<< " push eax\n";
|
<< " push r0\n";
|
||||||
break;
|
break;
|
||||||
case OperatorNode::OperationType::SUBTRACT:
|
case OperatorNode::OperationType::SUBTRACT:
|
||||||
m_assembly << " pop ebx\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " pop eax\n"
|
<< " pop r1\n"
|
||||||
<< " sub eax, ebx\n"
|
<< " sub r0, r1\n"
|
||||||
<< " push eax\n";
|
<< " push r0\n";
|
||||||
break;
|
break;
|
||||||
case OperatorNode::OperationType::MULTIPLY:
|
case OperatorNode::OperationType::MULTIPLY:
|
||||||
m_assembly << " pop ebx\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " pop eax\n"
|
<< " pop r1\n"
|
||||||
<< " imul eax, ebx\n"
|
<< " mul r0, r1\n"
|
||||||
<< " push eax\n";
|
<< " push r0\n";
|
||||||
break;
|
break;
|
||||||
case OperatorNode::OperationType::DIVIDE:
|
case OperatorNode::OperationType::DIVIDE:
|
||||||
m_assembly << " pop ebx\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " pop eax\n"
|
<< " pop r1\n"
|
||||||
<< " cdq\n"
|
<< " div r0, r1\n"
|
||||||
<< " idiv ebx\n"
|
<< " push r0\n";
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
break;
|
||||||
// Add other operators...
|
case OperatorNode::OperationType::AND:
|
||||||
|
m_assembly << " pop r0\n"
|
||||||
/*
|
<< " pop r1\n"
|
||||||
|
<< " and r0, r1\n"
|
||||||
|
<< " push r0\n";
|
||||||
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;
|
break;
|
||||||
case OperationType::SUBTRACT:
|
case OperatorNode::OperationType::GREATER_THAN:
|
||||||
ss << " pop ebx\n"
|
m_assembly << " pop r0\n"
|
||||||
<< " pop eax\n"
|
<< " pop r1\n"
|
||||||
<< " sub eax, ebx\n"
|
<< " gt r0, r0, r1\n"
|
||||||
<< " push eax\n";
|
<< " push r0\n";
|
||||||
break;
|
break;
|
||||||
case OperationType::MULTIPLY:
|
default:
|
||||||
ss << " pop ebx\n"
|
// Make voluntary bad assembly
|
||||||
<< " pop eax\n"
|
m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n";
|
||||||
<< " imul eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
break;
|
||||||
case OperationType::DIVIDE:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " cdq\n" // Sign extend eax into edx
|
|
||||||
<< " idiv ebx\n"
|
|
||||||
<< " push eax\n"; // Push quotient
|
|
||||||
break;
|
|
||||||
case OperationType::AND:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " and eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
case OperationType::OR:
|
|
||||||
ss << " pop ebx\n"
|
|
||||||
<< " pop eax\n"
|
|
||||||
<< " or eax, ebx\n"
|
|
||||||
<< " push eax\n";
|
|
||||||
break;
|
|
||||||
// Add other operators...
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_depth--;
|
m_depth--;
|
||||||
|
|
@ -253,23 +184,44 @@ private:
|
||||||
{
|
{
|
||||||
if (v->GetValueType() == Variable::ValueType::STRING)
|
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)
|
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)
|
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)
|
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) {
|
void GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
||||||
auto* varNode = node->GetAs<VariableNode>();
|
auto* varNode = node->GetAs<VariableNode>();
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
class ASTBuilder {
|
||||||
public:
|
public:
|
||||||
|
|
@ -194,7 +188,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return topologicalOrder;
|
// 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<BaseNode>>& m_nodes;
|
||||||
const std::vector<std::shared_ptr<Connection>>& m_connections;
|
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)
|
std::vector<std::shared_ptr<ASTNode>> ApplyKahnAlgorithm(const std::unordered_map<std::string, std::shared_ptr<ASTNode>> &nodeMap)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ protected:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void GenerateVariable(const std::shared_ptr<Variable> v) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
virtual void GenerateExit() {
|
virtual void GenerateExit() {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,44 +19,6 @@ BaseNode::~BaseNode()
|
||||||
std::cout << "Deleted base node" << std::endl;
|
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)
|
std::string BaseNode::GetEntryLabel(const std::string &id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,6 @@ public:
|
||||||
float y;
|
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
|
struct ConstantValue
|
||||||
{
|
{
|
||||||
|
|
@ -123,8 +115,6 @@ public:
|
||||||
void SetInternalData(const nlohmann::json &j);
|
void SetInternalData(const nlohmann::json &j);
|
||||||
nlohmann::json GetInternalData() const;
|
nlohmann::json GetInternalData() const;
|
||||||
|
|
||||||
static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS);
|
|
||||||
|
|
||||||
void ClearPorts() {
|
void ClearPorts() {
|
||||||
m_inputPorts.clear();
|
m_inputPorts.clear();
|
||||||
m_outputPorts.clear();
|
m_outputPorts.clear();
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ public:
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
|
|
||||||
virtual std::string GenerateAssembly() const { return ""; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,15 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
|
#include "variable.h"
|
||||||
|
|
||||||
PrintNode::PrintNode(const std::string &type)
|
PrintNode::PrintNode(const std::string &type)
|
||||||
: BaseNode(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
|
// Create empty variable in memory
|
||||||
auto v = std::make_shared<Variable>(m_label);
|
auto v = std::make_shared<Variable>(m_label);
|
||||||
v->SetTextValue("");
|
v->SetTextValue("");
|
||||||
|
m_label = v->GetLabel();
|
||||||
m_variables[m_label] = v;
|
m_variables[m_label] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,18 @@ public:
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
|
||||||
|
|
||||||
virtual std::string GenerateAssembly() const { return ""; }
|
|
||||||
|
|
||||||
void StoreInternalData();
|
void StoreInternalData();
|
||||||
|
|
||||||
void SetVariableUuid(const std::string &uuid) {
|
void SetVariable(const std::shared_ptr<Variable> v) {
|
||||||
m_variableUuid = uuid;
|
m_variable = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetVariableUuid() const {
|
std::shared_ptr<Variable> GetVariable() const {
|
||||||
return m_variableUuid;
|
return m_variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_variableUuid;
|
std::shared_ptr<Variable> m_variable;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,16 +84,16 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
variables.push_back(var4);
|
variables.push_back(var4);
|
||||||
|
|
||||||
auto variableNodeX = std::make_shared<VariableNode>("variable-node");
|
auto variableNodeX = std::make_shared<VariableNode>("variable-node");
|
||||||
variableNodeX->SetVariableUuid(var1->GetUuid());
|
variableNodeX->SetVariable(var1);
|
||||||
|
|
||||||
auto variableNodeY = std::make_shared<VariableNode>("variable-node");
|
auto variableNodeY = std::make_shared<VariableNode>("variable-node");
|
||||||
variableNodeY->SetVariableUuid(var2->GetUuid());
|
variableNodeY->SetVariable(var2);
|
||||||
|
|
||||||
auto variableNodeA = std::make_shared<VariableNode>("variable-node");
|
auto variableNodeA = std::make_shared<VariableNode>("variable-node");
|
||||||
variableNodeA->SetVariableUuid(var3->GetUuid());
|
variableNodeA->SetVariable(var3);
|
||||||
|
|
||||||
auto variableNodeB = std::make_shared<VariableNode>("variable-node");
|
auto variableNodeB = std::make_shared<VariableNode>("variable-node");
|
||||||
variableNodeB->SetVariableUuid(var4->GetUuid());
|
variableNodeB->SetVariable(var4);
|
||||||
|
|
||||||
auto testNode = std::make_shared<OperatorNode>();
|
auto testNode = std::make_shared<OperatorNode>();
|
||||||
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
|
testNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
|
||||||
|
|
@ -227,25 +227,24 @@ TEST_CASE( "Check various indentations and typos" ) {
|
||||||
|
|
||||||
|
|
||||||
ASTBuilder builder(nodes, connections);
|
ASTBuilder builder(nodes, connections);
|
||||||
auto pathTrees = builder.BuildAST();
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
// Generate flow in the console
|
// Generate flow in the console
|
||||||
VisualFlowGenerator flowGenerator(context);
|
VisualFlowGenerator flowGenerator(context);
|
||||||
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
|
FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01");
|
||||||
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTrees, variables);
|
std::string flow = flowGenerator.GenerateAssembly(nodes, pathTree, variables);
|
||||||
|
|
||||||
|
|
||||||
std::cout << "\nGenerated flow:\n" << flow << std::endl;
|
std::cout << "\nGenerated flow:\n" << flow << std::endl;
|
||||||
|
|
||||||
// Generate assembly
|
// Generate assembly
|
||||||
std::string assembly = generator.GenerateAssembly(nodes, pathTrees, variables);
|
std::string assembly = generator.GenerateAssembly(nodes, pathTree, variables);
|
||||||
|
|
||||||
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
|
std::cout << "\nGenerated assembly:\n" << assembly << std::endl;
|
||||||
|
|
||||||
// Chip32::Machine machine;
|
Chip32::Machine machine;
|
||||||
|
|
||||||
// machine.QuickExecute(compiler.GetCode());
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
// REQUIRE( parseResult == true );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue