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.”

ChatGPT

26 mai 2026

Ce code implémente un mini-interpréteur Logo (le langage de la tortue graphique) en C++ avec affichage graphique via SFML. Son architecture est assez propre pour un projet pédagogique : on retrouve les grandes étapes classiques d’un interpréteur :

  1. Analyse lexicale (Lexer)
  2. Analyse syntaxique (Program)
  3. Représentation interne des instructions
  4. Interprétation / exécution
  5. Affichage graphique de la tortue

1 Vue d’ensemble

Le programme lit un fichier Logo comme :

et produit un dessin en faisant avancer une tortue.

L’architecture générale est :

Fichier Logo
      │
      ▼
  Lexer.cpp
      │
      ▼
 Liste de tokens
      │
      ▼
 Program.cpp
      │
      ▼
 Arbre / liste d'instructions
      │
      ▼
 Interpreter.cpp
      │
      ▼
 Exécution instruction par instruction
      │
      ▼
 Turtle.cpp (SFML)

2 1. Le Lexer : découpage du texte

Fichier :

Lexer.cpp

Son rôle est de transformer :

en :

(TokenKeyword,"avance")
(TokenNumber,"100")
(TokenKeyword,"droite")
(TokenNumber,"90")

La fonction principale est :

TokenList getTokens(string const &s)

Le type :

typedef std::pair<TokenType,std::string> Token;

représente un mot du programme.


3 2. La classe Program : le parseur

Fichier :

Program.cpp

Cette classe transforme les tokens en objets C++ représentant les instructions.

Par exemple :

devient :

Move(100,true)

et

devient :

Turn(90,true)

3.1 Structure principale

InstructionList myInstructions;

contient toutes les instructions du programme.

Chaque élément est un :

std::unique_ptr<Instruction>

Donc on utilise le polymorphisme.


4 3. Hiérarchie des instructions

Classe de base :

class Instruction

Toutes les commandes héritent de cette classe.

Instruction
│
├── UnaryInstruction
│    ├── Move
│    └── Turn
│
├── SetPenPos
│
└── FunctionCall

4.1 Move

avance 100
recule 100

sont représentés par :

Move

Le booléen :

isForward

indique s’il s’agit d’un avance ou d’un recule.


4.2 Turn

droite 90
gauche 90

sont représentés par :

Turn

Le booléen :

isClockwise

indique le sens de rotation.


4.3 SetPenPos

active ou désactive le stylo.


4.4 FunctionCall

Lorsque le parseur rencontre :

il crée :

FunctionCall("carre")

qui appellera la fonction Logo correspondante.


5 4. UnaryInstruction

Classe intermédiaire :

class UnaryInstruction

Elle factorise toutes les instructions ayant un seul paramètre numérique.

Exemple :

Les deux possèdent :

int myParameter;

Le constructeur vérifie :

if(currentPos->first != TokenNumber)

et convertit le texte en entier.


6 5. Le moteur d’exécution

Classe :

Interpreter

C’est le cœur du système.


6.1 Compilation

Dans le constructeur :

parse(code);

on fait :

tokens

Program

et on obtient :

myProgram

6.2 Démarrage

startProgram();

initialise la pile d’exécution :

myCallStack

avec le programme principal.


6.3 Exécution

nextStep();

fait exactement une instruction.

Pseudo-code :

instruction courante

execute()

calcul instruction suivante

mettre à jour le pointeur

7 6. Gestion des appels de fonction

C’est la partie la plus intéressante.

Le programme utilise :

std::vector<ExecutionContext> myCallStack;

comme une pile d’appels.


7.1 ExecutionContext

Contient :

InstructionPointer myCurrentPos;
InstructionPointer myEndOfBlock;

Autrement dit :

où suis-je ?
où se termine mon bloc ?

7.1.1 Exemple

Programme :

Pile :

Main

Lorsque :

est exécuté :

FunctionCall::doExecute()

fait :

pushNewContext(...)

La pile devient :

Main
└── carre

Quand la fonction se termine :

myCallStack.pop_back();

et on revient au programme principal.


8 7. Navigation entre instructions

Chaque instruction sait calculer :

InstructionPointer getNext(...)

Par défaut :

return ++interpreter.currentPos();

Donc :

instruction suivante

8.1 Cas particulier : FunctionCall

Lorsqu’une fonction est appelée :

return interpreter.currentPos();

On ne passe pas à l’instruction suivante immédiatement.

Pourquoi ?

Parce qu’on vient d’empiler un nouveau contexte d’exécution.

L’instruction suivante doit être la première de la fonction appelée.


9 8. Partie graphique

Namespace :

namespace turtle

Fichier :

Turtle.cpp

Variables globales :

double turtleX;
double turtleY;
double turtleDir;

représentent :

position X
position Y
orientation

9.1 Avancer

Dans :

Move::doExecute()

on utilise :

sin()
cos()

pour calculer la nouvelle position.

turtleX += ...
turtleY -= ...

9.2 Tracer

Si :

turtlePenDown

alors :

drawLine(...)

ajoute un segment dans :

sf::VertexArray lines

9.3 Rotation

Turn::doExecute()

modifie :

turtleDir

10 9. Fonction main()

Le déroulement est :

ouvrir fichier

↓
compiler

↓
afficher programme

↓
initialiser tortue

↓
startProgram()

↓
tant que programme actif

    nextStep()

    redraw()

    sleep()

↓
attendre fermeture fenêtre

11 Points faibles à connaître pour la maintenance

11.1 1. Variables inachevées

Dans :

ExecutionContext

on trouve :

std::map<std::string,int> myVariables;

et :

int &variable(...)

mais aucune instruction ne les utilise.

Cela ressemble à une fonctionnalité prévue mais non terminée.


11.2 2. Absence de vérification d’appel de fonction

Dans :

FunctionCall::doExecute()

on trouve :

Program *prog = myMainProgram.findSubProgram(myName);

puis immédiatement :

prog->begin()

Si la fonction n’existe pas :

prog == nullptr

⇒ crash.

Il faudrait ajouter :

if(!prog)
    throw std::runtime_error("Unknown function");

11.3 3. Beaucoup d’états globaux

Le namespace :

turtle

contient de nombreuses variables globales :

turtleX
turtleY
turtleDir
...

C’est simple mais peu robuste.

Une classe :

class Turtle

serait plus maintenable.


11.4 4. Pas de boucle repete

Le mot-clé :

repete

est reconnu par le lexer :

kwRepeat

mais n’est jamais implémenté dans :

Program::parseKeyword()

Donc le langage est incomplet.


12 Ce qu’il faut absolument retenir

Pour maintenir ce code, les 4 classes les plus importantes sont :

  1. Lexer → transforme le texte en tokens.
  2. Program → transforme les tokens en objets Instruction.
  3. Interpreter → exécute les instructions et gère la pile d’appels.
  4. Turtle → affiche graphiquement les effets des instructions.

Si vous comprenez le chemin :

Texte Logo
   ↓
Lexer
   ↓
Program
   ↓
Instruction
   ↓
Interpreter
   ↓
Turtle

alors vous maîtrisez déjà environ 80 % du fonctionnement de ce projet.