Phases du compilateur avec exemple : processus et étapes de compilation

Quelles sont les phases de conception du compilateur ?

Compilateur fonctionne en différentes phases, chaque phase transforme le programme source d'une représentation à une autre. Chaque phase prend les entrées de son étape précédente et transmet sa sortie à la phase suivante du compilateur.
Il y a 6 phases dans un compilateur. Chacune de ces phases aide à convertir la langue de haut niveau en code machine. Les phases d'un compilateur sont :

  1. Analyse lexicale
  2. Analyse syntaxique
  3. Analyse sémantique
  4. Générateur de code intermédiaire
  5. Optimiseur de code
  6. Générateur de code
Phases du compilateur
Phases du compilateur

Toutes ces phases convertissent le code source en le divisant en jetons, en créant des arbres d'analyse et en optimisant le code source par différentes phases.

Phase 1 : Analyse lexicale

L'analyse lexicale est la première phase au cours de laquelle le compilateur analyse le code source. Ce processus peut être effectué de gauche à droite, caractère par caractère, et regrouper ces caractères en jetons.
Ici, le flux de caractères du programme source est regroupé en séquences significatives en identifiant les jetons. Il entre les tickets correspondants dans la table des symboles et transmet ce jeton à la phase suivante.
Les principales fonctions de cette phase sont :

  • Identifier les unités lexicales dans un code source
  • Classez les unités lexicales en classes comme les constantes, les mots réservés et saisissez-les dans différents tableaux. Il ignorera les commentaires dans le programme source
  • Identifier le jeton qui ne fait pas partie du langage

Exemple:
x = y + 10

Tokens

X identifiant
= Opérateur d'assignation
Y identifiant
+ Opérateur d'addition
10 Numéro

Phase 2 : Analyse syntaxique

L'analyse syntaxique consiste à découvrir la structure du code. Il détermine si un texte suit ou non le format attendu. L'objectif principal de cette phase est de s'assurer que le code source écrit par le programmeur est correct ou non.
L'analyse syntaxique est basée sur les règles basées sur le langage de programmation spécifique en construisant l'arbre d'analyse à l'aide de jetons. Il détermine également la structure de la langue source et la grammaire ou syntaxe de la langue.
Voici une liste des tâches effectuées au cours de cette phase :

  • Obtenir des jetons de l'analyseur lexical
  • Vérifie si l'expression est syntaxiquement correcte ou non
  • Signaler toutes les erreurs de syntaxe
  • Construire une structure hiérarchique connue sous le nom d'arbre d'analyse

Exemple

Tout identifiant/numéro est une expression
Si x est un identifiant et y+10 est une expression, alors x= y+10 est une instruction.
Considérez l'arbre d'analyse pour l'exemple suivant

(a+b)*c

Exemple d'analyse syntaxique

Dans l'arbre d'analyse

  • Noeud intérieur : fiche avec un opérateur déposé et deux fiches pour enfants
  • Feuille : enregistrements avec 2 champs ou plus ; un pour le jeton et d'autres informations sur le jeton
  • Veiller à ce que les composantes du programme s’emboîtent de manière significative
  • Rassemble les informations de type et vérifie la compatibilité des types
  • Vérifie que les opérandes sont autorisés par la langue source

Phase 3 : Analyse sémantique

L'analyse sémantique vérifie la cohérence sémantique du code. Il utilise l'arbre syntaxique de la phase précédente ainsi que la table des symboles pour vérifier que le code source donné est sémantiquement cohérent. Il vérifie également si le code véhicule une signification appropriée.
Semantic Analyser vérifiera les incompatibilités de type, les opérandes incompatibles, une fonction appelée avec des arguments inappropriés, une variable non déclarée, etc.
Les fonctions de la phase d'analyse sémantique sont :

  • Vous aide à stocker les informations de type recueillies et à les enregistrer dans la table des symboles ou l'arborescence syntaxique
  • Vous permet d'effectuer une vérification de type
  • Dans le cas d'une incompatibilité de type, lorsqu'il n'existe pas de règles de correction de type exactes satisfaisant l'opération souhaitée, une erreur sémantique est affichée.
  • Collecte les informations de type et vérifie la compatibilité des types
  • Vérifie si la langue source autorise ou non les opérandes

Exemple

float x = 20.2;
float y = x*30;

Dans le code ci-dessus, l'analyseur sémantique transtypera l'entier 30 en float 30.0 avant la multiplication

Phase 4 : Génération de code intermédiaire

Une fois la phase d'analyse sémantique terminée, le compilateur génère du code intermédiaire pour la machine cible. Il représente un programme pour une machine abstraite.
Le code intermédiaire se situe entre le langage de haut niveau et le langage de niveau machine. Ce code intermédiaire doit être généré de manière à faciliter sa traduction dans le code machine cible.
Fonctions de génération de code intermédiaire :

  • Il doit être généré à partir de la représentation sémantique du programme source
  • Contient les valeurs calculées pendant le processus de traduction
  • Vous aide à traduire le code intermédiaire dans la langue cible
  • Vous permet de conserver l’ordre de priorité de la langue source
  • Il contient le nombre correct d'opérandes de l'instruction

Exemple

Par exemple,

total = count + rate * 5

Le code intermédiaire à l’aide de la méthode du code d’adresse est :

 
t1 := int_to_float(5) 
t2 := rate * t1 
t3 := count + t2
total := t3

Phase 5 : Optimisation du code

La phase suivante est l'optimisation du code ou code intermédiaire. Cette phase supprime les lignes de code inutiles et organise la séquence d'instructions pour accélérer l'exécution du programme sans gaspiller de ressources. L'objectif principal de cette phase est d'améliorer le code intermédiaire pour générer un code qui s'exécute plus rapidement et occupe moins d'espace.
Les principales fonctions de cette phase sont :

  • Il vous aide à établir un compromis entre la vitesse d'exécution et la vitesse de compilation
  • Améliore le temps d'exécution du programme cible
  • Génère du code rationalisé toujours en représentation intermédiaire
  • Suppression du code inaccessible et suppression des variables inutilisées
  • Supprimer les instructions qui ne sont pas modifiées de la boucle

Mise en situation :
Considérez le code suivant

a = intofloat(10)
b = c * a
d = e + b
f = d

Peut devenir

b =c * 10.0
f = e+b

Phase 6 : Génération de code

La génération de code est la dernière et dernière phase d'un compilateur. Il obtient les entrées des phases d’optimisation du code et produit en conséquence le code de la page ou le code objet. L'objectif de cette phase est d'allouer du stockage et de générer du code machine délocalisable.
Il alloue également des emplacements mémoire pour la variable. Les instructions du code intermédiaire sont converties en instructions machine. Cette phase convertit le code d'optimisation ou intermédiaire dans le langage cible.
La langue cible est le code machine. Par conséquent, tous les emplacements mémoire et registres sont également sélectionnés et attribués au cours de cette phase. Le code généré par cette phase est exécuté pour prendre les entrées et générer les sorties attendues.

Exemple

une = b + 60.0
Serait éventuellement traduit en registres.

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Gestion des tables de symboles

Une table de symboles contient un enregistrement pour chaque identifiant avec des champs pour les attributs de l'identifiant. Ce composant permet au compilateur de rechercher plus facilement l'enregistrement d'identifiant et de le récupérer rapidement. La table des symboles vous aide également pour la gestion du périmètre. La table des symboles et le gestionnaire d'erreurs interagissent avec toutes les phases et la table des symboles est mise à jour en conséquence.

Routine de gestion des erreurs

Dans le processus de conception du compilateur, une erreur peut survenir dans toutes les phases indiquées ci-dessous :

  • Analyseur lexical : jetons mal orthographiés
  • Analyseur de syntaxe : parenthèse manquante
  • Générateur de code intermédiaire : opérandes incompatibles pour un opérateur
  • Code Optimizer : lorsque l'instruction n'est pas accessible
  • Code Generator: Lorsque la mémoire est pleine ou que les registres appropriés ne sont pas alloués
  • Tables de symboles : erreur de plusieurs identifiants déclarés

Les erreurs les plus courantes sont les séquences de caractères non valides lors de l'analyse, les séquences de jetons non valides dans le type, les erreurs de portée et l'analyse dans l'analyse sémantique.
L'erreur peut survenir dans l'une des phases ci-dessus. Après avoir trouvé des erreurs, la phase doit traiter les erreurs pour poursuivre le processus de compilation. Ces erreurs doivent être signalées au gestionnaire d'erreurs qui gère l'erreur pour effectuer le processus de compilation. Généralement, les erreurs sont signalées sous forme de message.

Résumé

  • Le compilateur fonctionne en différentes phases, chaque phase transforme le programme source d'une représentation à une autre
  • Six phases de conception du compilateur sont 1) Analyse lexicale 2) Analyse syntaxique 3) Analyse sémantique 4) Générateur de code intermédiaire 5) Optimiseur de code 6) Code Generator
  • L'analyse lexicale est la première phase au cours de laquelle le compilateur analyse le code source
  • L'analyse syntaxique consiste à découvrir la structure du texte
  • L'analyse sémantique vérifie la cohérence sémantique du code
  • Une fois la phase d'analyse sémantique terminée le compilateur, générez du code intermédiaire pour la machine cible
  • La phase d'optimisation du code supprime les lignes de code inutiles et organise la séquence d'instructions
  • La phase de génération de code obtient les entrées de la phase d'optimisation du code et produit en conséquence le code de la page ou le code objet
  • Une table de symboles contient un enregistrement pour chaque identifiant avec des champs pour les attributs de l'identifiant
  • La routine de gestion des erreurs gère les erreurs et les rapports pendant de nombreuses phases