Vous êtes sur la page 1sur 15

Compilation de langages de programmation C.

HEMDANI

Chapitre 2 : L’analyse lexicale


La tache principale d’un analyseur lexical consiste à lire un programme source carac-
tère par caractère et à produire en sortie une séquence d’unités lexicales dites tokens, qui
sera traitée par l’analyseur syntaxique.
L’interaction entre l’analyseur lexical et l’analyseur syntaxique peut être résumée par
la figure 1.

Demande du
token suivant
Programme Analyseur Analyseur
source lexical syntaxique
Token

F IGURE 1 – Interaction entre l’analyseur lexical et l’analyseur syntaxique.

L’analyseur lexical peut être vu comme une fonction qui à chaque fois quelle est ap-
pelée par l’analyseur syntaxique, lit le programme source caractère par caractère jusqu’à
ce quelle identifie le token suivant qu’elle retourne alors à l’analyseur syntaxique.
La lecture commence avec le caractère suivant la fin du dernier token reconnu et ce
termine avec la reconnaissance du plus long préfixe de la séquence de caractères restante
qui constitue un symbole (une unité lexicale) du langage.
Les symboles seront décrits par des expressions régulières et on utilisera des auto-
mates d’états finis simples et déterministes pour les reconnaître.

1 Rappels sur les langages réguliers


1.1 Les langages réguliers
Un langage régulier sur un alphabet Σ est défini inductivement comme suit :
— φ et {ε} sont des langages réguliers sur Σ ;
— ∀a ∈ Σ, {a} est un langage régulier sur Σ ;
— si L1 et L2 sont des langages réguliers sur Σ alors L1 ∪ L2 , L1 L2 et L∗1 sont des
langages réguliers sur Σ.

1.2 Les expressions régulières


Les expressions régulières sur un alphabet Σ sont définies inductivement par :
— φ est une expression régulière sur Σ ; elle décrit le langage φ ;
— ε est une expression régulière sur Σ ; elle décrit le langage {ε} ;
— ∀a ∈ Σ, a est une expression régulière sur Σ ; elle décrit le langage {a} ;
— si e1 et e2 sont des expressions régulières sur Σ, décrivant respectivement L1 et
L2 , alors e1 |e2 , e1 e2 et e∗1 sont des expressions régulières sur Σ ; elles décrivent,
respectivement, les langages L1 ∪ L2 , L1 L2 et L∗1 .
Au lieu de décrire les symboles d’un langage sources par des grammaires régulières,
on utilise le formalisme des expressions régulières car elles sont :
— plus compactes,
— mieux lisibles, et
— plus faciles à traiter par les programmes.

1
Abréviations

e+ ≡ e e∗ : l’itération positive
e? ≡ e|ε : l’option
en ≡ e e ... e : n fois e
[ab] ≡ a|b : un caractère parmi plusieurs
[a − c] ≡ a|b|c : une plage de caractères

Remarque 1
En compilation, les expressions régulières seront utilisées pour décrire les symboles
d’un langage de programmation dont les programmes ne sont rien d’autre qu’une suite
de caractères du code ASCII. De ce fait, nous considérerons toujours comme alphabet Σ
l’ensemble des caractères du code ASCII. 2

1.3 Les définitions régulières


Une définition régulière est une séquence de définitions de la forme :

d1 = e1
d2 = e2
..
.
dn = en

où (di )i=1..n sont des noms distincts et ei une expression régulière sur l’ensemble de
symboles Σ ∪ {d1 , . . . , di−1 }.

Exemple 1
1. Une définition régulière pour les identificateurs peut être :

lettre = A| · · · |Z|a| · · · |z
chif f re = 0| · · · |9
ident = lettre ( lettre | chif f re )∗

2. Une définition régulière pour les constantes numériques serait

chif f re = [0 − 9]
chif f res = chif f re+
partie_f ractionnaire = (  chif f res ) ?
exposant = ( ( E | e ) [+−]? chif f res ) ?
num = chif f res partie_f ractionnaire exposant

2 Tokens, modèles et lexèmes


Certaines chaînes de caractères d’un programme source ont une même structure et
une même fonction syntaxique, on les regroupe alors en une classe dite token.
Cette classe est décrite par une expression régulière dite modèle associé au token. On
dit que le modèle filtre chaque chaîne de la classe.
Un lexème est une séquence de caractères du programme source filtrée par le modèle
d’un token.
Exemple 2
Dans un programme contenant la déclaration :

2
var
nom:string;
la sous chaîne ”nom” est un lexème filtré par le modèle lettre(lettre|chif f re)∗ du token iden-
tificateur souvent abrégé par id, ou ident. En général, quand l’analyseur lexical reconnaît
un lexème filtré par le modèle lettre(lettre|chif f re)∗ , il retourne un token id à l’analyseur
syntaxique. 2
Exemple 3
Des exemples de tokens et lexèmes correspondants sont donnés dans la table sui-
vante :
Token Lexèmes
ID i, x1, prix_total, . . .
NUM 2, 0.25, 1.5E − 4, −13, . . .
LIT ERAL ”erreur lexicale !”
OP +, −, . . .
CM P <, >, <=, . . .

Les différents tokens rencontrés dans la plus part des langages de programmation
sont :
— les mots clés,
— les opérateurs,
— les identificateurs,
— les constantes (numériques, booléennes, ...),
— les chaînes littérales,
— les séparateurs (parenthèses, virgule, point-virgule, ...),
— ...
Remarque 2
Les tokens représentent les symboles terminaux de la grammaire qui engendre le
langage source. 2

3 Attributs des tokens


Si la connaissance seule du token suffit à l’analyse syntaxique, il n’en est pas de
même pour l’analyse sémantique et la génération de code. Ces phases pourront avoir
besoin d’informations supplémentaires, dites attributs, relatives au lexème particulier
reconnu.
En pratique, un token a zéro ou un seul attribut qui consiste en :
— un nom s’il s’agit d’un identificateur,
— une valeur, s’il s’agit d’une constante,
— un code s’il s’agit d’un opérateur,
— aucun attribut, s’il s’agit d’un mot clé ou d’un symbole particulier.
L’analyseur lexical devra donc renvoyer des couples de la forme
< token, attribut >

Exemple 4
Les tokens et attributs associés à la déclaration en langage C suivante :
f loat x = 1.5E2 ;
sont
< REEL, > , < ID, “x”> , < ASSIGN, > , < N U M, 150 > et < P V, > 2

3
4 Reconnaissance des tokens

Comme les tokens sont décrits par des expressions régulières (leurs modèles), on uti-
lisera des automates d’états fini simples et déterministes pour les reconnaître.

4.1 Conception d’un analyseur lexical


La conception d’un analyseur lexical pour un langage quelconque peut se faire selon
les étapes suivantes :
1. Déterminer les différents tokens ti du langage ainsi que leurs modèles ei et leurs
attributs ai .
2. Construire l’automate d’états fini simple et déterministe permettant :
— d’ignorer les blancs et les commentaires, et
— de reconnaître l’ensemble des tokens ti .
Dans cet automate,
— aucune transition n’est permise à partir d’un état final, et
— chaque état final sert à terminer la reconnaissance d’un et d’un seul token.
3. Associer des actions à entreprendre au niveau des états finaux ; celles-ci consistent
généralement à :
— reculer sur la chaîne d’entrée,
— calculer la valeur d’un attribut ai d’un token ti ,
— retourner un couple < ti , ai >.

Remarque 3
1. Par souci d’efficacité, il faut coder les tokens et les codes d’attributs par des nombres
entiers qu’il est préférable de définir comme des constantes ou dans des types énu-
mérés.
2. Pour faire en sorte qu’il n’y ait pas de transitions à partir d’un état final, on procède
comme suit :
Remplacer chaque transition de la forme :
action i
si a sj

par :
si a sj

=a sk reculer
action i

et dans le cas général, remplacer toutes transitions de la forme :


action i
si a1 sj1

a2 sj2

an sjn

4
par :

si a1 sj1

an sjn

autre sk reculer
action i

où sk devra être un nouvel état.

Exemple 5
Soit le mini-langage dont la syntaxe est décrite par la grammaire :

P −→ P ;P |I
I −→ if (E == E) I | id = E | ε
E −→ E op E | (E) | id | num

où op désigne l’un des opérateurs arithmétiques + ou − ; id est un identificateur


constitué d’une séquence de lettres minuscules et de chiffres décimaux, commençant
par une lettre ; num est un nombre entier constitué d’une séquence non vide de chiffres
décimaux.

Le tableau suivant donne une description des tokens du mini-langage.

token modèle attribut


F IN \0 | EOF
PV ;
IF if
EGAL ==
ASSIGN =
OP +|− COP ∈{P LU S, M OIN S}
P ARG (
P ARD )
ID lettre(lettre | chif f re)∗ nom
NUM chif f re+ valeur entière

Dans le tableau ci-dessus,


— lettre et chif f re désignent respectivement, l’expression régulière [a − z] et [0 − 9].
— \0 est la marque de fin de chaîne.
— Le token (ou le pseudo-token) F IN est nécessaire pour l’analyse syntaxique ; il
servira à repérer la fin du programme. De ce fait, on utilise toujours ce token auquel
on donne par convention le code entier 0.

Un DFA reconnaissant les différents tokens et incluant les actions aux niveaux des
états d’acceptation serait :

5
reculer
s7 retourner<NUM, valeur>

s8 reculer

re
autre

aut
retourner<IF, >

c
s3
s1 l|c
f autre
retourner<PV, > s9 reculer
s6 s2 l=f|c autre retourner<ID, nom>
c s4
i
; l=i l|c
’’
s0 = =
s5 s10 retourner<EGAL, >
0 au
tre
+|−
s15
( ) s11 reculer
retourner<FIN, > s12 retourner<ASSIGN, >

s13 retourner<OP, COP>

s14
retourner<PARD, >
retourner<PARG, >

4.2 Implémentation d’un analyseur lexical


Une implémentation méthodique et efficace passe par les étapes suivantes :
1. Coder les états de l’automate par des entiers distincts.
2. Coder les caractères ou classes de caractères par des entiers distincts.
3. Définir une fonction car_suivant() qui renvoie le code du prochain caractère
du tampon d’entrée ; cette fonction assure la codification des caractères ; pour la
gestion du tampon d’entrée, utiliser deux pointeurs :
— un pointeur debut pour indiquer la position de début d’un lexème ;
— un pointeur position indiquant la position du prochain caractère à lire par la
fonction car_suivant().
4. Déclarer deux variables entières (etat et cc) dont l’une contiendra le code de l’état
courant et l’autre le code du caractère courant.
5. Déclarer une variable (attribut) de type union qui contiendra la valeur d’attribut
du dernier token reconnu.
6. Définir une procédure de gestion des erreurs lexicales (erreur_lexicale()).

4.2.1 Simulation d’un DFA par un programme

Pour simuler un DFA par un programme, on affecte un fragment de code à chaque


état de l’automate. Chaque fragment de code (dont le contenu dépend de l’état) est écrit
comme décrit par l’algorithme 1.

6
Algorithme 1 Simulation d’un DFA.
si il y a des transitions à partir de l’état alors
lire le caractère suivant ;
si il existe une transition sur ce caractère alors
réaliser la transition /* modifier l’état */
sinon
appeler la procédure de gestion d’erreurs
si non /* l’état est final */
exécuter les actions associées à l’état

Exemple 6
Nous donnons dans cet exemple un programme en langage C simulant le DFA de
l’exemple 5. La codification des caractères est donnée par la table suivante.

Caractère Code entier


\0 0
[a − eghj − z] 1
i 2
f 3
[0 − 9] 4
= 5
+|− 6
( 7
) 8
; 9
0 0 10
autre 11

autre désigne tout caractère différent de tous ceux qui l’ont précédé ; c’est en fait tout
caractère illégal.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum TOKEN {FIN=0, PV, IF, EGAL, ASSIGN,


OP, PARG, PARD, ID, NUM}; /* codification des tokens */

enum CODEOPERATION {PLUS, MOINS}; /* codification des valeurs


d’attribut du token OP
*/

char programme[256]; /* contiendra la chaîne d’entrée;


i.e., le programme source.
*/
int debut, position;

union {
char * nom;
int valeur;
enum CODEOPERATION cop;
} attribut; /* cette variable contiendra la valeur
d’attribut du dernier token reconu.
*/

7
/* La fonction car_suivant() retourne le code du prochain caractère du
programme source et incrémente la variable position. C’est cette fonction
qui assure la codification des caractères.
* /
int car_suivant(){
int cc; /* caractère courant */

if (position > strlen(programme)) return 0; /* fin du programme */

cc=programme[position++]; /* lecture du caractère et incrémentation


de la variable position.
* /
if (cc==’\0’) return 0;
if (cc>=’a’ && cc<=’z’ && cc!=’i’ && cc!=’f’) return 1;
if (cc==’i’) return 2;
if (cc==’f’) return 3;
if (cc>=’0’ && cc<=’9’) return 4;
if (cc==’=’) return 5;
if (cc==’+’ || cc==’-’) return 6;
if (cc==’(’) return 7;
if (cc==’)’) return 8;
if (cc==’;’) return 9;
if (cc==’ ’) return 10;
return 11; /* autre */
}

/* La fonction reculer() permet de reculer d’une position sur le programme


source.
* /
void reculer(){
position --;
}

/* La fonction erreur_lexicale() est notre procédure de gestion d’erreurs


lexicales: elle affiche un diagnostic de l’erreur et arrète le programme
par appel à la fonction exit() déclarée dans stdlib.h.
*/
void erreur_lexicale(){
printf("position %d: le caractère ’%c’ est illégal!\n",
position,programme[position-1]);
exit(-1);
}

/* La fonction get_lexeme() permet de récupérer le dernier lexème reconu.


Elle utilise les fonctions malloc() et strncpy() déclarées,
respectivement, dans stdlib.h et string.h.

*/
char* get_lexeme(){
int longueur=position-debut; /* longueur du lexème */
char* lexeme=(char*) malloc(longueur+1); /* réservation de l’espace
mémoire.
*/
strncpy(lexeme,programme+debut,longueur); /* le lexème commence à
l’adresse programme+debut.
*/
lexeme[longueur]=’\0’;
return lexeme;
}

8
/* token_suivant() est la fonction princiaple de l’analyseur lexical; c’est
elle qui assure la simulation du DFA. A chaque appel, elle retourne le
prochain token dont elle place la valeur d’attribut dans la variable
attribut.
* /
enum TOKEN token_suivant(){

int cc;
int etat;

etat=0;
while (1){
switch (etat){
case 0: debut=position;
cc=car_suivant();
switch(cc){
case 0: etat=15;
break;
case 1: etat=4;
break;
case 2: etat=2;
break;
case 3: etat=4;
break;
case 4: etat=1;
break;
case 5: etat=5;
break;
case 6: etat=12;
break;
case 7: etat=14;
break;
case 8: etat=13;
break;
case 9: etat=6;
break;
case 10: break;
default: erreur_lexicale();
}
break;
case 1: cc=car_suivant();
while (cc==4)
cc=car_suivant();
etat=7;
break;
case 2: cc=car_suivant();
switch(cc){
case 3: etat=3;
break;
case 1:
case 2:
case 4: etat=4;
break;
default: etat=9;
}
break;
case 3: cc=car_suivant();
switch(cc){
case 1:
case 2:
case 3:

9
case 4: etat=4;
break;
default: etat=8;
}
break;
case 4: cc=car_suivant();
while (cc>=1 && cc<=4)
cc=car_suivant();
etat=9;
break;
case 5: cc=car_suivant();
if (cc==5) etat=10;
else etat=11;
break;
case 6: return PV;
case 7: reculer();
attribut.valeur=atoi(get_lexeme()); /* calcul de la valeur */
return NUM;
case 8: reculer();
return IF;
case 9: reculer();
attribut.nom=get_lexeme();
return ID;
case 10: return EGAL;
case 11: reculer();
return ASSIGN;
case 12: if(get_lexeme()[0]==’+’) attribut.cop=PLUS;
else attribut.cop=MOINS;
return OP;
case 13: return PARD;
case 14: return PARG;
case 15: return FIN;
}
}
}

/* En pratique, la fonction principale main() n’est pas nécessaire; sa


présence ne se justifie que par l’absence d’un analyseur syntaxique
qui ferait appel à la fonction token_suivant().
*/
int main(){

enum TOKEN tc; /* token suivant */

printf("Taper un programme:\n");
printf("------------------\n\n");
scanf("%[\40-\176]", programme);

position=0;

printf("\n\nSéquence des couples <token, attribut>\n");


printf("--------------------------------------\n");

while (tc=token_suivant()){
switch(tc){
case PV: printf("<PV, >\n");
break;
case IF: printf("<IF, >\n");
break;
case EGAL: printf("<EGAL, >\n");
break;

10
case ASSIGN: printf("<ASSIGN, >\n");
break;
case OP: printf("<OP, ");
if (attribut.cop==PLUS) printf("PLUS>\n");
else printf("MOINS>\n");
break;
case PARG: printf("<PARG, >\n");
break;
case PARD: printf("<PARD, >\n");
break;
case ID: printf("<ID, %s>\n",attribut.nom);
break;
case NUM: printf("<NUM, %d>\n",attribut.valeur);
}
}
printf("<FIN, >\n");
return 0;
}

/*
Exemples d’exécution
====================

Exemple 1
=========

Taper un programme:
------------------

if (x1=max) y=ifs+13-max

Séquence des couples <token, attribut>


--------------------------------------
<IF, >
<PARG, >
<ID, x1>
<ASSIGN, >
<ID, max>
<PARD, >
<ID, y>
<ASSIGN, >
<ID, ifs>
<OP, PLUS>
<NUM, 13>
<OP, MOINS>
<ID, max>
<FIN, >

Exemple 2
=========

Taper un programme:
------------------

if (x1*2==max) y=ifs+13-max

Séquence des couples <token, attribut>


--------------------------------------
<IF, >

11
<PARG, >
<ID, x1>
position 7: le caractère ’*’ est illégal!

*/
2

Remarque 4
Le programme est téléchargeable à partir du site web du module. 2

4.2.2 Implémentation au moyen d’une table de transition

On utilise une table bidimensionnelle delta indexée par les états non finaux de l’auto-
mate et les caractères de l’alphabet d’entrée. Les états et les caractères sont alors codés
par des entiers consécutifs.

Construction de la table

Soit A = < Σ, Q, q0 , δ, F > un automate d’états fini déterministe, l’algorithme 2 montre


comment construire sa table de transition.

Algorithme 2 Construction d’une table de transition.


pour chaque état qi ∈ Q\F f aire
pour chaque caractère d’entrée c f aire
si la transition δ(qi , c) existe alors
delta[i, cc]:=j /* i et j sont les codes de qi et qj */
sinon /* cc est le code de c */
delta[i, cc]:=−1
f ait
f ait

Les entrées de valeur −1 construites par l’algorithme, correspondent à des cas d’er-
reurs ; i.e., des transitions non définies.

Exemple 7
Reprenons l’automate de l’exemple 5 dont la codification des caractères est donnée
dans l’exemple 6. On donne ci-après la table de transition construite par l’algorithme 2.

0 1 2 3 4 5 6 7 8 9 10 11
0 15 4 2 4 1 5 12 14 13 6 0 -1
1 7 7 7 7 1 7 7 7 7 7 7 7
2 9 4 4 3 4 9 9 9 9 9 9 9
3 8 4 4 4 4 8 8 8 8 8 8 8
4 9 4 4 4 4 9 9 9 9 9 9 9
5 11 11 11 11 11 10 11 11 11 11 11 11

Algorithme d’analyse

En utilisant la table de transition, l’analyse lexicale se fait tel que décrit par l’algo-
rithme 3.

12
Algorithme 3 Algorithme d’analyse lexicale.
etat := 0;
tantque etat 6∈ F ∪ {−1} f aire
si etat = 0 alors
debut := position;
f insi;
cc := car_suivant();
etat:=delta[etat, cc];
f ait
si etat ∈ F alors
exécuter les actions associées à etat
sinon /* etat = −1 */
appeler la procédure de gestion d’erreurs

Exemple 8
Pour l’implémentation en langage C de l’analyseur lexical du mini-langage considéré
dans l’exemple 5, il suffit de reprendre le programme donné dans l’exemple 6 et
1. d’ajouter la définition de la table de transition comme suit :
int delta [6][12]={ { 15, 4, 2, 4, 1, 5, 12, 14, 13, 6, 0, -1 },
{ 7, 7, 7, 7, 1, 7, 7, 7, 7, 7, 7, 7 },
{ 9, 4, 4, 3, 4, 9, 9, 9, 9, 9, 9, 9 },
{ 8, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8 },
{ 9, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 9 },
{ 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11 }
};

2. puis, de remplacer la fonction token_suivant() par la suivante :

enum TOKEN token_suivant(){


int cc;
int etat;

etat=0;
while(etat !=-1 && etat<=5){
if (etat== 0) debut=position;
cc=car_suivant();
etat=delta[etat][cc];
}
switch (etat){
case 6: return PV;
case 7: reculer();
attribut.valeur=atoi(get_lexeme());
return NUM;
case 8: reculer();
return IF;
case 9: reculer();
attribut.nom=get_lexeme();
return ID;
case 10: return EGAL;
case 11: reculer();
return ASSIGN;
case 12: if(get_lexeme()[0]==’+’) attribut.cop=PLUS;
else attribut.cop=MOINS;
return OP;

13
case 13: return PARD;
case 14: return PARG;
case 15: return FIN;
default: erreur_lexicale(); /* etat = -1 */
}
}

Le programme obtenu donne exactement le même résultat que celui donné dans
l’exemple 6. Le fichier source complet est téléchargeable en tant que tel à partir du site
web du module. 2

Remarque 5
L’avantage de l’utilisation d’une table de transition est que l’accès à l’état suivant
( delta[etat, cc] ) est rapide. Son inconvénient est que la table peut contenir trop de cas
de transitions indéfinies (matrice creuse) et dans ce cas, la table occupe trop d’espace
mémoire. 2

4.2.3 Méthode de compression d’une table de transition

La table compressée (ou compacte) sera constituée de trois vecteurs :


— un vecteur Etat dont chaque entrée correspond à un état ; i.e., à une ligne de la
table bidimensionnelle,
— un vecteur Delta qui contiendra les transitions à partir de tous les états,
— un vecteur V alide de même longueur que Delta indiquant à quel état i appartient
une transition Delta[j].
Schématiquement, on représente la table compacte comme suit :

0 1 2 m
Delta

0
0
1
1
2
2

n
m
Etat Valide

Le principe de compression étant de ranger toutes les lignes de la table de transition


dans le vecteur Delta en veillant à minimiser sa longueur. Les lignes peuvent se chevau-
cher mais aucune transition définie ne doit être perdue (écrasée).

Exemple 9
Considérons la table de transition bidimensionnelle suivante :

-1 2 -1 3 -1
-1 4 1 -1 -1
-1 -1 -1 -1 1
-1 -1 4 -1 -1

La table compacte correspondante sera :

14
0 1 2 3 4 5 6 7
Delta -1 2 4 3 4 1 1 -1

0 -1
1 0
0 0 2 3
1 3 3 0
2 2 4 1
3 0 5 1
6 2
Etat 7 -1
Valide
2

Soit etat l’état courant et cc le code du caractère courant ; la détermination de l’état


suivant à partir d’une table compacte se fait selon le code :
si valide[Etat[etat] + cc] = etat alors
etat := delta[Etat[i] + cc]
si non
etat := −1

5 Traitement des mots réservés


Trois techniques principales peuvent êtres utilisées.

5.1 Mots réservés inclus dans l’automate global


Un inconvénient de cette méthode est que l’automate aura un très grand nombre
d’états ; par conséquent la table de transition où le programme qui l’implémente occupera
beaucoup de place mémoire.

5.2 Utilisation d’une table des mots réservés


Utiliser une table statique (de taille fixe) ayant une entrée pour chaque mot réservé.
Chaque entrée de la table des mots réservés est un enregistrement ayant les deux champs :
— La chaîne de caractère constituant le lexème,
— un entier indiquant le token correspondant.

Les mots réservés sont traités comme des identificateurs spéciaux : à chaque fois
qu’un identificateur est reconnu, cette table est consultée pour déterminer s’il s’agit d’un
mot réservé. Si tel est le cas, le token correspondant est renvoyé, si non il s’agit donc d’un
identificateur.
Remarque 6
Pour accélérer la recherche, la table est triée par ordre alphabétique des mots réservés
et la recherche est dichotomique. 2

5.3 Mots réservés dans la table des symboles


Avant de commencer la reconnaissance des tokens, la table des symboles est initiali-
sée par l’ensemble des mots réservés. Quand un identificateur est reconnu, la table des
symboles est consultée. Si le lexème correspond à un mot réservé, le token correspondant
est renvoyé ; si non, il est traité comme un identificateur.

15

Vous aimerez peut-être aussi