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
|
|
@ -129,6 +129,19 @@ private:
|
||||||
int m_nextTempReg = 0; // Prochain registre t0-t9 disponible
|
int m_nextTempReg = 0; // Prochain registre t0-t9 disponible
|
||||||
int m_tempVarCounter = 0; // Compteur pour variables temporaires en RAM
|
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
|
// GÉNÉRATION DE LA SECTION DATA
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
@ -260,13 +273,35 @@ private:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TACInstruction::OpCode::RETURN:
|
case TACInstruction::OpCode::RETURN:
|
||||||
|
// 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";
|
m_assembly << " ret\n";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TACInstruction::OpCode::NOP:
|
case TACInstruction::OpCode::NOP:
|
||||||
m_assembly << " nop\n";
|
m_assembly << " nop\n";
|
||||||
break;
|
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:
|
default:
|
||||||
AddComment("WARNING: Unsupported TAC instruction");
|
AddComment("WARNING: Unsupported TAC instruction");
|
||||||
}
|
}
|
||||||
|
|
@ -380,6 +415,173 @@ private:
|
||||||
// GÉNÉRATION DES INSTRUCTIONS
|
// 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) {
|
void GenerateBinaryOp(std::shared_ptr<TACInstruction> instr) {
|
||||||
// Charger les opérandes
|
// Charger les opérandes
|
||||||
LoadOperand(instr->GetOp1(), "r0");
|
LoadOperand(instr->GetOp1(), "r0");
|
||||||
|
|
@ -474,11 +676,6 @@ private:
|
||||||
|
|
||||||
std::vector<std::shared_ptr<TACOperand>> m_printParams;
|
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) {
|
void GeneratePrint(std::shared_ptr<TACInstruction> instr) {
|
||||||
// Sauvegarder r0, r1
|
// Sauvegarder r0, r1
|
||||||
m_assembly << " push r0\n";
|
m_assembly << " push r0\n";
|
||||||
|
|
@ -515,20 +712,6 @@ private:
|
||||||
m_printParams.clear();
|
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
|
// HELPER : Obtenir la taille d'une variable
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,13 @@ public:
|
||||||
// Special
|
// Special
|
||||||
PRINT, // Print (syscall 4)
|
PRINT, // Print (syscall 4)
|
||||||
SYSCALL, // Generic syscall
|
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)
|
TACInstruction(OpCode op)
|
||||||
|
|
@ -252,6 +258,18 @@ public:
|
||||||
case OpCode::SYSCALL:
|
case OpCode::SYSCALL:
|
||||||
ss << "syscall " << m_dest->ToString();
|
ss << "syscall " << m_dest->ToString();
|
||||||
break;
|
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:
|
case OpCode::NOP:
|
||||||
ss << "nop";
|
ss << "nop";
|
||||||
break;
|
break;
|
||||||
|
|
@ -328,6 +346,7 @@ private:
|
||||||
#include "while_loop_node.h"
|
#include "while_loop_node.h"
|
||||||
#include "break_node.h"
|
#include "break_node.h"
|
||||||
#include "continue_node.h"
|
#include "continue_node.h"
|
||||||
|
#include "function_exit_node.h"
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// SECTION 2: CLASSE TACGenerator - MODIFICATIONS
|
// SECTION 2: CLASSE TACGenerator - MODIFICATIONS
|
||||||
|
|
@ -400,6 +419,17 @@ private:
|
||||||
// Variables disponibles pour résolution
|
// Variables disponibles pour résolution
|
||||||
std::vector<std::shared_ptr<Variable>> m_variables;
|
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
|
// HELPERS
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
@ -538,6 +568,12 @@ private:
|
||||||
GenerateNode(node->children[i]);
|
GenerateNode(node->children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (node->IsType<FunctionEntryNode>()) {
|
||||||
|
return GenerateFunctionEntryNode(node);
|
||||||
|
}
|
||||||
|
else if (node->IsType<FunctionExitNode>()) {
|
||||||
|
return GenerateFunctionExitNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// NŒUDS SYSCALL
|
// NŒUDS SYSCALL
|
||||||
|
|
@ -560,7 +596,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// OUR LES BOUCLES
|
// POUR LES BOUCLES
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
else if (node->IsType<ForLoopNode>()) {
|
else if (node->IsType<ForLoopNode>()) {
|
||||||
std::cout << " -> Type: ForLoopNode\n";
|
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
|
// GÉNÉRATION DU FOR LOOP
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
@ -614,7 +836,7 @@ private:
|
||||||
auto loopContinue = NewLabel("for_continue");
|
auto loopContinue = NewLabel("for_continue");
|
||||||
auto loopEnd = NewLabel("for_end");
|
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({
|
m_loopStack.push_back({
|
||||||
loopStart->GetValue(),
|
loopStart->GetValue(),
|
||||||
loopEnd->GetValue(),
|
loopEnd->GetValue(),
|
||||||
|
|
@ -734,7 +956,7 @@ private:
|
||||||
);
|
);
|
||||||
m_program.AddInstruction(labelEnd);
|
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();
|
m_loopStack.pop_back();
|
||||||
|
|
||||||
// === 10. COMPLETED (port de sortie 1) ===
|
// === 10. COMPLETED (port de sortie 1) ===
|
||||||
|
|
@ -759,7 +981,7 @@ private:
|
||||||
auto loopBody = NewLabel("while_body");
|
auto loopBody = NewLabel("while_body");
|
||||||
auto loopEnd = NewLabel("while_end");
|
auto loopEnd = NewLabel("while_end");
|
||||||
|
|
||||||
// ⭐ Empiler le contexte AVANT le corps
|
// Empiler le contexte AVANT le corps
|
||||||
m_loopStack.push_back({
|
m_loopStack.push_back({
|
||||||
loopStart->GetValue(),
|
loopStart->GetValue(),
|
||||||
loopEnd->GetValue(),
|
loopEnd->GetValue(),
|
||||||
|
|
@ -815,7 +1037,7 @@ private:
|
||||||
);
|
);
|
||||||
m_program.AddInstruction(labelEnd);
|
m_program.AddInstruction(labelEnd);
|
||||||
|
|
||||||
// ⭐ Dépiler APRÈS le corps
|
// Dépiler APRÈS le corps
|
||||||
m_loopStack.pop_back();
|
m_loopStack.pop_back();
|
||||||
|
|
||||||
// === 8. COMPLETED (port de sortie 1) ===
|
// === 8. COMPLETED (port de sortie 1) ===
|
||||||
|
|
@ -1033,30 +1255,6 @@ private:
|
||||||
<< (args.size() + 1) << " instructions)\n";
|
<< (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) {
|
void GenerateBranchNode(std::shared_ptr<ASTNode> node) {
|
||||||
auto* branchNode = node->GetAs<BranchNode>();
|
auto* branchNode = node->GetAs<BranchNode>();
|
||||||
if (!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) {
|
void GenerateWaitDelayNode(std::shared_ptr<ASTNode> node) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue