Réponse au prompt “Je suis étudiant en deuxième année d’école d’ingénieur. Explique-moi les grandes lignes de ce code pour que je puisse le maintenir.”

codex

26 mai 2026

Voici les grandes lignes, orientées maintenance.

Le projet est un petit interpréteur du langage Logo en C++ : il lit un fichier .logo, le transforme en instructions internes, puis exécute ces instructions pas à pas avec une tortue graphique SFML.

Flux Principal

  1. main.cpp lit deux arguments : logo fichier.logo delai Le délai sert à ralentir l’animation pour voir la tortue bouger.

  2. Lexer.cpp découpe le texte en tokens : mots-clés comme avance, droite, pour, fin, nombres, noms de fonctions, signes [ et ].

  3. Program.cpp compile ces tokens en objets Instruction. Par exemple : avance 150 devient une instance de Move. droite 90 devient une instance de Turn. Un nom inconnu comme hex devient un appel de fonction FunctionCall.

  4. Interpreter.cpp exécute une instruction à chaque appel de nextStep(). Il maintient une pile d’exécution (myCallStack) pour gérer les appels de fonctions Logo.

  5. Turtle.cpp gère la fenêtre SFML, la position de la tortue, son angle, le stylo levé/baissé, et les lignes dessinées.

Architecture

La classe centrale abstraite est Instruction. Chaque commande Logo hérite d’elle et redéfinit principalement :

Les commandes existantes sont :

Points importants à connaître

Le mot-clé repete existe dans le lexer, mais n’est pas implémenté dans Program::parseKeyword(). Donc un fichier comme prog2.logo peut être reconnu lexicalement, mais échouera à la compilation avec “Unimplemented keyword”.

Les fonctions Logo ne peuvent être définies qu’au niveau principal. Le code interdit les fonctions imbriquées dans Program.cpp.

La tortue utilise des variables globales dans le namespace turtle : position, direction, état du stylo, couleur. C’est simple pour un projet pédagogique, mais si tu maintiens longtemps le code, ce serait un bon candidat à encapsuler dans une classe.

Risques à surveiller

Un appel à une fonction inexistante peut provoquer un crash : FunctionCall::doExecute() récupère un Program*, mais ne vérifie pas s’il vaut nullptr avant de faire prog->begin().

Un programme vide peut aussi poser problème : l’interpréteur démarre avec begin() == end(), puis currentInstruction() déréférence potentiellement une position invalide.

Enfin, certaines erreurs de parsing peuvent déréférencer un token de fin si l’erreur arrive en bout de fichier. C’est typiquement le genre de bug qui apparaît avec un fichier incomplet comme avance sans nombre derrière.

Pour ajouter une nouvelle commande, le chemin habituel est : ajouter le mot-clé dans Lexer.h, créer une classe héritant de Instruction ou UnaryInstruction, puis la brancher dans Program::parseKeyword().