mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
tac implementation f new nodes function entry and exit with parameters
This commit is contained in:
parent
397da70d83
commit
07849e3e69
2 changed files with 433 additions and 52 deletions
|
|
@ -128,6 +128,19 @@ private:
|
|||
std::map<std::string, TempLocation> m_tempLocations;
|
||||
int m_nextTempReg = 0; // Prochain registre t0-t9 disponible
|
||||
int m_tempVarCounter = 0; // Compteur pour variables temporaires en RAM
|
||||
|
||||
// Function call management
|
||||
struct FunctionCallContext {
|
||||
int paramCount;
|
||||
std::string functionLabel;
|
||||
std::map<std::string, int> paramRegMap;
|
||||
};
|
||||
|
||||
std::shared_ptr<FunctionCallContext> m_currentFunctionCall;
|
||||
|
||||
// Flag pour distinguer PARAM pour syscall vs function call
|
||||
bool m_preparingFunctionCall = false;
|
||||
int m_functionCallParamIndex = 0;
|
||||
|
||||
// ===================================================================
|
||||
// GÉNÉRATION DE LA SECTION DATA
|
||||
|
|
@ -260,12 +273,34 @@ private:
|
|||
break;
|
||||
|
||||
case TACInstruction::OpCode::RETURN:
|
||||
m_assembly << " ret\n";
|
||||
// Utiliser FUNC_RETURN pour les fonctions avec FUNC_BEGIN
|
||||
if (m_currentFunctionCall) {
|
||||
GenerateFuncReturn(instr);
|
||||
} else {
|
||||
// RETURN normal (existant) - peut-être déjà géré ailleurs
|
||||
m_assembly << " ret\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case TACInstruction::OpCode::NOP:
|
||||
m_assembly << " nop\n";
|
||||
break;
|
||||
|
||||
case TACInstruction::OpCode::FUNC_BEGIN:
|
||||
GenerateFuncBegin(instr);
|
||||
break;
|
||||
|
||||
case TACInstruction::OpCode::FUNC_END:
|
||||
GenerateFuncEnd(instr);
|
||||
break;
|
||||
|
||||
case TACInstruction::OpCode::FUNC_PARAM_IN:
|
||||
GenerateFuncParamIn(instr);
|
||||
break;
|
||||
|
||||
case TACInstruction::OpCode::RETURN_VAL:
|
||||
GenerateReturnVal(instr);
|
||||
break;
|
||||
|
||||
default:
|
||||
AddComment("WARNING: Unsupported TAC instruction");
|
||||
|
|
@ -379,6 +414,173 @@ private:
|
|||
// ===================================================================
|
||||
// GÉNÉRATION DES INSTRUCTIONS
|
||||
// ===================================================================
|
||||
|
||||
// Génération pour FUNC_BEGIN
|
||||
void GenerateFuncBegin(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Function Begin: " + instr->GetDest()->ToString());
|
||||
}
|
||||
|
||||
std::string functionLabel = instr->GetDest()->GetValue();
|
||||
|
||||
// Générer le label de la fonction
|
||||
m_assembly << "\n" << functionLabel << ":\n";
|
||||
|
||||
// Initialiser le contexte d'appel
|
||||
m_currentFunctionCall = std::make_shared<FunctionCallContext>();
|
||||
m_currentFunctionCall->functionLabel = functionLabel;
|
||||
m_currentFunctionCall->paramCount = 0;
|
||||
|
||||
AddComment("Parameters are passed in r0-r9");
|
||||
}
|
||||
|
||||
// Génération pour FUNC_PARAM_IN
|
||||
void GenerateFuncParamIn(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Read parameter: " + instr->GetOp1()->ToString());
|
||||
}
|
||||
|
||||
std::string paramName = instr->GetOp1()->GetValue();
|
||||
|
||||
// Le paramètre est dans r0, r1, r2, etc. selon l'ordre
|
||||
int paramReg = m_currentFunctionCall->paramCount;
|
||||
if (paramReg >= 10) {
|
||||
throw std::runtime_error("Too many parameters (max 10 with r0-r9)");
|
||||
}
|
||||
|
||||
m_currentFunctionCall->paramRegMap[paramName] = paramReg;
|
||||
m_currentFunctionCall->paramCount++;
|
||||
|
||||
// Le paramètre est déjà dans rX, le copier dans le temporaire destination
|
||||
std::string sourceReg = "r" + std::to_string(paramReg);
|
||||
StoreResult(instr->GetDest(), sourceReg);
|
||||
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Parameter " + paramName + " from " + sourceReg);
|
||||
}
|
||||
}
|
||||
|
||||
// Génération pour FUNC_RETURN
|
||||
void GenerateFuncReturn(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Function return");
|
||||
}
|
||||
|
||||
// Nettoyer le contexte
|
||||
m_currentFunctionCall.reset();
|
||||
|
||||
// Retourner (le résultat est déjà dans r0 via RETURN_VAL)
|
||||
m_assembly << " ret\n";
|
||||
}
|
||||
|
||||
// Génération pour FUNC_END
|
||||
void GenerateFuncEnd(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Function End");
|
||||
}
|
||||
// Rien à faire, juste marquer la fin
|
||||
}
|
||||
|
||||
// Génération pour RETURN_VAL
|
||||
void GenerateReturnVal(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Set return value: " + instr->GetDest()->ToString());
|
||||
}
|
||||
|
||||
std::string returnName = instr->GetDest()->GetValue();
|
||||
|
||||
// Charger la valeur à retourner dans r0 (convention de retour)
|
||||
std::string valueReg = LoadOperand(instr->GetOp1(), "r0");
|
||||
|
||||
// Si la valeur est déjà dans r0, rien à faire
|
||||
if (valueReg != "r0") {
|
||||
m_assembly << " mov r0, " << valueReg << "\n";
|
||||
}
|
||||
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Return value " + returnName + " in r0");
|
||||
}
|
||||
}
|
||||
|
||||
// Génération pour CALL (peut déjà exister - vérifier avant d'ajouter)
|
||||
void GenerateCall(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Call function: " + instr->GetOp1()->ToString());
|
||||
}
|
||||
|
||||
std::string functionLabel = instr->GetOp1()->GetValue();
|
||||
|
||||
// Réinitialiser le compteur de paramètres après l'appel
|
||||
m_functionCallParamIndex = 0;
|
||||
m_preparingFunctionCall = false;
|
||||
|
||||
// Effectuer l'appel
|
||||
m_assembly << " call " << functionLabel << "\n";
|
||||
|
||||
// Le résultat est dans r0 (convention)
|
||||
// Stocker dans le temporaire de destination
|
||||
if (instr->GetDest()) {
|
||||
StoreResult(instr->GetDest(), "r0");
|
||||
}
|
||||
}
|
||||
|
||||
// Génération pour PARAM - DISTINGUER syscall vs function call
|
||||
void GenerateParam(std::shared_ptr<TACInstruction> instr) {
|
||||
if (m_context.debugOutput) {
|
||||
AddComment("Parameter: " + instr->GetDest()->ToString());
|
||||
}
|
||||
|
||||
// Déterminer si c'est pour un syscall ou un appel de fonction
|
||||
// en regardant si on est dans un contexte d'appel de fonction
|
||||
if (m_preparingFunctionCall) {
|
||||
// C'est pour un appel de fonction → charger dans rN
|
||||
if (m_functionCallParamIndex >= 10) {
|
||||
throw std::runtime_error("Too many parameters for function call (max 10)");
|
||||
}
|
||||
|
||||
std::string targetReg = "r" + std::to_string(m_functionCallParamIndex);
|
||||
std::string paramReg = LoadOperand(instr->GetDest(), targetReg);
|
||||
|
||||
if (paramReg != targetReg) {
|
||||
m_assembly << " mov " << targetReg << ", " << paramReg << "\n";
|
||||
}
|
||||
|
||||
m_functionCallParamIndex++;
|
||||
} else {
|
||||
// C'est pour un syscall (Print, etc.) → empiler sur la stack
|
||||
std::string paramReg = LoadOperand(instr->GetDest(), "r0");
|
||||
m_assembly << " push " << paramReg << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode helper pour détecter si les PARAM suivants sont pour un CALL
|
||||
void DetectFunctionCallContext(size_t currentInstrIndex) {
|
||||
// Regarder les instructions suivantes pour détecter un CALL de fonction
|
||||
const auto& instructions = m_tacProgram.GetInstructions();
|
||||
|
||||
// Compter les PARAM consécutifs après l'instruction courante
|
||||
size_t paramCount = 0;
|
||||
size_t idx = currentInstrIndex + 1;
|
||||
|
||||
while (idx < instructions.size() &&
|
||||
instructions[idx]->GetOpCode() == TACInstruction::OpCode::PARAM) {
|
||||
paramCount++;
|
||||
idx++;
|
||||
}
|
||||
|
||||
// Vérifier ce qui vient après les PARAM
|
||||
if (idx < instructions.size()) {
|
||||
auto nextInstr = instructions[idx];
|
||||
|
||||
// Si c'est un CALL de fonction utilisateur, activer le flag
|
||||
if (nextInstr->GetOpCode() == TACInstruction::OpCode::CALL) {
|
||||
m_preparingFunctionCall = true;
|
||||
m_functionCallParamIndex = 0;
|
||||
}
|
||||
// Sinon (PRINT, etc.), c'est pour un syscall
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GenerateBinaryOp(std::shared_ptr<TACInstruction> instr) {
|
||||
// Charger les opérandes
|
||||
|
|
@ -474,11 +676,6 @@ private:
|
|||
|
||||
std::vector<std::shared_ptr<TACOperand>> m_printParams;
|
||||
|
||||
void GenerateParam(std::shared_ptr<TACInstruction> instr) {
|
||||
// Accumuler les paramètres pour le prochain PRINT/CALL
|
||||
m_printParams.push_back(instr->GetDest());
|
||||
}
|
||||
|
||||
void GeneratePrint(std::shared_ptr<TACInstruction> instr) {
|
||||
// Sauvegarder r0, r1
|
||||
m_assembly << " push r0\n";
|
||||
|
|
@ -515,20 +712,6 @@ private:
|
|||
m_printParams.clear();
|
||||
}
|
||||
|
||||
void GenerateCall(std::shared_ptr<TACInstruction> instr) {
|
||||
// Générer l'appel de fonction
|
||||
std::string functionName = instr->GetOp1() ?
|
||||
instr->GetOp1()->ToString() :
|
||||
instr->GetDest()->ToString();
|
||||
|
||||
m_assembly << " call " << functionName << "\n";
|
||||
|
||||
// Si on a une destination, sauvegarder le résultat
|
||||
if (instr->GetDest() && instr->GetOp1()) {
|
||||
// Le résultat est dans r0 par convention
|
||||
StoreResult(instr->GetDest(), "r0");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// HELPER : Obtenir la taille d'une variable
|
||||
|
|
|
|||
|
|
@ -113,7 +113,13 @@ public:
|
|||
// Special
|
||||
PRINT, // Print (syscall 4)
|
||||
SYSCALL, // Generic syscall
|
||||
NOP // No operation
|
||||
NOP, // No operation
|
||||
|
||||
// Function definition
|
||||
FUNC_BEGIN, // Begin function definition
|
||||
FUNC_PARAM_IN, // Read input parameter from stack
|
||||
RETURN_VAL, // Set return value
|
||||
FUNC_END, // End function definition
|
||||
};
|
||||
|
||||
TACInstruction(OpCode op)
|
||||
|
|
@ -252,6 +258,18 @@ public:
|
|||
case OpCode::SYSCALL:
|
||||
ss << "syscall " << m_dest->ToString();
|
||||
break;
|
||||
case OpCode::FUNC_BEGIN:
|
||||
ss << "func_begin " << m_dest->ToString();
|
||||
break;
|
||||
case OpCode::FUNC_END:
|
||||
ss << "func_end";
|
||||
break;
|
||||
case OpCode::FUNC_PARAM_IN:
|
||||
ss << m_dest->ToString() << " = param_in " << m_op1->ToString();
|
||||
break;
|
||||
case OpCode::RETURN_VAL:
|
||||
ss << "return_val " << m_dest->ToString() << " = " << m_op1->ToString();
|
||||
break;
|
||||
case OpCode::NOP:
|
||||
ss << "nop";
|
||||
break;
|
||||
|
|
@ -328,6 +346,7 @@ private:
|
|||
#include "while_loop_node.h"
|
||||
#include "break_node.h"
|
||||
#include "continue_node.h"
|
||||
#include "function_exit_node.h"
|
||||
|
||||
// ===================================================================
|
||||
// SECTION 2: CLASSE TACGenerator - MODIFICATIONS
|
||||
|
|
@ -400,6 +419,17 @@ private:
|
|||
// Variables disponibles pour résolution
|
||||
std::vector<std::shared_ptr<Variable>> m_variables;
|
||||
|
||||
// Context de fonction
|
||||
struct FunctionContext {
|
||||
std::string functionName;
|
||||
std::string functionUuid;
|
||||
std::vector<std::string> parameters; // Noms des paramètres
|
||||
std::vector<std::string> returnValues; // Noms des valeurs de retour
|
||||
std::string returnLabel; // Label de sortie
|
||||
};
|
||||
|
||||
std::shared_ptr<FunctionContext> m_currentFunction;
|
||||
|
||||
// ===================================================================
|
||||
// HELPERS
|
||||
// ===================================================================
|
||||
|
|
@ -538,6 +568,12 @@ private:
|
|||
GenerateNode(node->children[i]);
|
||||
}
|
||||
}
|
||||
else if (node->IsType<FunctionEntryNode>()) {
|
||||
return GenerateFunctionEntryNode(node);
|
||||
}
|
||||
else if (node->IsType<FunctionExitNode>()) {
|
||||
return GenerateFunctionExitNode(node);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// NŒUDS SYSCALL
|
||||
|
|
@ -560,7 +596,7 @@ private:
|
|||
}
|
||||
|
||||
// ===================================================================
|
||||
// OUR LES BOUCLES
|
||||
// POUR LES BOUCLES
|
||||
// ===================================================================
|
||||
else if (node->IsType<ForLoopNode>()) {
|
||||
std::cout << " -> Type: ForLoopNode\n";
|
||||
|
|
@ -594,9 +630,195 @@ private:
|
|||
}
|
||||
|
||||
// ===================================================================
|
||||
// GÉNÉRATION PAR TYPE DE NŒUD - EXISTANTS (pas de changement)
|
||||
// GÉNÉRATION PAR TYPE DE NŒUD
|
||||
// ===================================================================
|
||||
|
||||
std::shared_ptr<TACOperand> GenerateFunctionEntryNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* entryNode = node->GetAs<FunctionEntryNode>();
|
||||
if (!entryNode) return nullptr;
|
||||
|
||||
std::cout << " Generating TAC for FunctionEntryNode\n";
|
||||
|
||||
// Créer un contexte de fonction
|
||||
m_currentFunction = std::make_shared<FunctionContext>();
|
||||
m_currentFunction->functionName = "function_" + node->GetId();
|
||||
|
||||
// Générer FUNC_BEGIN
|
||||
auto funcLabel = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::LABEL,
|
||||
m_currentFunction->functionName
|
||||
);
|
||||
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::FUNC_BEGIN,
|
||||
funcLabel,
|
||||
nullptr,
|
||||
nullptr
|
||||
));
|
||||
|
||||
// Pour chaque paramètre, générer FUNC_PARAM_IN
|
||||
for (const auto& param : entryNode->GetParameters()) {
|
||||
// Créer un temporaire pour stocker le paramètre
|
||||
auto paramTemp = NewTemp();
|
||||
m_currentFunction->parameters.push_back(paramTemp->GetValue());
|
||||
|
||||
auto paramName = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::VARIABLE,
|
||||
param.name
|
||||
);
|
||||
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::FUNC_PARAM_IN,
|
||||
paramTemp,
|
||||
paramName,
|
||||
nullptr
|
||||
));
|
||||
|
||||
std::cout << " Parameter: " << param.name
|
||||
<< " -> " << paramTemp->GetValue() << "\n";
|
||||
}
|
||||
|
||||
return funcLabel;
|
||||
}
|
||||
|
||||
// Génération pour FunctionExitNode
|
||||
std::shared_ptr<TACOperand> GenerateFunctionExitNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* exitNode = node->GetAs<FunctionExitNode>();
|
||||
if (!exitNode) return nullptr;
|
||||
|
||||
std::cout << " Generating TAC for FunctionExitNode: "
|
||||
<< exitNode->GetExitLabel() << "\n";
|
||||
|
||||
// Pour chaque valeur de retour, évaluer et générer RETURN_VAL
|
||||
size_t portIndex = 1; // Port 0 est l'exécution
|
||||
for (const auto& returnValue : exitNode->GetReturnValues()) {
|
||||
// Récupérer l'input qui fournit cette valeur
|
||||
auto it = node->dataInputs.find(portIndex);
|
||||
if (it != node->dataInputs.end()) {
|
||||
auto valueOperand = GenerateNode(it->second);
|
||||
|
||||
auto returnName = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::VARIABLE,
|
||||
returnValue.name
|
||||
);
|
||||
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::RETURN_VAL,
|
||||
returnName,
|
||||
valueOperand,
|
||||
nullptr
|
||||
));
|
||||
|
||||
std::cout << " Return value: " << returnValue.name << "\n";
|
||||
}
|
||||
portIndex++;
|
||||
}
|
||||
|
||||
// Générer le label de sortie
|
||||
auto exitLabel = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::LABEL,
|
||||
"exit_" + exitNode->GetExitLabel() + "_" + node->GetId()
|
||||
);
|
||||
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::LABEL,
|
||||
exitLabel,
|
||||
nullptr,
|
||||
nullptr
|
||||
));
|
||||
|
||||
// Générer FUNC_RETURN
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::RETURN, // Utiliser RETURN existant
|
||||
exitLabel,
|
||||
nullptr,
|
||||
nullptr
|
||||
));
|
||||
|
||||
// Si c'est la dernière sortie, générer FUNC_END
|
||||
if (m_currentFunction) {
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::FUNC_END,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
));
|
||||
}
|
||||
|
||||
return exitLabel;
|
||||
}
|
||||
|
||||
// Génération pour CallFunctionNode
|
||||
std::shared_ptr<TACOperand> GenerateCallFunctionNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* callNode = node->GetAs<CallFunctionNode>();
|
||||
if (!callNode) return nullptr;
|
||||
|
||||
std::cout << " Generating TAC for CallFunctionNode: "
|
||||
<< callNode->GetFunctionName() << "\n";
|
||||
|
||||
// 1. Préparer les paramètres
|
||||
// Récupérer le module appelé pour connaître ses paramètres
|
||||
// (Ici on suppose qu'on a accès à la liste des paramètres via le module)
|
||||
|
||||
// Pour chaque input binding
|
||||
const auto& bindings = callNode->GetInputBindings();
|
||||
for (size_t i = 0; i < bindings.size(); i++) {
|
||||
const auto& binding = bindings[i];
|
||||
|
||||
std::shared_ptr<TACOperand> paramValue;
|
||||
|
||||
if (binding.mode == CallFunctionNode::MODE_CONSTANT) {
|
||||
// Valeur constante
|
||||
paramValue = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::CONSTANT,
|
||||
binding.constantValue
|
||||
);
|
||||
} else {
|
||||
// MODE_CONNECTED : évaluer le nœud connecté
|
||||
auto portIt = node->dataInputs.find(i + 1); // Port 0 = exec
|
||||
if (portIt != node->dataInputs.end()) {
|
||||
paramValue = GenerateNode(portIt->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (paramValue) {
|
||||
// Générer PARAM pour empiler l'argument
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::PARAM,
|
||||
paramValue,
|
||||
nullptr,
|
||||
nullptr
|
||||
));
|
||||
|
||||
std::cout << " Param " << i << ": "
|
||||
<< binding.paramName << " = "
|
||||
<< paramValue->ToString() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Générer l'appel
|
||||
auto functionLabel = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::LABEL,
|
||||
"function_" + callNode->GetFunctionUuid()
|
||||
);
|
||||
|
||||
auto resultTemp = NewTemp();
|
||||
|
||||
m_program.AddInstruction(std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::CALL,
|
||||
resultTemp,
|
||||
functionLabel,
|
||||
nullptr
|
||||
));
|
||||
|
||||
std::cout << " Call: " << callNode->GetFunctionName() << "\n";
|
||||
|
||||
// 3. Le résultat de l'appel est dans resultTemp
|
||||
// Les valeurs de retour seront accessibles via des LOAD après le CALL
|
||||
|
||||
return resultTemp;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// GÉNÉRATION DU FOR LOOP
|
||||
// ===================================================================
|
||||
|
|
@ -614,7 +836,7 @@ private:
|
|||
auto loopContinue = NewLabel("for_continue");
|
||||
auto loopEnd = NewLabel("for_end");
|
||||
|
||||
// ⭐ IMPORTANT : Empiler le contexte AVANT de générer le corps
|
||||
// IMPORTANT : Empiler le contexte AVANT de générer le corps
|
||||
m_loopStack.push_back({
|
||||
loopStart->GetValue(),
|
||||
loopEnd->GetValue(),
|
||||
|
|
@ -734,7 +956,7 @@ private:
|
|||
);
|
||||
m_program.AddInstruction(labelEnd);
|
||||
|
||||
// ⭐ IMPORTANT : Dépiler APRÈS avoir généré tout le corps
|
||||
// IMPORTANT : Dépiler APRÈS avoir généré tout le corps
|
||||
m_loopStack.pop_back();
|
||||
|
||||
// === 10. COMPLETED (port de sortie 1) ===
|
||||
|
|
@ -759,7 +981,7 @@ private:
|
|||
auto loopBody = NewLabel("while_body");
|
||||
auto loopEnd = NewLabel("while_end");
|
||||
|
||||
// ⭐ Empiler le contexte AVANT le corps
|
||||
// Empiler le contexte AVANT le corps
|
||||
m_loopStack.push_back({
|
||||
loopStart->GetValue(),
|
||||
loopEnd->GetValue(),
|
||||
|
|
@ -815,7 +1037,7 @@ private:
|
|||
);
|
||||
m_program.AddInstruction(labelEnd);
|
||||
|
||||
// ⭐ Dépiler APRÈS le corps
|
||||
// Dépiler APRÈS le corps
|
||||
m_loopStack.pop_back();
|
||||
|
||||
// === 8. COMPLETED (port de sortie 1) ===
|
||||
|
|
@ -1033,30 +1255,6 @@ private:
|
|||
<< (args.size() + 1) << " instructions)\n";
|
||||
}
|
||||
|
||||
void GenerateCallFunctionNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* callNode = node->GetAs<CallFunctionNode>();
|
||||
if (!callNode) return;
|
||||
|
||||
std::string pageUuid = callNode->GetFunctionUuid();
|
||||
std::string pageLabel = "page_" + pageUuid;
|
||||
|
||||
std::cout << " Generating CALL to page: " << pageLabel << "\n";
|
||||
|
||||
// Créer l'opérande label pour la page cible
|
||||
auto targetLabel = std::make_shared<TACOperand>(
|
||||
TACOperand::Type::LABEL,
|
||||
pageLabel
|
||||
);
|
||||
|
||||
// Générer l'instruction CALL
|
||||
auto callInstr = std::make_shared<TACInstruction>(
|
||||
TACInstruction::OpCode::CALL,
|
||||
targetLabel
|
||||
);
|
||||
|
||||
m_program.AddInstruction(callInstr);
|
||||
}
|
||||
|
||||
void GenerateBranchNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* branchNode = node->GetAs<BranchNode>();
|
||||
if (!branchNode) {
|
||||
|
|
@ -1128,7 +1326,7 @@ private:
|
|||
}
|
||||
|
||||
// ===================================================================
|
||||
// NOUVEAUX GÉNÉRATEURS POUR LES NŒUDS SYSCALL
|
||||
// GÉNÉRATEURS POUR LES NŒUDS SYSCALL
|
||||
// ===================================================================
|
||||
|
||||
void GenerateWaitDelayNode(std::shared_ptr<ASTNode> node) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue