Précédent Index Suivant

Chapitre 12 :   Procédures paramétrées

On introduit donc ici les procédures paramétrées ; l'extension de PP6 ainsi construite se nomme PP8. (PP8 est une extension de PP6, on ne reprend donc pas les procédures imbriquées.)

12.1   Grammaire et sémantique

12.1.1   Définition de procédures

Les règles suivantes de la grammaire de PP6 sont modifiées
PROGRAM ::= program ID ; BLOCK .
BLOCK ::= CONSTS VARS PROCS INSTS
PROCS ::= { proc ID PARAMLIST ; CONSTS VARS INSTS ; }
PARAMLIST ::= ( PARAMDECL { , PARAMDECL } ) | e
PARAMDECL ::= var ID | ID
La règle PARAMLIST définit la liste des paramètres formels de la procédure.

12.1.2   Appel de procédure

L'appel de procédure peut maintenant comporter une liste de paramètres effectifs :
APPEL ::= ID PARAMEFFLIST
PARAMEFFLIST ::= ( PARAMEFF { , PARAMEFF } ) | e
PARAMEFF ::= EXPR
Sémantiquement, le nombre de paramètres effectifs de l'appel de procédure doit correspondre au nombre de paramètres déclarés dans la définition de la procédure. Il est possible au compilateur de vérifier le respect de cette règle sémantique en associant le nombre de paramètres de la procédure à son entrée dans la table des symboles.

12.1.3   Passages de paramètre par valeur et par adresse

Contrairement à d'autres langages, deux types de passage de paramètres existent en Pascal. En Fortran, tous les passages de paramètres se font par adresse ; en C tous les passages de paramètres se font par valeur1.

Afin de différencier les deux types de passages de paramètres, les définitions de paramètres formels PARAMDECL peuvent être étiquetées par le mot clé var pour indiquer un passage par adresse ; dans le cas contraire , il s'agit d'un passage par valeur.

Le paramètre effectif correspondant à une définition de paramètre formel déclaré var est une expression EXPR limitée à un identificateur ID (cf. figure 2.2).

Un paramètre effectif correspondant à un passage par valeur est une expression EXPR. Cette expression est évaluée et sa valeur est passée à la procédure.

12.2   Implémentation du passage de paramètre par valeur

12.2.1   Allocation mémoire des paramètres

Les paramètres d'une procédure ne peuvent être connus avant l'exécution. De plus, ils sont différents à chaque appel. L'idée de base est qu'une procédure retrouve ses paramètres sur la pile sous la zone qui lui est allouée, cf figure 12.1




                                    |----------|    
                                    |          |    
                                    |          |<--- zone allouee pour     
                                    |          |     l'appel (AR 
                                    |          |     + liens statiques
                    BASE ---------> |          |     + variables locales) 
                                    |----------|
                                    |          |<--- parametres effectifs 
                                    |          |     de l'appel
                                    |----------|
                                    |          |
                                    |          | 
                                    +----------+
Figure 12.1 : État de la pile juste après l'appel d'une procédure.


Ainsi, les paramètres seront accédés grâce à un déplacement négatif relatif à BASE.

12.2.2   Génération de code

Le code à générer pour un appel de procédure doit inclure
  1. Le P-Code empilant les valeurs des paramètres effectifs.
  2. Une instruction P-Code CAL i réalisant le branchement nécessaire à l'appel de la procédure.
On modifie l'instruction P-Code RET de retour de procédure qui accepte maintenant un paramètre :
 RET  n  
Ce paramètre correspond au nombre de paramètres devant être dépilés pour mettre à jour la variable SP du compilateur. On modifie donc l'interpréteur P-Code (section 9.2) en conséquence :
with INST do
   case MNE of
      ...
      RET : begin 
         PC   := MEM [BASE] ; 
         SP   := SP - SUITE ; 
         BASE := MEM [BASE + 1]
      end ;  
   end 
Prenons en exemple le code PP8 suivant :
 program X ; 
 var A ; 
 proc Y (N) ; 
    begin 
       write (N) 
    end ;
 begin 
    read (A) ; 
    Y (A+2)
 end . 
On générera le P-Code suivant :
0   INT 1   réserve 1 emplacement pour A
1   BRN 6   saut au début du programme principal
#       début de la fonction Y
2   LDL -3   empile l'adresse de N
3   LDV   accède la valeur de N
4   PRN
5   RET 1
#       début du programme
6   LDA 0   adresse de A
7   INN   lecture d'une valeur dans A
8   LDA 0   adresse de A
9   LDV   valeur de A
10   LDI 2   2
11   ADD   addition : la valeur est sur la pile
12   CAL 2   appel de Y
13   HLT    

La pile avant l'exécution de l'instruction LDL -3 de la ligne 2 est schématisée à la figure 12.2.



                     |          |<-------- variables locales
                     |          |
                     |----------|
                     |     -----|---+
                     |----------|   |
                     |    AR    |<-------- BASE
                     |----------|   |
                     |    N     |   |
                     |----------|   V
                     |          |
Figure 12.2 : État de la pile juste avant l'exécution de LDL -3.


Le paramètre de l'instruction LDL a pour valeur -3 car l'instruction LDL i référence l'emplacement mémoire BASE+2-i (cf. exercice 5).

12.3   Implémentation du passage de paramètre par adresse

Le mécanisme mis en place pour accéder les paramètres passés par adresse est semblable à celui mis en place pour les passages par valeur.

L'appelant laisse sur la pile non pas la valeur du paramètre effectif, mais son adresse.

L'accès à un paramètre formel se fait de la manière suivante :

12.4   Travaux dirigés et travaux pratiques

  1. Quels sont les avantages de proposer les deux types de passage de paramètre par adresse et par valeur au sein d'un même langage. Comparer avec les approches de Fortran (passage par adresse uniquement) et C (passage par valeur uniquement).

  2. Qu'advient-il si, dans un code Pascal, on passe une expression non réduite à un nom de variable comme paramètre effectif dont le paramètre correspondant est déclaré var ? Comment un compilateur Pascal peut-il détecter une telle erreur ?

  3. Implanter dans un premier temps le passage de paramètre par valeur. Étendre cette implantation au passage par adresse.

  4. Quels problèmes nouveaux surviennent si l'on désire étendre le passage de paramètre à des variables et valeurs de type différents (entiers et réels, puis tableaux, structures et types construits) ?

1
Cette limitation apparente est contournée par la possibilité de passer par valeur des adresses ; le passage par adresse est donc à la charge du programmeur.

Précédent Index Suivant