Chapitre 6 : Variables de type tableau
6.1 Grammaire et sémantique
On définit le langage PP2 comme une extension de PP1 autorisant la
déclaration et la manipulation de tableaux simples. On modifie la
règle VARS
pour autoriser la déclaration de tableaux ;
|
VARS |
|
::= |
|
var DECL { , DECL } ; | e |
|
|
DECL |
|
::= |
|
ID | ID [ NUM ] |
|
Sémantiquement, cela permet la déclaration de tableaux d'entiers
de dimension 1 dont la borne inférieure est toujours zéro et la
borne supérieure est indiquée par la constante NUM
(qui doit
être strictement positive). Le nombre d'éléments est
immédiatement calculé à partir de ces deux informations ; il
n'existe pas de tableau à un élément.
On modifie les règles dans lesquelles figure le non-terminal ID
(à savoir AFFEC
, LIRE
et FACT
) pour autoriser la
référence à un élément de tableau en introduisant une
règle VAR
:
|
VAR |
|
::= |
|
ID | ID [ EXPR ] |
|
|
AFFEC |
|
::= |
|
VAR := EXPR |
|
|
LIRE |
|
::= |
|
read ( VAR { , VAR } ) |
|
|
FACT |
|
::= |
|
VAR | NUM | ( EXPR ) |
|
Sémantiquement, une variable VAR
doit toujours référencer une
variable simple ou un élément de tableau. Cela revient à dire
que les noms de tableaux sont obligatoirement indicés dans une
instruction. (En particulier, l'affectation directe de tableau n'est
pas permise.)
6.2 Table des symboles
Lors de l'analyse d'une déclaration, on mémorise dans la table des
symboles la taille du tableau (nombre d'éléments). Pour les
symboles dénotant des variables simples, on mettra une taille à 1
(il n'y a pas de conflits avec les tableaux, les tableaux d'un
élément n'existant pas en PP2).
var
TABLESYM : array [TABLEINDEX] of record
NOM : ALFA ;
CLASSE : CLASSES ;
ADRESSE : integer ;
TAILLE : integer
end ;
On modifie la procédure TESTE_ET_ENTRE
pour mettre à jour cette table des symboles :
procedure TESTE_ET_ENTRE (T:TOKENS; C:CLASSES) ;
begin
if TOKEN = T
then if C <> VARIABLE
then begin ENTRERSYM (C) ; NEXT_TOKEN end
else ENTRERVARIABLE (C)
else ERREUR
end ;
La procédure ENTRERVARIABLE
se charge de l'entrée dans la table des symboles d'une variable
simple ou d'un tableau.
procedure ENTRERVARIABLE (C:CLASSES) ;
begin
if DERNIERSYM = INDEXMAX then ERREUR ;
DERNIERSYM := DERNIERSYM + 1 ;
with TABLESYM [DERNIERSYMB] do begin
NOM := SYM ;
CLASSE := C ;
TAILLE := 1 ;
ADRESSE := OFFSET
end ; (* with *)
NEXT_TOKEN ;
if TOKEN = CROCH_OUV_TOKEN then begin
(* c'est un tableau *)
NEXT_TOKEN ;
TESTE (NUM_TOKEN) ;
TESTE (CROCH_FER_TOKEN) ;
TABLESYM [DERNIERSYM]. TAILLE := VAL + 1
end ;
OFFSET := OFFSET + TABLESYM [DERNIERSYM]. TAILLE
end ;
6.3 Génération de code
La génération de code pour accéder à un élément de tableau
doit inclure la génération du code pour calculer l'adresse de cet
élément. En effet, cette adresse ne peut être calculée à la
compilation car l'élément accédé dépend de l'exécution.
Le code généré pour t [expression]
doit permettre d'obtenir
sur la pile l'adresse du (expression
+ 1)ième
élément du tableau t
; c'est-à-dire adresse (t) + expression
!
Pour cela on doit générer le P-Code :
|
LDA adresse (t) |
|
|
<code pour expression> |
|
|
ADD |
|
Donc, par exemple, pour l'affectation t [expression] := expr2
,
on génère:
|
LDA adresse (t) |
|
|
<code pour expression> |
|
|
ADD |
|
|
<code pour expr2> |
|
|
STO |
|
D'où la modification de la procédure AFFEC
:
procedure AFFEC ;
begin
TESTE_ET_CHERCHE (ID_TOKEN, VARIABLE) ;
GENERER2 (LDA, TABLESYM [PLACESYM]. ADRESSE) ;
if TABLESYM [PLACESYM]. TAILLE > 1
then begin
(* On a un tableau, il faut un [ *)
TESTE (CROCH_OUV_TOKEN) ;
EXPR ;
TESTE (CROCH_FER_TOKEN) ;
GENERER1 (ADD) ;
end ;
TESTE (AFFEC_TOKEN) ;
EXPR ;
GENERER1 (STO)
end ;
On modifie de même les procédures FACT
et LIRE
qui sont les seules à référencer des noms de tableaux.
6.4 Travaux dirigés et travaux pratiques
-
Modifier le compilateur
pp1
(qui devient pp2
) pour autoriser la
manipulation de tableaux simples.
- Modifier la grammaire de PP2 pour autoriser l'utilisation de
constantes dans la déclaration de tableaux ; par exemple :
program tab_const ;
const TAILLE = 64 ;
var tab [ TAILLE ] ;
Prendre cette nouvelle grammaire en compte pour modifier le
compilateur pp2
.
Il est aussi possible d'autoriser les tailles à être des
expressions simples et évaluables à la compilation formées à
base de constantes déclarées et/ou de littéraux. Qu'en
pensez-vous. Comment l'implémenter ? (Se reporter à
l'exercice 2.)
-
Lors de l'accès à un élément de tableau, on génère le code
nécessaire au calcul de son adresse car, de manière générale,
celle-ci ne peut pas être définie à la compilation. Cependant,
dans certains cas, il est possible de déterminer cette adresse dès
la compilation. Il n'est donc plus nécessaire de générer un tel
code. Quels sont les cas où cela est possible ? Comment prendre en
compte cette optimisation dans le compilateur
pp2
?
- On aurait pu étendre la syntaxe de PP1 de la manière suivante :
|
VARS |
|
::= |
|
var DECL { , DECL } ; | e |
|
|
DECL |
|
::= |
|
ID | ID [ NUM ] | ID [ NUM .. NUM ] |
|
Cela permet la déclaration de tableaux d'entiers indicés par un
intervalle de valeurs.
-
Que doit-on mémoriser dans la table des symboles ?
- Réécrire les procédures
ENTRERVARIABLE
et AFFEC
pour de tels tableaux.
- On peut généraliser la manipulation de tableaux à la manipulation
de tableaux à plusieurs dimensions.
-
Proposer une syntaxe pour de tels tableaux.
- Quelle est la structure en mémoire pour de tels tableaux ?
Comment obtient-on l'adresse d'un élément d'un tel
tableau ?
- Quelles informations doivent donc être rangées dans
la table des symboles lors de la déclaration d'un tableau
multi-dimensionnel ?
- Lors de l'utilisation des tableaux de dimension 1 décrits dans ce
chapitre, on ne se soucie pas d'éventuels débordements d'indices.
Faites en sorte que cette erreur soit signalée. Dans certains cas on
peut signaler l'erreur dès la compilation ; envisagez aussi cette
solution (cf. l'exercice 3 ci-dessus).
Dans le cas général, lorsque l'on dispose de la valeur de
l'indice d'un tableau sur la pile, il est nécessaire de comparer
cette valeur avec la borne supérieure du tableau et de laisser cette
valeur sur la pile pour la suite du traitement. Comment réaliser
cette opération en P-Code ? Est-il imaginable d'étendre le P-Code
par une instruction appropriée ?
En cas d'erreur pour débordement, on s'arrêtera sur une instruction
P-Code d'arrêt sur erreur OOB
(out of bounds).
-
Il est possible d'étendre la grammaire de PP2 pour autoriser
l'affectation directe entre tableaux de même taille. Pour permettre
cette affectation entre tableau, on introduit une nouvelle instruction
P-Code :
Cette instruction attend deux adresses sur la pile (
a1
au
sous-sommet et a2
au sommet) et réalise la recopie de n
valeurs lues à partir de l'adresse a2
dans les adresses
successives à partir de a1
.