mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Fixed data connection, compilation order and print format
This commit is contained in:
parent
eb08627029
commit
741a3c633e
16 changed files with 358 additions and 430 deletions
|
|
@ -33,7 +33,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lecture d'une chaîne depuis la mémoire (non statique maintenant)
|
// Lecture d'une chaîne depuis la mémoire (non statique maintenant)
|
||||||
std::string GetStringFromMemory(chip32_ctx_t *ctx, uint32_t addr)
|
static std::string GetStringFromMemory(chip32_ctx_t *ctx, uint32_t addr)
|
||||||
{
|
{
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
throw std::runtime_error("Invalid context in GetStringFromMemory");
|
throw std::runtime_error("Invalid context in GetStringFromMemory");
|
||||||
|
|
@ -73,66 +73,101 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatter avec nombre variable d'arguments (non statique)
|
static std::string FormatStringWithPlaceholders(chip32_ctx_t *ctx,
|
||||||
std::string FormatString(const std::string& format,
|
const std::string& format,
|
||||||
const std::vector<uint32_t>& args)
|
const std::vector<uint32_t>& args)
|
||||||
{
|
{
|
||||||
if (args.empty()) {
|
std::ostringstream result;
|
||||||
return format;
|
size_t pos = 0;
|
||||||
|
|
||||||
|
while (pos < format.length()) {
|
||||||
|
// Chercher le prochain placeholder '{'
|
||||||
|
if (format[pos] == '{' && pos + 1 < format.length()) {
|
||||||
|
char nextChar = format[pos + 1];
|
||||||
|
|
||||||
|
// Vérifier si c'est un placeholder valide {0} à {3}
|
||||||
|
if (nextChar >= '0' && nextChar <= '3') {
|
||||||
|
int argIndex = nextChar - '0';
|
||||||
|
|
||||||
|
// Vérifier si on a assez d'arguments
|
||||||
|
if (argIndex >= static_cast<int>(args.size())) {
|
||||||
|
result << "{" << argIndex << ":?}"; // Argument manquant
|
||||||
|
pos += 2;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> buffer(1024);
|
uint32_t argValue = args[argIndex];
|
||||||
int result = -1;
|
|
||||||
|
|
||||||
switch (args.size()) {
|
// Vérifier s'il y a un type spécifié {:d}, {:s}, {:f}, {:x}
|
||||||
case 1:
|
if (pos + 3 < format.length() && format[pos + 2] == ':') {
|
||||||
result = std::snprintf(buffer.data(), buffer.size(),
|
char typeChar = format[pos + 3];
|
||||||
format.c_str(), args[0]);
|
|
||||||
|
// Vérifier si le placeholder se termine bien par '}'
|
||||||
|
if (pos + 4 < format.length() && format[pos + 4] == '}') {
|
||||||
|
// Parser le type et formater
|
||||||
|
switch (typeChar) {
|
||||||
|
case 'd': // Entier décimal signé
|
||||||
|
case 'i':
|
||||||
|
result << static_cast<int32_t>(argValue);
|
||||||
break;
|
break;
|
||||||
case 2:
|
|
||||||
result = std::snprintf(buffer.data(), buffer.size(),
|
case 'u': // Entier non signé
|
||||||
format.c_str(), args[0], args[1]);
|
result << argValue;
|
||||||
break;
|
break;
|
||||||
case 3:
|
|
||||||
result = std::snprintf(buffer.data(), buffer.size(),
|
case 'x': // Hexadécimal minuscule
|
||||||
format.c_str(), args[0], args[1], args[2]);
|
result << "0x" << std::hex << argValue << std::dec;
|
||||||
break;
|
break;
|
||||||
case 4:
|
|
||||||
result = std::snprintf(buffer.data(), buffer.size(),
|
case 'X': // Hexadécimal majuscule
|
||||||
format.c_str(), args[0], args[1], args[2], args[3]);
|
result << "0x" << std::hex << std::uppercase
|
||||||
|
<< argValue << std::nouppercase << std::dec;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's': // String (adresse)
|
||||||
|
try {
|
||||||
|
result << GetStringFromMemory(ctx, argValue);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
result << "<error:0x" << std::hex << argValue << std::dec << ">";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f': // Float
|
||||||
|
{
|
||||||
|
float floatValue;
|
||||||
|
std::memcpy(&floatValue, &argValue, sizeof(float));
|
||||||
|
result << floatValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'c': // Caractère
|
||||||
|
result << static_cast<char>(argValue);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Too many arguments for printf (max 4)");
|
// Type inconnu, afficher tel quel
|
||||||
|
result << "{" << argIndex << ":" << typeChar << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result < 0) {
|
pos += 5; // Avancer de "{0:d}"
|
||||||
throw std::runtime_error("Error formatting string");
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Format court {0} sans type → défaut: entier
|
||||||
|
else if (pos + 2 < format.length() && format[pos + 2] == '}') {
|
||||||
|
result << static_cast<int32_t>(argValue);
|
||||||
|
pos += 3; // Avancer de "{0}"
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<size_t>(result) >= buffer.size()) {
|
|
||||||
buffer.resize(result + 1);
|
|
||||||
|
|
||||||
switch (args.size()) {
|
|
||||||
case 1:
|
|
||||||
std::snprintf(buffer.data(), buffer.size(),
|
|
||||||
format.c_str(), args[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
std::snprintf(buffer.data(), buffer.size(),
|
|
||||||
format.c_str(), args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
std::snprintf(buffer.data(), buffer.size(),
|
|
||||||
format.c_str(), args[0], args[1], args[2]);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
std::snprintf(buffer.data(), buffer.size(),
|
|
||||||
format.c_str(), args[0], args[1], args[2], args[3]);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string(buffer.data());
|
// Caractère normal, copier tel quel
|
||||||
|
result << format[pos];
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler de syscall (méthode membre, non statique)
|
// Handler de syscall (méthode membre, non statique)
|
||||||
|
|
@ -149,7 +184,7 @@ public:
|
||||||
args.push_back(ctx->registers[R2 + i]);
|
args.push_back(ctx->registers[R2 + i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printOutput = FormatString(format, args);
|
printOutput = FormatStringWithPlaceholders(ctx, format, args);
|
||||||
std::cout << "[SYSCALL PRINT] " << printOutput << std::endl;
|
std::cout << "[SYSCALL PRINT] " << printOutput << std::endl;
|
||||||
}
|
}
|
||||||
else if (code == 5) // WAIT
|
else if (code == 5) // WAIT
|
||||||
|
|
|
||||||
|
|
@ -284,10 +284,28 @@ private:
|
||||||
m_assembly << " lcons " << targetReg << ", " << op->GetValue() << "\n";
|
m_assembly << " lcons " << targetReg << ", " << op->GetValue() << "\n";
|
||||||
return targetReg;
|
return targetReg;
|
||||||
|
|
||||||
case TACOperand::Type::VARIABLE:
|
case TACOperand::Type::VARIABLE: {
|
||||||
|
std::shared_ptr<Variable> var = nullptr;
|
||||||
|
|
||||||
|
// Chercher la variable par son label
|
||||||
|
for (const auto& v : m_context.variables) {
|
||||||
|
if (v->GetLabel() == op->GetValue()) {
|
||||||
|
var = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var && var->GetValueType() == Variable::ValueType::STRING) {
|
||||||
|
// Pour les strings, charger l'ADRESSE
|
||||||
|
m_assembly << " lcons " << targetReg << ", $" << op->GetValue() << "\n";
|
||||||
|
} else {
|
||||||
|
// Pour les autres types, charger la VALEUR
|
||||||
m_assembly << " load " << targetReg << ", $" << op->GetValue() << ", 4\n";
|
m_assembly << " load " << targetReg << ", $" << op->GetValue() << ", 4\n";
|
||||||
|
}
|
||||||
return targetReg;
|
return targetReg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
case TACOperand::Type::TEMPORARY: {
|
case TACOperand::Type::TEMPORARY: {
|
||||||
auto it = m_tempLocations.find(op->GetValue());
|
auto it = m_tempLocations.find(op->GetValue());
|
||||||
if (it == m_tempLocations.end()) {
|
if (it == m_tempLocations.end()) {
|
||||||
|
|
@ -542,16 +560,6 @@ private:
|
||||||
case Variable::ValueType::STRING: {
|
case Variable::ValueType::STRING: {
|
||||||
std::string value = v->GetValue<std::string>();
|
std::string value = v->GetValue<std::string>();
|
||||||
|
|
||||||
// Convertir {0} {1} {2} {3} en %d
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
std::string placeholder = "{" + std::to_string(i) + "}";
|
|
||||||
size_t pos = 0;
|
|
||||||
while ((pos = value.find(placeholder, pos)) != std::string::npos) {
|
|
||||||
value.replace(pos, placeholder.length(), "%d");
|
|
||||||
pos += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_assembly << "$" << v->GetLabel() << " DC8, \""
|
m_assembly << "$" << v->GetLabel() << " DC8, \""
|
||||||
<< value << "\" ; " << v->GetVariableName() << "\n";
|
<< value << "\" ; " << v->GetVariableName() << "\n";
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -183,11 +183,17 @@ public:
|
||||||
// Maintenant, on va ajouter les connexions de données
|
// Maintenant, on va ajouter les connexions de données
|
||||||
for (const auto& conn : m_connections)
|
for (const auto& conn : m_connections)
|
||||||
{
|
{
|
||||||
|
std::cout << ">>> ASTBuilder: Processing connection from " << conn->outNodeId
|
||||||
|
<< " to " << conn->inNodeId
|
||||||
|
<< " type=" << conn->type << " (0=EXEC, 1=DATA)" << std::endl;
|
||||||
|
|
||||||
// Ne traiter que les connexions DATA_LINK
|
// Ne traiter que les connexions DATA_LINK
|
||||||
if (conn->type != Connection::DATA_LINK) {
|
if (conn->type != Connection::DATA_LINK) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << " -> Adding DATA connection!" << std::endl;
|
||||||
|
|
||||||
auto outNode = nodeMap[conn->outNodeId];
|
auto outNode = nodeMap[conn->outNodeId];
|
||||||
auto inNode = nodeMap[conn->inNodeId];
|
auto inNode = nodeMap[conn->inNodeId];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -460,10 +460,19 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<TACOperand> GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
std::shared_ptr<TACOperand> GenerateVariableNode(std::shared_ptr<ASTNode> node) {
|
||||||
auto* varNode = node->GetAs<VariableNode>();
|
auto* varNode = node->GetAs<VariableNode>();
|
||||||
if (!varNode) return nullptr;
|
if (!varNode) {
|
||||||
|
std::cout << " ERROR: node is not a VariableNode!\n";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto var = varNode->GetVariable();
|
auto var = varNode->GetVariable();
|
||||||
if (!var) return nullptr;
|
|
||||||
|
if (!var) {
|
||||||
|
std::cout << " ERROR: Variable is NULL for node " << varNode->GetId()
|
||||||
|
<< " (UUID: " << varNode->GetVariableUuid() << ")\n";
|
||||||
|
std::cout << " This should have been resolved before TAC generation!\n";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Créer une opérande qui référence la variable
|
// Créer une opérande qui référence la variable
|
||||||
return std::make_shared<TACOperand>(
|
return std::make_shared<TACOperand>(
|
||||||
|
|
@ -552,17 +561,12 @@ private:
|
||||||
|
|
||||||
std::cout << " GeneratePrintNode: START\n";
|
std::cout << " GeneratePrintNode: START\n";
|
||||||
|
|
||||||
// Créer l'opérande pour la chaîne de format
|
// RÉCUPÉRER ET CONVERTIR LE FORMAT STRING
|
||||||
auto formatOperand = std::make_shared<TACOperand>(
|
std::string formatString = printNode->GetText();
|
||||||
TACOperand::Type::VARIABLE,
|
|
||||||
printNode->GetLabel()
|
|
||||||
);
|
|
||||||
|
|
||||||
std::cout << " Format string label: " << printNode->GetLabel() << "\n";
|
// Évaluer tous les arguments et déterminer leurs types
|
||||||
std::cout << " Number of data inputs: " << node->dataInputs.size() << "\n";
|
|
||||||
|
|
||||||
// Évaluer tous les arguments
|
|
||||||
std::vector<std::shared_ptr<TACOperand>> args;
|
std::vector<std::shared_ptr<TACOperand>> args;
|
||||||
|
std::vector<Variable::ValueType> argTypes;
|
||||||
|
|
||||||
// Collecter et trier les inputs par port index
|
// Collecter et trier les inputs par port index
|
||||||
std::vector<std::pair<unsigned int, std::shared_ptr<ASTNode>>> sortedInputs;
|
std::vector<std::pair<unsigned int, std::shared_ptr<ASTNode>>> sortedInputs;
|
||||||
|
|
@ -574,18 +578,76 @@ private:
|
||||||
std::sort(sortedInputs.begin(), sortedInputs.end(),
|
std::sort(sortedInputs.begin(), sortedInputs.end(),
|
||||||
[](const auto& a, const auto& b) { return a.first < b.first; });
|
[](const auto& a, const auto& b) { return a.first < b.first; });
|
||||||
|
|
||||||
// Générer le code pour chaque argument
|
// Générer le code pour chaque argument ET récupérer son type
|
||||||
for (const auto& [port, inputNode] : sortedInputs) {
|
for (const auto& [port, inputNode] : sortedInputs) {
|
||||||
std::cout << " Processing input port " << port << "\n";
|
std::cout << " Processing input port " << port << "\n";
|
||||||
auto argOperand = GenerateNode(inputNode);
|
auto argOperand = GenerateNode(inputNode);
|
||||||
if (argOperand) {
|
if (argOperand) {
|
||||||
std::cout << " -> Got operand: " << argOperand->ToString() << "\n";
|
std::cout << " -> Got operand: " << argOperand->ToString() << "\n";
|
||||||
args.push_back(argOperand);
|
args.push_back(argOperand);
|
||||||
|
|
||||||
|
// DÉTERMINER LE TYPE DE L'ARGUMENT
|
||||||
|
Variable::ValueType argType = Variable::ValueType::INTEGER; // défaut
|
||||||
|
|
||||||
|
if (inputNode->IsType<VariableNode>()) {
|
||||||
|
auto* varNode = inputNode->GetAs<VariableNode>();
|
||||||
|
auto var = varNode->GetVariable();
|
||||||
|
if (var) {
|
||||||
|
argType = var->GetValueType();
|
||||||
|
std::cout << " -> Variable type: "
|
||||||
|
<< Variable::ValueTypeToString(argType) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pour les OperatorNode, le résultat est toujours un INTEGER
|
||||||
|
else if (inputNode->IsType<OperatorNode>()) {
|
||||||
|
argType = Variable::ValueType::INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
argTypes.push_back(argType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << " Total args collected: " << args.size() << "\n";
|
std::cout << " Total args collected: " << args.size() << "\n";
|
||||||
|
|
||||||
|
// CONVERTIR LES PLACEHOLDERS EN FONCTION DU TYPE
|
||||||
|
for (size_t i = 0; i < argTypes.size() && i < 4; i++) {
|
||||||
|
std::string placeholder = "{" + std::to_string(i) + "}";
|
||||||
|
std::string formatSpec;
|
||||||
|
|
||||||
|
switch (argTypes[i]) {
|
||||||
|
case Variable::ValueType::STRING:
|
||||||
|
formatSpec = "{" + std::to_string(i) + ":s}";
|
||||||
|
break;
|
||||||
|
case Variable::ValueType::INTEGER:
|
||||||
|
formatSpec = "{" + std::to_string(i) + ":d}";
|
||||||
|
break;
|
||||||
|
case Variable::ValueType::FLOAT:
|
||||||
|
formatSpec = "{" + std::to_string(i) + ":f}";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
formatSpec = "{" + std::to_string(i) + ":d}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remplacer {0} par {0:d} ou {0:s}
|
||||||
|
size_t pos = formatString.find(placeholder);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
formatString.replace(pos, placeholder.length(), formatSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// METTRE À JOUR LE FORMAT STRING DANS LA VARIABLE
|
||||||
|
auto formatVar = printNode->GetVariable(printNode->GetLabel());
|
||||||
|
if (formatVar) {
|
||||||
|
formatVar->SetTextValue(formatString);
|
||||||
|
std::cout << " Updated format string to: " << formatString << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer l'opérande pour la chaîne de format (avec le format mis à jour)
|
||||||
|
auto formatOperand = std::make_shared<TACOperand>(
|
||||||
|
TACOperand::Type::VARIABLE,
|
||||||
|
printNode->GetLabel()
|
||||||
|
);
|
||||||
|
|
||||||
// Générer les instructions PARAM pour chaque argument
|
// Générer les instructions PARAM pour chaque argument
|
||||||
for (size_t i = 0; i < args.size(); i++) {
|
for (size_t i = 0; i < args.size(); i++) {
|
||||||
std::cout << " Generating PARAM instruction [" << i << "] for "
|
std::cout << " Generating PARAM instruction [" << i << "] for "
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ void to_json(nlohmann::json &j, const Connection &p) {
|
||||||
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
||||||
{"inNodeId", p.inNodeId},
|
{"inNodeId", p.inNodeId},
|
||||||
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
||||||
|
{"type", static_cast<int>(p.type)}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,4 +16,11 @@ void from_json(const nlohmann::json &j, Connection &p) {
|
||||||
p.inNodeId = j["inNodeId"].get<std::string>();
|
p.inNodeId = j["inNodeId"].get<std::string>();
|
||||||
p.outPortIndex = j["outPortIndex"].get<int>();
|
p.outPortIndex = j["outPortIndex"].get<int>();
|
||||||
p.inPortIndex = j["inPortIndex"].get<int>();
|
p.inPortIndex = j["inPortIndex"].get<int>();
|
||||||
|
|
||||||
|
if (j.contains("type")) {
|
||||||
|
p.type = static_cast<Connection::Type>(j["type"].get<int>());
|
||||||
|
} else {
|
||||||
|
// Par défaut EXECUTION_LINK pour les anciens fichiers
|
||||||
|
p.type = Connection::EXECUTION_LINK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,24 @@ struct Connection
|
||||||
std::string inNodeId;
|
std::string inNodeId;
|
||||||
unsigned int inPortIndex{0};
|
unsigned int inPortIndex{0};
|
||||||
|
|
||||||
Connection(const Connection &other){
|
Connection(const Connection &other)
|
||||||
*this = other;
|
: type(other.type)
|
||||||
|
, outNodeId(other.outNodeId)
|
||||||
|
, outPortIndex(other.outPortIndex)
|
||||||
|
, inNodeId(other.inNodeId)
|
||||||
|
, inPortIndex(other.inPortIndex)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection& operator=(const Connection& other) {
|
Connection& operator=(const Connection& other) {
|
||||||
|
if (this != &other) {
|
||||||
this->outNodeId = other.outNodeId;
|
this->outNodeId = other.outNodeId;
|
||||||
this->outPortIndex = other.outPortIndex;
|
this->outPortIndex = other.outPortIndex;
|
||||||
this->inNodeId = other.inNodeId;
|
this->inNodeId = other.inNodeId;
|
||||||
this->inPortIndex = other.inPortIndex;
|
this->inPortIndex = other.inPortIndex;
|
||||||
|
this->type = other.type;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -45,7 +54,7 @@ struct Connection
|
||||||
inline bool operator==(Connection const &a, Connection const &b)
|
inline bool operator==(Connection const &a, Connection const &b)
|
||||||
{
|
{
|
||||||
return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex
|
return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex
|
||||||
&& a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex;
|
&& a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex && a.type == b.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(Connection const &a, Connection const &b)
|
inline bool operator!=(Connection const &a, Connection const &b)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,14 @@ public:
|
||||||
|
|
||||||
static constexpr int MAX_INPUT_COUNT = 4;
|
static constexpr int MAX_INPUT_COUNT = 4;
|
||||||
|
|
||||||
|
std::shared_ptr<Variable> GetVariable(const std::string& label) const {
|
||||||
|
auto it = m_variables.find(label);
|
||||||
|
if (it != m_variables.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_label; // Label for the string literal
|
std::string m_label; // Label for the string literal
|
||||||
};
|
};
|
||||||
|
|
@ -46,3 +46,32 @@ std::shared_ptr<Variable> VariableNode::GetVariable() const
|
||||||
{
|
{
|
||||||
return m_variable;
|
return m_variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VariableNode::ResolveVariable(const std::vector<std::shared_ptr<Variable>>& variables)
|
||||||
|
{
|
||||||
|
// Si la variable est déjà résolue, pas besoin de chercher
|
||||||
|
if (m_variable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas d'UUID, impossible de résoudre
|
||||||
|
if (m_variableUuid.empty()) {
|
||||||
|
std::cout << "WARNING: VariableNode " << GetId()
|
||||||
|
<< " has no variable UUID!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chercher la variable correspondant à l'UUID
|
||||||
|
for (const auto& var : variables) {
|
||||||
|
if (var->GetUuid() == m_variableUuid) {
|
||||||
|
m_variable = var;
|
||||||
|
std::cout << "✓ Resolved variable '" << var->GetVariableName()
|
||||||
|
<< "' for VariableNode " << GetId() << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "ERROR: Could not resolve variable UUID " << m_variableUuid
|
||||||
|
<< " for VariableNode " << GetId() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ public:
|
||||||
void SetVariable(std::shared_ptr<Variable> var);
|
void SetVariable(std::shared_ptr<Variable> var);
|
||||||
std::shared_ptr<Variable> GetVariable() const;
|
std::shared_ptr<Variable> GetVariable() const;
|
||||||
|
|
||||||
|
bool ResolveVariable(const std::vector<std::shared_ptr<Variable>>& variables);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_variableUuid;
|
std::string m_variableUuid;
|
||||||
std::shared_ptr<Variable> m_variable;
|
std::shared_ptr<Variable> m_variable;
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,38 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly)
|
||||||
pageData[std::string(page->Uuid())] = {pageNodes, pageLinks};
|
pageData[std::string(page->Uuid())] = {pageNodes, pageLinks};
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PHASE 2 : GÉNÉRATION ===
|
std::cout << "\n=== Resolving VariableNode references ===\n";
|
||||||
|
for (const auto& baseNode : allNodes) {
|
||||||
|
auto varNode = std::dynamic_pointer_cast<VariableNode>(baseNode);
|
||||||
|
if (varNode) {
|
||||||
|
varNode->ResolveVariable(m_variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ PHASE 2 : GÉNÉRATION DE TOUS LES TAC (avant la section DATA!)
|
||||||
|
std::cout << "\n=== Generating all TAC programs ===\n";
|
||||||
|
std::map<std::string, TACProgram> pageTACPrograms;
|
||||||
|
|
||||||
|
for (const auto& page : m_pages) {
|
||||||
|
std::string pageUuid(page->Uuid());
|
||||||
|
auto& [nodes, connections] = pageData[pageUuid];
|
||||||
|
|
||||||
|
// Construire l'AST pour cette page
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto astNodes = builder.BuildAST();
|
||||||
|
|
||||||
|
// Générer le TAC pour cette page
|
||||||
|
TACGenerator tacGen;
|
||||||
|
TACProgram pageTAC = tacGen.Generate(astNodes);
|
||||||
|
|
||||||
|
// Stocker le TAC
|
||||||
|
pageTACPrograms[pageUuid] = pageTAC;
|
||||||
|
|
||||||
|
std::cout << "Generated TAC for page: " << page->GetName() << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "=== All TAC programs generated ===\n\n";
|
||||||
|
|
||||||
|
// === PHASE 3 : GÉNÉRATION DE L'ASSEMBLEUR ===
|
||||||
AssemblyGenerator::GeneratorContext context(
|
AssemblyGenerator::GeneratorContext context(
|
||||||
m_variables,
|
m_variables,
|
||||||
"2025-01-10 15:30:00",
|
"2025-01-10 15:30:00",
|
||||||
|
|
@ -453,13 +484,14 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly)
|
||||||
generator.Reset();
|
generator.Reset();
|
||||||
generator.GenerateHeader();
|
generator.GenerateHeader();
|
||||||
|
|
||||||
// === SECTION DATA (commune à toutes les pages) ===
|
// === SECTION DATA (maintenant les format strings sont corrects!) ===
|
||||||
generator.StartSection(AssemblyGenerator::Section::DATA);
|
generator.StartSection(AssemblyGenerator::Section::DATA);
|
||||||
|
|
||||||
// Variables globales (partagées entre toutes les pages)
|
// Variables globales (partagées entre toutes les pages)
|
||||||
generator.GenerateGlobalVariables();
|
generator.GenerateGlobalVariables();
|
||||||
|
|
||||||
// Constantes de tous les nœuds de toutes les pages
|
// Constantes de tous les nœuds de toutes les pages
|
||||||
|
// ✅ Les format strings ont déjà été modifiés par le TAC generator
|
||||||
generator.GenerateNodesVariables(allNodes);
|
generator.GenerateNodesVariables(allNodes);
|
||||||
|
|
||||||
// === SECTION TEXT (chaque page = une fonction) ===
|
// === SECTION TEXT (chaque page = une fonction) ===
|
||||||
|
|
@ -469,11 +501,9 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly)
|
||||||
bool isFirstPage = true;
|
bool isFirstPage = true;
|
||||||
for (const auto& page : m_pages) {
|
for (const auto& page : m_pages) {
|
||||||
std::string pageUuid(page->Uuid());
|
std::string pageUuid(page->Uuid());
|
||||||
auto& [nodes, connections] = pageData[pageUuid];
|
|
||||||
|
|
||||||
// Construire l'AST pour cette page
|
// Récupérer le TAC pré-généré
|
||||||
ASTBuilder builder(nodes, connections);
|
TACProgram& pageTAC = pageTACPrograms[pageUuid];
|
||||||
auto astNodes = builder.BuildAST();
|
|
||||||
|
|
||||||
// Générer le label de fonction
|
// Générer le label de fonction
|
||||||
std::string functionLabel;
|
std::string functionLabel;
|
||||||
|
|
@ -490,10 +520,6 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly)
|
||||||
generator.AddComment("========================================");
|
generator.AddComment("========================================");
|
||||||
generator.GetAssembly() << functionLabel << ":\n";
|
generator.GetAssembly() << functionLabel << ":\n";
|
||||||
|
|
||||||
// Générer le TAC pour cette page
|
|
||||||
TACGenerator tacGen;
|
|
||||||
TACProgram pageTAC = tacGen.Generate(astNodes);
|
|
||||||
|
|
||||||
if (context.debugOutput) {
|
if (context.debugOutput) {
|
||||||
std::cout << "\n=== TAC for page: " << page->GetName() << " ===\n";
|
std::cout << "\n=== TAC for page: " << page->GetName() << " ===\n";
|
||||||
std::cout << pageTAC.ToString() << std::endl;
|
std::cout << pageTAC.ToString() << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[Window][WindowOverViewport_11111111]
|
[Window][WindowOverViewport_11111111]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=1220,694
|
Size=1220,836
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
|
|
@ -10,31 +10,31 @@ Collapsed=0
|
||||||
|
|
||||||
[Window][Library Manager]
|
[Window][Library Manager]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,0
|
DockId=0x00000002,0
|
||||||
|
|
||||||
[Window][Console]
|
[Window][Console]
|
||||||
Pos=60,263
|
Pos=60,546
|
||||||
Size=628,457
|
Size=628,316
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,0
|
DockId=0x00000004,0
|
||||||
|
|
||||||
[Window][Emulator]
|
[Window][Emulator]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,5
|
DockId=0x00000002,5
|
||||||
|
|
||||||
[Window][Code viewer]
|
[Window][Code viewer]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,4
|
DockId=0x00000002,4
|
||||||
|
|
||||||
[Window][Resources]
|
[Window][Resources]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,1
|
DockId=0x00000002,1
|
||||||
|
|
||||||
|
|
@ -50,36 +50,36 @@ Size=150,42
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Variables]
|
[Window][Variables]
|
||||||
Pos=690,263
|
Pos=690,546
|
||||||
Size=590,457
|
Size=590,316
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,0
|
DockId=0x00000005,0
|
||||||
|
|
||||||
[Window][CPU]
|
[Window][CPU]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,2
|
DockId=0x00000002,2
|
||||||
|
|
||||||
[Window][RAM view]
|
[Window][RAM view]
|
||||||
Pos=630,26
|
Pos=630,26
|
||||||
Size=650,235
|
Size=650,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,3
|
DockId=0x00000002,3
|
||||||
|
|
||||||
[Window][Properties]
|
[Window][Properties]
|
||||||
Pos=690,263
|
Pos=690,546
|
||||||
Size=590,457
|
Size=590,316
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,1
|
DockId=0x00000005,1
|
||||||
|
|
||||||
[Window][ToolBar]
|
[Window][ToolBar]
|
||||||
Pos=0,26
|
Pos=0,26
|
||||||
Size=60,694
|
Size=60,836
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][QuitConfirm]
|
[Window][QuitConfirm]
|
||||||
Pos=508,312
|
Pos=508,383
|
||||||
Size=264,96
|
Size=264,96
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
|
|
@ -90,13 +90,13 @@ Collapsed=0
|
||||||
|
|
||||||
[Window][Module editor]
|
[Window][Module editor]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=568,235
|
Size=568,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000001,0
|
||||||
|
|
||||||
[Window][Story editor]
|
[Window][Story editor]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=568,235
|
Size=568,518
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,1
|
DockId=0x00000001,1
|
||||||
|
|
||||||
|
|
@ -106,8 +106,8 @@ Size=687,422
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Error List]
|
[Window][Error List]
|
||||||
Pos=60,263
|
Pos=60,546
|
||||||
Size=628,457
|
Size=628,316
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,1
|
DockId=0x00000004,1
|
||||||
|
|
||||||
|
|
@ -155,11 +155,11 @@ Column 2 Weight=1.0000
|
||||||
Column 3 Width=60
|
Column 3 Width=60
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y
|
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,836 Split=Y
|
||||||
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,235 Split=X
|
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,549 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=1144,694 CentralNode=1 Selected=0x93ADCAAB
|
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=1144,694 CentralNode=1 Selected=0x93ADCAAB
|
||||||
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=650,694 Selected=0x4B07C626
|
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=650,694 Selected=0xE5897A33
|
||||||
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,457 Split=X Selected=0xEA83D666
|
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,316 Split=X Selected=0xEA83D666
|
||||||
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=616,192 Selected=0xEA83D666
|
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=616,192 Selected=0xEA83D666
|
||||||
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=578,192 Selected=0x8C72BEA8
|
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=578,192 Selected=0x8C72BEA8
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,51 +16,7 @@
|
||||||
#include "variable.h" // Pour Variable
|
#include "variable.h" // Pour Variable
|
||||||
#include "all_events.h"
|
#include "all_events.h"
|
||||||
#include "Localization.h"
|
#include "Localization.h"
|
||||||
|
#include "chip32_machine.h"
|
||||||
// Définitions des registres et événements CHIP-32 si non déjà dans chip32_vm.h
|
|
||||||
#ifndef R0
|
|
||||||
#define R0 0
|
|
||||||
#endif
|
|
||||||
#ifndef R1
|
|
||||||
#define R1 1
|
|
||||||
#endif
|
|
||||||
#ifndef R2
|
|
||||||
#define R2 2
|
|
||||||
#endif
|
|
||||||
#ifndef R3
|
|
||||||
#define R3 3
|
|
||||||
#endif
|
|
||||||
#ifndef R4
|
|
||||||
#define R4 4
|
|
||||||
#endif
|
|
||||||
#ifndef PC
|
|
||||||
#define PC 7 // Exemple de registre Program Counter
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EV_MASK_OK_BUTTON
|
|
||||||
#define EV_MASK_OK_BUTTON 1
|
|
||||||
#endif
|
|
||||||
#ifndef EV_MASK_HOME_BUTTON
|
|
||||||
#define EV_MASK_HOME_BUTTON 2
|
|
||||||
#endif
|
|
||||||
#ifndef EV_MASK_PREVIOUS_BUTTON
|
|
||||||
#define EV_MASK_PREVIOUS_BUTTON 4
|
|
||||||
#endif
|
|
||||||
#ifndef EV_MASK_NEXT_BUTTON
|
|
||||||
#define EV_MASK_NEXT_BUTTON 8
|
|
||||||
#endif
|
|
||||||
#ifndef EV_MASK_END_OF_AUDIO
|
|
||||||
#define EV_MASK_END_OF_AUDIO 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Définitions pour les codes de retour de Syscall
|
|
||||||
#ifndef SYSCALL_RET_OK
|
|
||||||
#define SYSCALL_RET_OK 0
|
|
||||||
#endif
|
|
||||||
#ifndef SYSCALL_RET_WAIT_EV
|
|
||||||
#define SYSCALL_RET_WAIT_EV 1 // Exemple: VM doit attendre un événement
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
AppController::AppController(ILogger& logger, EventBus& eventBus)
|
AppController::AppController(ILogger& logger, EventBus& eventBus)
|
||||||
: m_logger(logger)
|
: m_logger(logger)
|
||||||
|
|
@ -633,37 +589,6 @@ void AppController::LoadParams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AppController::GetStringFromMemory(uint32_t addr)
|
|
||||||
{
|
|
||||||
// Buffer local pour la chaîne
|
|
||||||
// Assurez-vous qu'il est assez grand pour gérer les chaînes de votre VM
|
|
||||||
// et qu'il est terminé par null
|
|
||||||
char strBuf[256]; // Augmenté la taille pour plus de sécurité
|
|
||||||
|
|
||||||
// Le bit le plus significatif indique si c'est de la RAM (0x80000000) ou ROM
|
|
||||||
bool isRam = (addr & 0x80000000) != 0;
|
|
||||||
addr &= 0xFFFF; // Masque pour obtenir l'adresse 16 bits
|
|
||||||
|
|
||||||
// Vérification de l'adresse pour éviter les dépassements de buffer
|
|
||||||
if (isRam) {
|
|
||||||
if (addr < m_chip32_ctx.ram.size) {
|
|
||||||
strncpy(strBuf, (const char *)&m_chip32_ctx.ram.mem[addr], sizeof(strBuf) - 1);
|
|
||||||
strBuf[sizeof(strBuf) - 1] = '\0'; // S'assurer que c'est null-terminated
|
|
||||||
} else {
|
|
||||||
m_logger.Log("GetStringFromMemory: Invalid RAM address: 0x" + std::to_string(addr), true);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (addr < m_chip32_ctx.rom.size) {
|
|
||||||
strncpy(strBuf, (const char *)&m_chip32_ctx.rom.mem[addr], sizeof(strBuf) - 1);
|
|
||||||
strBuf[sizeof(strBuf) - 1] = '\0'; // S'assurer que c'est null-terminated
|
|
||||||
} else {
|
|
||||||
m_logger.Log("GetStringFromMemory: Invalid ROM address: 0x" + std::to_string(addr), true);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppController::ProcessStory()
|
void AppController::ProcessStory()
|
||||||
{
|
{
|
||||||
|
|
@ -784,6 +709,7 @@ void AppController::StepInstruction()
|
||||||
UpdateVmView();
|
UpdateVmView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
{
|
{
|
||||||
uint8_t retCode = SYSCALL_RET_OK;
|
uint8_t retCode = SYSCALL_RET_OK;
|
||||||
|
|
@ -795,7 +721,7 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
// R0: image file name address, R1: sound file name address
|
// R0: image file name address, R1: sound file name address
|
||||||
if (ctx->registers[R0] != 0)
|
if (ctx->registers[R0] != 0)
|
||||||
{
|
{
|
||||||
std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(ctx->registers[R0]));
|
std::string imageFile = m_story->BuildFullAssetsPath(Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R0]));
|
||||||
m_logger.Log("Image: " + imageFile);
|
m_logger.Log("Image: " + imageFile);
|
||||||
// Ici, vous notifieriez la fenêtre de l'émulateur
|
// Ici, vous notifieriez la fenêtre de l'émulateur
|
||||||
// m_emulatorDock.SetImage(imageFile); // Ceci est une dépendance GUI
|
// m_emulatorDock.SetImage(imageFile); // Ceci est une dépendance GUI
|
||||||
|
|
@ -807,7 +733,7 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
|
|
||||||
if (ctx->registers[R1] != 0)
|
if (ctx->registers[R1] != 0)
|
||||||
{
|
{
|
||||||
std::string soundFile = m_story->BuildFullAssetsPath(GetStringFromMemory(ctx->registers[R1]));
|
std::string soundFile = m_story->BuildFullAssetsPath(Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R1]));
|
||||||
m_logger.Log("Sound: " + soundFile);
|
m_logger.Log("Sound: " + soundFile);
|
||||||
m_player.Play(soundFile);
|
m_player.Play(soundFile);
|
||||||
}
|
}
|
||||||
|
|
@ -827,23 +753,18 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
}
|
}
|
||||||
else if (code == 4) // Printf (printf-like behavior)
|
else if (code == 4) // Printf (printf-like behavior)
|
||||||
{
|
{
|
||||||
std::string text = GetStringFromMemory(ctx->registers[R0]);
|
std::string format = Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R0]);
|
||||||
int arg_count = ctx->registers[R1];
|
int arg_count = ctx->registers[R1];
|
||||||
char working_buf[400] = {0};
|
|
||||||
|
|
||||||
// Simplified printf logic for logging
|
std::vector<uint32_t> args;
|
||||||
switch(arg_count){
|
for (int i = 0; i < arg_count && i < 4; ++i) {
|
||||||
case 0: strcpy(working_buf, text.c_str()); break;
|
args.push_back(ctx->registers[R2 + i]);
|
||||||
case 1: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]); break;
|
|
||||||
case 2: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]); break;
|
|
||||||
case 3: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]); break;
|
|
||||||
default: m_logger.Log("Printf with unsupported arg_count: " + std::to_string(arg_count) + " text: " + text, true); break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send event to UI
|
// Send event to UI
|
||||||
auto evObj = std::make_shared<VmStateEvent>();
|
auto evObj = std::make_shared<VmStateEvent>();
|
||||||
evObj->type = VmStateEvent::Type::PrintEvent;
|
evObj->type = VmStateEvent::Type::PrintEvent;
|
||||||
evObj->printOutput = working_buf;
|
evObj->printOutput = Chip32::Machine::FormatStringWithPlaceholders(ctx, format, args);
|
||||||
m_eventBus.Emit(evObj);
|
m_eventBus.Emit(evObj);
|
||||||
}
|
}
|
||||||
else if (code == 5) // WAIT (sleep)
|
else if (code == 5) // WAIT (sleep)
|
||||||
|
|
@ -869,14 +790,13 @@ void AppController::UpdateVmView()
|
||||||
// Au lieu de cela, il émettrait un signal ou appellerait un observer.
|
// Au lieu de cela, il émettrait un signal ou appellerait un observer.
|
||||||
uint32_t pcVal = m_chip32_ctx.registers[PC];
|
uint32_t pcVal = m_chip32_ctx.registers[PC];
|
||||||
|
|
||||||
if (m_story && m_story->GetAssemblyLine(pcVal, m_dbg.line))
|
if (m_story)
|
||||||
|
{
|
||||||
|
if (m_story->GetAssemblyLine(pcVal, m_dbg.line))
|
||||||
{
|
{
|
||||||
m_logger.Log("Executing line: " + std::to_string(m_dbg.line + 1));
|
m_logger.Log("Executing line: " + std::to_string(m_dbg.line + 1));
|
||||||
// m_debuggerWindow.HighlightLine(m_dbg.line); // Dépendance GUI
|
// m_debuggerWindow.HighlightLine(m_dbg.line); // Dépendance GUI
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_logger.Log("Reached end or instruction not found (line: " + std::to_string(m_dbg.line) + ")", false);
|
|
||||||
}
|
}
|
||||||
// m_cpuWindow.updateRegistersView(m_chip32_ctx); // Dépendance GUI
|
// m_cpuWindow.updateRegistersView(m_chip32_ctx); // Dépendance GUI
|
||||||
// m_memoryEditor.DrawWindow("RAM view", m_chip32_ctx.ram.mem, m_chip32_ctx.ram.size); // Dépendance GUI
|
// m_memoryEditor.DrawWindow("RAM view", m_chip32_ctx.ram.mem, m_chip32_ctx.ram.size); // Dépendance GUI
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ public:
|
||||||
// Méthodes pour interagir avec la VM et le débogueur
|
// Méthodes pour interagir avec la VM et le débogueur
|
||||||
chip32_ctx_t* GetChip32Context() { return &m_chip32_ctx; }
|
chip32_ctx_t* GetChip32Context() { return &m_chip32_ctx; }
|
||||||
DebugContext* GetDebugContext() { return &m_dbg; }
|
DebugContext* GetDebugContext() { return &m_dbg; }
|
||||||
std::string GetStringFromMemory(uint32_t addr);
|
|
||||||
void ProcessStory();
|
void ProcessStory();
|
||||||
void StepInstruction();
|
void StepInstruction();
|
||||||
void StopAudio() { m_player.Stop(); }
|
void StopAudio() { m_player.Stop(); }
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
||||||
// Show success message if no errors
|
// Show success message if no errors
|
||||||
if (!m_errorListDock.HasErrors()) {
|
if (!m_errorListDock.HasErrors()) {
|
||||||
// You can also open a popup if desired
|
// You can also open a popup if desired
|
||||||
m_logger.Log("✓ Module compilation successful - Binary saved and loaded into VM");
|
m_logger.Log("Module compilation successful - Binary saved and loaded into VM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.GetType() == ModuleEvent::Type::BuildFailure) {
|
else if (event.GetType() == ModuleEvent::Type::BuildFailure) {
|
||||||
|
|
|
||||||
|
|
@ -134,37 +134,6 @@ struct NodeEditorPage : public ImFlow::BaseNode
|
||||||
return m_uuid;
|
return m_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<BaseNodeWidget>> GetNodes()
|
|
||||||
{
|
|
||||||
std::list<std::shared_ptr<BaseNodeWidget>> nlist;
|
|
||||||
// std::unordered_map<ImFlow::NodeUID, std::shared_ptr<BaseNode>>&
|
|
||||||
for (auto &node : mINF.getNodes())
|
|
||||||
{
|
|
||||||
auto delegate = dynamic_cast<NodeDelegate*>(node.second.get());
|
|
||||||
|
|
||||||
if (delegate == nullptr)
|
|
||||||
continue;
|
|
||||||
nlist.push_back(delegate->GetWidget());
|
|
||||||
}
|
|
||||||
|
|
||||||
return nlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> GetLinks() {
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> links;
|
|
||||||
|
|
||||||
// const std::vector<std::weak_ptr<Link>>& getLinks()
|
|
||||||
for (auto &link : mINF.getLinks())
|
|
||||||
{
|
|
||||||
auto linkInfo = std::make_shared<Connection>();
|
|
||||||
|
|
||||||
links.push_back(linkInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return links;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Select()
|
void Select()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,22 @@ void NodeEditorWindow::SaveNodesToProject()
|
||||||
connection->inNodeId = rightBaseNode->GetId();
|
connection->inNodeId = rightBaseNode->GetId();
|
||||||
connection->inPortIndex = rightPinIndex;
|
connection->inPortIndex = rightPinIndex;
|
||||||
|
|
||||||
|
// Detect type
|
||||||
|
auto outputPort = leftBaseNode->GetOutputPort(leftPinIndex);
|
||||||
|
if (outputPort.type == BaseNode::Port::Type::DATA_PORT) {
|
||||||
|
connection->type = Connection::DATA_LINK;
|
||||||
|
} else {
|
||||||
|
connection->type = Connection::EXECUTION_LINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 🔍 DEBUG
|
||||||
|
// std::cout << "=== SAVE CONNECTION ===" << std::endl;
|
||||||
|
// std::cout << " From: " << connection->outNodeId << "[" << connection->outPortIndex << "]" << std::endl;
|
||||||
|
// std::cout << " To: " << connection->inNodeId << "[" << connection->inPortIndex << "]" << std::endl;
|
||||||
|
// std::cout << " Output port type: " << (outputPort.type == BaseNode::Port::Type::DATA_PORT ? "DATA_PORT" : "EXECUTION_PORT") << std::endl;
|
||||||
|
// std::cout << " Connection type: " << (connection->type == Connection::DATA_LINK ? "DATA_LINK" : "EXECUTION_LINK") << std::endl;
|
||||||
|
// std::cout << "========================" << std::endl;
|
||||||
|
|
||||||
// Add connection to project
|
// Add connection to project
|
||||||
m_story->AddConnection(projectPage->Uuid(), connection);
|
m_story->AddConnection(projectPage->Uuid(), connection);
|
||||||
|
|
||||||
|
|
@ -474,165 +490,15 @@ void NodeEditorWindow::Draw()
|
||||||
ToolbarUI();
|
ToolbarUI();
|
||||||
|
|
||||||
m_currentPage->Draw(m_nodesFactory, m_widgetFactory, m_manager);
|
m_currentPage->Draw(m_nodesFactory, m_widgetFactory, m_manager);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ed::Begin(m_currentPage->Uuid().data(), ImVec2(0.0, 0.0f));
|
|
||||||
|
|
||||||
// Draw our nodes
|
|
||||||
m_currentPage->Draw();
|
|
||||||
|
|
||||||
// Handle creation action, returns true if editor want to create new object (node or link)
|
|
||||||
if (ed::BeginCreate())
|
|
||||||
{
|
|
||||||
ed::PinId startId, endId;
|
|
||||||
if (ed::QueryNewLink(&startId, &endId))
|
|
||||||
{
|
|
||||||
// QueryNewLink returns true if editor want to create new link between pins.
|
|
||||||
//
|
|
||||||
// Link can be created only for two valid pins, it is up to you to
|
|
||||||
// validate if connection make sense. Editor is happy to make any.
|
|
||||||
//
|
|
||||||
// Link always goes from input to output. User may choose to drag
|
|
||||||
// link from output pin or input pin. This determine which pin ids
|
|
||||||
// are valid and which are not:
|
|
||||||
// * input valid, output invalid - user started to drag new ling from input pin
|
|
||||||
// * input invalid, output valid - user started to drag new ling from output pin
|
|
||||||
// * input valid, output valid - user dragged link over other pin, can be validated
|
|
||||||
|
|
||||||
if (startId && endId) // both are valid, let's accept link
|
|
||||||
{
|
|
||||||
// ed::AcceptNewItem() return true when user release mouse button.
|
|
||||||
if (ed::AcceptNewItem())
|
|
||||||
{
|
|
||||||
auto c = std::make_shared<Connection>();
|
|
||||||
|
|
||||||
// On cherche à quel noeud appartien les pin (selon si le lien a été créé à partir d'une entrée ou d'une sortie)
|
|
||||||
if (FillConnection(c, startId))
|
|
||||||
{
|
|
||||||
if (FillConnection(c, endId))
|
|
||||||
{
|
|
||||||
m_story->AddConnection(m_currentPage->Uuid(), c);
|
|
||||||
|
|
||||||
CreateLink(c, startId, endId);
|
|
||||||
|
|
||||||
// Draw new link.
|
|
||||||
ed::Link(m_currentPage->m_links.back()->ed_link->Id, startId, endId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// You may choose to reject connection between these nodes
|
|
||||||
// by calling ed::RejectNewItem(). This will allow editor to give
|
|
||||||
// visual feedback by changing link thickness and color.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ed::EndCreate(); // Wraps up object creation action handling.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Handle deletion action
|
|
||||||
if (ed::BeginDelete())
|
|
||||||
{
|
|
||||||
ed::NodeId nodeId = 0;
|
|
||||||
while (ed::QueryDeletedNode(&nodeId))
|
|
||||||
{
|
|
||||||
if (ed::AcceptDeletedItem())
|
|
||||||
{
|
|
||||||
std::shared_ptr<BaseNodeWidget> node;
|
|
||||||
if (m_currentPage->GetNode(nodeId, node))
|
|
||||||
{
|
|
||||||
// First delete model, then current entry
|
|
||||||
m_story->DeleteNode(m_currentPage->Uuid(), node->Base()->GetId());
|
|
||||||
m_currentPage->DeleteNode(nodeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There may be many links marked for deletion, let's loop over them.
|
|
||||||
ed::LinkId deletedLinkId;
|
|
||||||
while (ed::QueryDeletedLink(&deletedLinkId))
|
|
||||||
{
|
|
||||||
// If you agree that link can be deleted, accept deletion.
|
|
||||||
if (ed::AcceptDeletedItem())
|
|
||||||
{
|
|
||||||
std::shared_ptr<Connection> model;
|
|
||||||
if (m_currentPage->GetModel(deletedLinkId, model))
|
|
||||||
{
|
|
||||||
m_story->DeleteLink(m_currentPage->Uuid(), model);
|
|
||||||
m_currentPage->EraseLink(deletedLinkId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// You may reject link deletion by calling:
|
|
||||||
// ed::RejectDeletedItem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ed::EndDelete(); // Wrap up deletion action
|
|
||||||
|
|
||||||
|
|
||||||
auto openPopupPosition = ImGui::GetMousePos();
|
|
||||||
ed::Suspend();
|
|
||||||
|
|
||||||
if (ed::ShowBackgroundContextMenu())
|
|
||||||
{
|
|
||||||
ImGui::OpenPopup("Create New Node");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopup("Create New Node"))
|
|
||||||
{
|
|
||||||
auto newNodePostion = openPopupPosition;
|
|
||||||
std::shared_ptr<BaseNode> base;
|
|
||||||
auto nodeTypes = m_nodesFactory.ListOfNodes();
|
|
||||||
|
|
||||||
for (auto &type : nodeTypes)
|
|
||||||
{
|
|
||||||
if (ImGui::MenuItem(type.name.c_str()))
|
|
||||||
{
|
|
||||||
base = m_nodesFactory.CreateNode(type.uuid);
|
|
||||||
if (base)
|
|
||||||
{
|
|
||||||
m_story->AddNode(m_currentPage->Uuid(), base);
|
|
||||||
auto n = CreateNodeWidget(type.uuid, m_manager, base);
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
n->Base()->SetPosition(newNodePostion.x, newNodePostion.y);
|
|
||||||
n->Initialize();
|
|
||||||
m_currentPage->AddNode(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_loaded)
|
|
||||||
{
|
|
||||||
ed::NavigateToContent();
|
|
||||||
m_loaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ed::Resume();
|
|
||||||
|
|
||||||
|
|
||||||
ed::End();
|
|
||||||
ed::SetCurrentEditor(nullptr);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set background color to light gray
|
// Set background color to light gray
|
||||||
// ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.7f, 0.7f, 0.7f, 1.0f));
|
// ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.7f, 0.7f, 0.7f, 1.0f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
ImGui::Text("Please load or create a project.");
|
ImGui::Text("Please load or create a project.");
|
||||||
|
|
||||||
ImGui::PopStyleColor(1); // Pop both colors
|
ImGui::PopStyleColor(1); // Pop both colors
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
|
|
@ -640,16 +506,6 @@ void NodeEditorWindow::Draw()
|
||||||
|
|
||||||
void NodeEditorWindow::ToolbarUI()
|
void NodeEditorWindow::ToolbarUI()
|
||||||
{
|
{
|
||||||
// auto& io = ImGui::GetIO();
|
|
||||||
// ImVec2 window_pos = ImGui::GetWindowPos();
|
|
||||||
// ImVec2 window_size = ImGui::GetWindowSize();
|
|
||||||
// ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove;
|
|
||||||
|
|
||||||
// ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
|
||||||
|
|
||||||
// ImGui::Begin("TOOLBAR", NULL, window_flags);
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::SetCursorPos(ImVec2(10, 40));
|
ImGui::SetCursorPos(ImVec2(10, 40));
|
||||||
ImGui::BeginChild("ToolbarChild", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 1.5f), false, ImGuiWindowFlags_NoScrollbar);
|
ImGui::BeginChild("ToolbarChild", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 1.5f), false, ImGuiWindowFlags_NoScrollbar);
|
||||||
|
|
||||||
|
|
@ -678,16 +534,6 @@ void NodeEditorWindow::ToolbarUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
// ImGui::End();
|
|
||||||
|
|
||||||
ImGui::EndChild(); // Fin de la ChildWindow de la barre d'outils
|
ImGui::EndChild(); // Fin de la ChildWindow de la barre d'outils
|
||||||
|
|
||||||
ImGui::SetCursorPos(ImVec2(0, 0));
|
ImGui::SetCursorPos(ImVec2(0, 0));
|
||||||
|
|
||||||
|
|
||||||
// if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
|
||||||
// {
|
|
||||||
// io.ConfigViewportsNoDecoration = false;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue