<!doctype linuxdoc  system>
<report opts="a4,francais">
<title>Le langage Fortran 77
<author> Michel Billaud <tt/&lt;billaud@labri.u-bordeaux.fr&gt;/
<date>Août 1999
<abstract>
Support de cours pour l'enseignement de Fortran 77
en première année en IUT. Ecrit sous WordStar vers 1985-1987. Converti
en SGML (DTD Linuxdoc) en août 1999, avec quelques  légères
corrections.

<toc>
<chapt> Le langage Fortran 77 <p>

<sect> Objets de base du Fortran 77<p>

<sect1> Jeu de caractères<p>

<itemize>
<item>  Alphabet Majuscule : A B C ... Z
<item>  Alphabet Minuscule : a b c ... z
<item>            Chiffres : 0 1 2 ... 9
<item> Caractères spéciaux : + - * / = ( ) &lt; &gt; . ; &dollar;  _  '   etc.
</itemize>
 

<sect1> Èléments du langage <p>

<sect2>Noms d'instructions, mots réservés<p>

<tscreen><verb>
     INTEGER REAL CHARACTER DOUBLE PRECISION COMPLEX LOGICAL DO GOTO 
     IF THEN ELSE ELSEIF STOP END COMMON SUBROUTINE CALL RETURN FUNCTION 
     READ WRITE FORMAT OPEN CLOSE REWIND BACKSPACE DATA ...
</verb></tscreen>

<sect2>Noms symboliques<p>

<itemize>
<item> Les noms symboliques (identificateurs) sont des suites  d'au  plus 
30 caractères (lettres, chiffres ou _ ). Le premier caractère   doit  être 
une lettre. Majuscules et minuscules sont confondues.
<item>Servent à nommer les variables, les zones communes et les unités  de 
programme (programme principal, fonctions et sous-programmes) et les  zones 
communes.
<item> La longueur des noms symboliques est limitée à 6 dans le  cas  des 
unités de programmes et des zones communes.
</itemize>

<sect2>Opérateurs<p>

<itemize>
<item>signes mathématiques + - * / ** (Exponentiation)
<item>opérateurs de relation :  
<tscreen><verb>
          .LT. ( < )    .GT.  ( > )
          .LE. (  )     .GE.  (  )  
	  .EQ. ( = )    .NE.  ( # )
</verb></tscreen>

<item>opérateurs logiques :     
<tscreen><verb>
         .NOT. (non)   .AND. (et)    .OR.  (ou)    
         .EQV. (équivalence)  .NEQV. (ou exclusif)
</verb></tscreen>

<item>concaténation de chaînes de caractères :  
<tscreen><verb>
          //
</verb></tscreen>
</itemize>

<sect2>Expressions<p>
   
      Identificateurs et constantes reliés par des opérateurs.
      Exemples : 
<tscreen><verb>
         A + B * ( C ** D )
         (1.LE.K).AND.(K.LE.MAX)                 
         PATH // '/' // NOM // '.' // EXT
</verb></tscreen>

<sect1> Types de données, constantes <p>

<itemize>
<item> Type Entier                 :    123      -6123
<item>Type Réel                   :    1.414    65.4E-6      
<item>Type Logique (Booléens)     :    .TRUE.  .FALSE.
<item>Type chaîne                 :    'Hello' 'C''est l''heure'
</itemize>

Autres types de données : Réels  double-précision,  Complexes  (simple  et 
double précision), Fractionnels, Virgules fixes, etc ...


<sect1> Variables, scalaires, tableaux <p>

<sect2>Variables<p>

Une <em/variable/ est une grandeur dont la valeur peut changer au
cours de l'exécution d'un programme.  Une variable est désignée par un
<em/identificateur/.  Un <em/type/ est associé à chaque variable

<itemize>
<item> soit par déclaration explicite (exemple INTEGER A,B,C); 
<item> soit implicitement selon la règle dite « IJKLMN » :
</itemize>
      
Toute variable dont le nom commence par I, J, K, L, M ou N et qui n'a
pas été déclarée explicitement est par défaut de type INTEGER. Les
autres variables non déclarées sont de type REAL.

<sect2>Scalaires<p>

     Scalaire :     donnée unique désignée par un nom.

<sect2>Tableaux<p>

     Tableau :      collection d'objets du même type.
<p>
Une déclaration de tableau se fait en mentionnant - après  son  nom  -  la 
liste des intervalles de ses indices. 
<p>
      Exemple : 
<tscreen><verb>
        REAL TAB(5:12,3,0:20)  
</verb></tscreen>
déclare  un  tableau  à 
3 dimensions dont les éléments sont de type REAL.  Le premier  indice  peut 
varier entre 5 et 12, le second entre 1 et 3, et le troisième entre  0  et 
20. On peut utiliser jusqu'à  7  dimensions.
<p>
Elément  de  tableau  :  donnée 
élémentaire désignée par l'identificateur du tableau suivi par  une  liste 
d'indices placés entre parenthèses et séparés par des virgules.  Le nombre 
d'indices doit correspondre au nombre  de  dimensions  déclarées. Exemple :
<tt/TAB(6,2,0)/.
<p>
Pendant 
l'exécution, si un indice déborde  des  bornes  indiquées,  le  résultat  est 
indéfini.

<sect1> Unités de programme <p>

Un programme est composé d'une ou plusieurs unités de programme :

<itemize>      
<item> un programme principal (commençant par PROGRAM ...),
<item> éventuellement des sous-programmes  et  des  fonctions  (commençant 
respectivement par SUBROUTINE ... ou FUNCTION ...),
<item>  le  cas  échéant  un  « BLOCK  DATA »  (ou  plusieurs,   mais  c'est 
déconseillé).
</itemize>
     La fin de toute unité de programme est indiquée par la présence d'une 
instruction END  .
<p>
     La portée des identificateurs de  variables  et  des  étiquettes  est 
limitée à une unité de programme.
<p>      
     Les noms des sous-programmes, fonctions et  zones  communes  (COMMON) 
sont accessibles à partir de toute unité.

     
<sect> Présentation des programmes<p>
      
      
<itemize>
<item> Les  instructions  FORTRAN  sont  écrites  sur   des   lignes   de 
80caractères.
<item> Seules les 72 premières positions sont utilisées. Les colonnes 73 à 
80  sont ignorées. Attention à ne pas déborder.
<item>      
 Les lignes qui contiennent  un  C  en  première  colonne  sont  des 
commentaires ; le reste de la ligne  n'est  pas  pris  en  compte  par  le  
compilateur.
      <item>  Les  autres  lignes  sont  des  lignes  « instructions »;   qui   se 
décomposent en 3 zones :
<itemize>    
<item> la zone étiquette ( de 1 à 5 ),
<item> la zone suite (colonne 6),
<item> la zone instruction proprement dite (7 à 72).
</itemize>
</itemize>
      
     Une instruction particulièrement longue peut s'écrire  sur  plusieurs 
lignes consécutives; dans ce cas seule la première  ligne  peut  comporter 
une étiquette, et les « lignes-suite » sont  identifiées  par  un  caractère 
quelconque différent du blanc et du zéro (on met en général un  S,  ou  un 
chiffre).
<p>
 Un exemple de programme FORTRAN :
<tscreen><verb>
          1         2         3         4         5         
123456789012345678901234567890123456789012345678901234567890
-----S------------------------------------------------------
          PROGRAM DEGRAD
C
C Imprime une table de conversion degrés -> radians   
C
          INTEGER DEG
          REAL    RAD,COEFF
C
C En-tête
          WRITE (*,10)
10        FORMAT (' ',20('*') / 
     S              ' * Degres * Radians *' /
     S              ' ',20('*') )
C Corps
          COEFF = (2.0 * 3.1416) / 360.0         
          DO 100 DEG = 0,90
               RAD = DEG * COEFF
               WRITE (*,20) DEG,RAD
20             FORMATF (' *  ',F4.1,'  * ',F7.5,' *')
100       CONTINUE
C
C Fin du tableau
C         WRITE(*,30)
30        FORMAT (' ',20('*') )
C
          STOP
          END
</verb></tscreen>

<sect> Instructions<p>

<sect1> Les déclarations de variables<p>

Une variable est déclarée en citant : son type,  son  nom  et,  (pour  les 
tableaux) les bornes des indices.
<p>      
Principaux types :

<itemize>  
<item><tt/INTEGER        INTEGER*2      INTEGER*4/
<item><tt/REAL           COMPLEX        DOUBLE PRECISION/
<item><tt/LOGICAL/
<item><tt/CHARACTER*1    ....           CHARACTER*256/
</itemize>

Exemple :     
<tscreen><verb>
               INTEGER*4      A(20,3),B
               CHARACTER*1O   C(0..9)
               LOGICAL        D(3,4,8:12)
</verb></tscreen>

      Ces instructions déclarent :

<itemize>
<item> Un tableau A de 20 x 3 entiers,
<item> Une variable scalaire entière nommée B,
<item> Un tableau C de 10 chaînes de 15 caractères,
<item> Un tableau D de 3 x 4 x 5 scalaires booléens.
</itemize>

<sect1> Initialisation statique des variables<p>

Il est possible de donner une valeur initiale aux variables d'une
unité de programme pendant le chargement du programme.  C'est ce qu'on
appelle l'<em/initialisation statique/ d'une variable, par opposition
à l'<em/initialisation dynamique/ qui se fait à l'exécution au moyen
d'une instruction d'affectation.
<p>
Exemples :
<tscreen><verb>
          REAL           PI,E
          DATA           PI,E / 3.14159 , 2.718 /

          CHARACTER*1    SPACE,BELL,ESCAPE
          DATA           SPACE,BELL,ESCAPE / ' ',Z'07',Z'1B' /

          CHARACTER*10   NAMES(10)
          DATA           NAMES / 3*'AAAAAAAAAA',7*'XXXXXXXXXX' /
</verb></tscreen>

Le dernier exemple utilise des facteurs de répétition  :  les  3  premiers 
élements de NAMES contiendront 'AAAAAAAAAA', les 8 autres 'XXXXXXXXXX'.


<sect> Les déclarations d'unités de programmes<p>

Rappelons que les noms d'unités de programmes sont limités à 6 caractères, 
et que le texte d'une unité de programme  se  termine sur  une  instruction 
END.

<sect1>Programme principal.<p>

      Cette unité de programme commence par la ligne :

<tscreen><verb>
               PROGRAM nom 
</verb></tscreen>
 Exemple 1 :
<tscreen><verb>
               PROGRAM ESSAI
               INTEGER  I
          C
               DO  1000 I=1,10
                    WRITE  (*,*) ' Bonjour !'
          1000 CONTINUE
          C
               STOP
               END
</verb></tscreen>

<sect1>Sous-programmes et fonctions<p>

<sect2> Exemple 2 : définition d'un sous-programme <p>

<tscreen><verb>
               SUBROUTINE  ECHANG ( X,Y )
               INTEGER X,Y,INTER
          C
               INTER = X
               X = Y
               Y = INTER
          C
               RETURN
               END
</verb></tscreen>

     Les sous-programmes sont appelés par l'ordre CALL. Exemple :

<tscreen><verb>
                CALL ECHANG( T(I) , T(I+1) )
</verb></tscreen>

<sect2> Exemple 3 : Définition de fonction <p>

<tscreen><verb>
               INTEGER FUNCTION  MAX (N1,N2)
               INTEGER  N1, N2
          C
               IF (N1 .GE. N2) THEN
                    MAX = N1
               ELSE
                    MAX = N2
               ENDIF
          C
               RETURN
               END
</verb></tscreen>

     Les  fonctions  sont  appelées  à  partir  des   expressions.   Elles 
retournent toujours une valeur.
<p>
Exemple d'appel de fonction :
<tscreen><verb>
          I12 = 2 * MAX(A+1,B+2) - MAX (C,10)
</verb      ></tscreen>

<itemize>
<item> Les sous-programmes et fonctions doivent toujours contenir au moins 
une instruction RETURN ; l'exécution  de cette  instruction   provoque le 
retour à l'unité de programme appelante. Il est possible d'avoir plusieurs 
instructions RETURN dans une même unité de programme (voir exemple 4).
<item> Les instructions de déclaration SUBROUTINE et  FUNCTION  servent  à 
indiquer :
<itemize>
<item> le nom de l'unité de programme,
<item> le  nombre de  paramètres formels   (Dans l'exemple 2, X et Y sont 
les paramètres formels de ECHANG),
<item> pour les fonctions le  type du résultat.
  </itemize>
</itemize>

<sect2> Exemple 4 : passage d'un tableau formel<p>
<tscreen><verb>
          INTEGER FUNCTION INDEX (T,N,V)
          INTEGER  N, T(N), V, K
 C
 C Cette fonction calcule l'index de la première occurence de V
 C dans le tableau T. (Retourne 0 si cette valeur est absente)
 C
          DO  100 K = 1,N
               IF ( T(K) E.EQ. FV ) THEN
                    INDEX = K
                    RETURN
               ENDIF F
 100      CONTINUE
 C
          INDEX = 0
          RETURN
          END
</verb></tscreen>

IMPORTANT : lors de l'appel d'une unité de programme, les paramètres
effectifs doivent être conformes - en nombre et en type - aux
paramètres formels.  (Chose que les compilateurs FORTRAN ne vérifient
en général pas, et qui provoque des <em/gags/ plutôt 
difficiles à déceler).
<p>
Exemple typique d'erreur :

<tscreen><verb>
          REAL FUNCTION F (X)
          REAL F, X
               F = X + 1.0
          RETURN
          END
</verb></tscreen>

     Si l'on exécute alors l'instruction Y=F(0)  (au  lieu  de F(0.0)),  on 
récupère dans Y quelque chose qui est tout-à-fait différent de  la  valeur 
attendue 1.0. Essayez !
<p>      
 Autre source d'erreurs : ne pas oublier de déclarer le type d'une 
fonction appelée dans l'unité appelante. Exemple d'erreur :

<tscreen><verb>
          INTEGER FUNCTION CARRE (N)
          INTEGER N
               CARRE = N * N
          RETURN
          END

          INTEGER FUNCTION P4 (N)
          INTEGER  N
               P4 = CARRE ( CARRE ( N ) )
          RETURN
          END
</verb></tscreen>

     Dans P4 la fonction CARRE est considérée comme rendant un résultat de 
type REAL (d'après la règle IJKLMN), ce  qui n'est  pas  cohérent  avec  la 
définition de la fonction CARRE. Il faut donc  ajouter  dans  P4  (et  dans 
toute unité de programme qui appelle CARRE) la déclaration « INTEGER CARRE ».


<sect1>Block Data<p>

     Cette  unité  de  programme  un  peu  spéciale  sert   uniquement   à 
l'initialisation statique (par DATA) des zones communes.
     Elle commence par la ligne :
<tscreen><verb>
               BLOCKDATA nom
</verb></tscreen>
 et ne peut contenir que :
<itemize>
<item> des déclarations de type ( INTEGER, REAL ...)
<item> des déclaration de zones communes (COMMON),
<item> des initialisations statiques (DATA). 
</itemize>
     Une zone commune ne peut être citée que dans un  seul  BLOCKDATA.  Il 
est d'ailleurs conseillé de n'avoir qu'un seul BLOCKDATA par programme.
      <p>
     (Pour plus d'informations se reporter à l'annexe sur l'utilisation des 
zones communes).


<sect1> Instructions de contrôle<p>

<sect2>Affectation<p>

     Exemple : PAS ( N , P ) = PAS ( N-1 , P-1 ) + PAS ( N , P )
<p>      
     Le déroulement  d'une affectation  « var = expression »  est le suivant :
<itemize>
<item> l'expression à la droite du signe '='  est  évaluée  selon son  type 
propre,
<item> le résultat est au besoin converti dans le type de la  variable  de 
gauche,
<item> la valeur obtenue est rangée dans la variable.
 </itemize>
    
     Ainsi, si les variables I et R sont respectivement de type
INTEGER et REAL, les instructions : 
<tscreen><verb> 
          I = 1 
          R = I / 2.0
</verb></tscreen>
provoquent l'affectation de la valeur 0.5 à R, tandis que :
<tscreen><verb>
          I = 1
          R = I / 2
</verb></tscreen>
met 0.0 dans R (l'expression I/2 étant de type entier, la division est une 
division entière de résultat nul, converti ensuite en valeur réelle).

<sect2>CONTINUE<p>
      
C'est une «non-opération», qui sert uniquement à <em/poser une étiquette/ (en 
particulier dans les boucles DO).
<p>
     Exemple :
<tscreen><verb>
          DO 1000 K=1,N
               A(K) = B(K) + 1
     1000 CONTINUE
</verb></tscreen>

<sect2>STOP<p>

     Provoque l'arrêt complet du programme en cours.


<sect2>GOTO<p>

     Exemple :  GOTO 1234
<p>
    Provoque un saut (branchement) à l'instruction (de la  même  unité  de 
programme) qui porte l'étiquette 1234.


<sect2>GOTO  calculé<p>

     Exemple :  GOTO (1010,2000,3000,1515),I+1
<p>
     Si l'expression I+1 a pour valeur 1, alors saut  à l'étiquette   1010. 
Si la valeur est 2, saut à 2000; etc. 
<p>
Si la valeur calculée estt inférieure à 1 ou 
supérieure  au  nombre  d'étiquettes  citées,  on   passe   simplement   à 
l'instruction suivante. 

<sect2>IF logique <p>

     Instruction de la forme :  IF ( condition ) instruction
<p>
     Exemple :
<tscreen><verb>
               IF  ( M .LT. FT(K) ) M = T(K)
               K = K + 1
</verb></tscreen>

     Si  la  condition  citée  (M  plus  petit  que   T(K))   est   vraie, 
l'instruction située sur la même ligne est exécutée, puis on  passe  à  la 
suivante (K = K + 1). Dans le cas contraire,  l'instruction  suivante  est 
exécutée directement (on ne fait pas l'affectation M = T(K) ).
<p>      
     Le « IFlogique » est très souvent employé en compagnie de l'instruction 
GOTO, c'est-à-dire sous la forme :

<tscreen><verb>
          IF( condition ) GOTO etiquette
</verb></tscreen>
      C'est le « GOTO conditionnel ».


<sect2>Bloc  IF<p>

      Forme générale :
<tscreen><verb>
          IF ( condition1 ) THEN
               bloc 1
          ELSE IF ( condition2 )  THEN
               bloc 2
          ELSE IF ( condition3 )  THEN
               bloc 3
          ....
          ELSE
               bloc-else
          ENDIF
</verb></tscreen>
      
     Si la condition 1 est vraie, le bloc  1  (suite  d'instructions)  est 
exécuté et on passe à l'instruction  qui  suit  le  ENDIF.  Sinon,  si  la 
condition 2 est vraie on exécute le bloc 2, etc ...
<p>
     Si les conditions sont toutes fausses, c'est  le  bloc-else  qui  est 
exécuté.
<p>
     Le nombre de parties ELSE IF n'est pas limité  (on  peut  ne  pas  en 
mettre). La partie ELSE est également facultative.
<p>      
     Exemples :
<tscreen><verb>

          PROGRAM CHOIX      
          CHARACTER*1 CODE
C
C on demande le caractere CODE
C
1         WRITE (*,*) ' Tapez A,B,C,? ou X'            
          READ (*,100) CODE
100       FORMAT F (A1)
C
C au besoin, on transforme les minuscules en majuscules.
C
          IF(  ('a'.LE.CODE).AND.(CODE.LE.'z')  THEN 
               CODE  = CHAR ( ICHAR ( CODE ) - 32 )
          ENDIF
C
C selon CODE, on appelle FA,FC,FC,MENU et on recommence.
C si CODE=X on arrête tout.
C
          IF (CODE.EQ.'?') THEN
              CALL MENU
          ELSE IF ( CODE.EQ.'A' ) THEN
              CALL FA
          ELSE IF ( CODE.EQ.'B' ) THEN
              CALL FB
          ELSE IF ( CODE.EQ.'C' ) THEN
              CALL FC
          ELSE IF ( CODE.EQ.'X' ) THEN
               WRITE  (*,*) ' C''est tout !'
               STOP
          ELSE
               WRITE (*,*) ' Quoi ?'
          END IF
C
          GOTO 1
          END
</verb></tscreen>

<sect2>« IF arithmétique »<p>

     Tout manuel FORTRAN qui se respecte se doit  de  citer  ce  vénérable 
vestige de la préhistoire informatique, période FORTRAN I  !  Cette  chose 
est appelée vulgairement « IF à trois pattes », d'après sa forme générale qui 
est :
<tscreen><verb>
          IF ( Expression ) Etiquette1,Etiquette2,Etiquette3
</verb></tscreen>
<p>      
<itemize>
<item>     Si  l'expression  arithmétique   entre   parenthèses   est   négative 
(strictement), on saute à l'étiquette 1. 
<item>Si elle est  nulle
 on  passe  à 
l'étiquette 2.  
<item>Enfin,  si  elle  est  strictement  positive  on  saute  à 
l'étiquette 3.
</itemize>

     Cette forme est utile (et encore ...)  uniquement si on a
vraiment trois traitements distincts à effectuer dans chaque cas. 
L'exemple classique est la recherche des solutions d'une équation du
second degré ... qui ne marche pas puisque les opérations
réelles fournissent rarement un résultat exactement nul, à cause de la
précision limitée. En réalité il faut faire une comparaison «à epsilon près».  

Quoi s'il en soit, on fait exactement la même chose avec un 
GOTO conditionnel mille fois plus clair. 

<p>      
     Cette chose a malheureusement survécu à  toutes  les  révisions  du 
langage  FORTRAN,  parce  que  beaucoup  de  programmes FORTRAN  
l'utilisaient, et que personne n'a  le  courage 
de les refaire.     
     Notamment on rencontre des choses du genre : 
<tscreen><verb>
     IF (M-T(K)) 100,200,200
     100   M = T(K)
     200   K = K + 1
</verb></tscreen>
     Le devoir sacré de tout programmeur FORTRAN est de  remplacer  illico 
tous les « IF arithmétiques » qu'il rencontre par des  « IF  logiques ».  
Ne pas corriger une faute, c'est là la véritable faute (Confucius).

<sect2>DO<p>

     Exemple : DO 100 K=1,N
<p>      
     L'instruction DO sert à indiquer qu'un certain « bloc »  d'instructions 
(le corps de la boucle) est à répéter pour plusieurs valeurs  de  l'indice 
de boucle (ici K), cet indice variant entre une borne inférieure  (ici  1) 
et une borne supérieure (ici N).
<p>      
     Le corps  de  la  boucle  est  composé  des  instructions  quisuivent 
l'instruction DO jusqu'à (et y compris) l'instruction dont l'étiquette est 
indiquée (ici 100). Une bonne habitude consiste à utiliser une instruction 
CONTINUE pour poser cette étiquette, et à indenter (décaler) le  corps  de 
boucle.     
<p>
          Exemple      
<tscreen><verb>
          SUBROUTINE  PROMAT (A,B,C,N,M,P)
C
          INTEGER   N,M,P
          REAL      A(N,M),B(M,P),C(N,P)
C
          INTEGER   I,J,K           
          REAL S
C
          DO 300  I=1,N
               DO 200 J=1,P
                    S = 0.0
                    DO 300 K=1,M
                         S = S + A(I,K)*B(K,J)
100                 CONTINUE
                    C(I,J)=S
200            CONTINUE
300       CONTINUE
C
          RETURN
          END
</verb></tscreen>

     Quelques remarques :
      
<itemize>
<item> A  l'intérieur  d'une  boucle,  il  est  fortement  déconseillé  de 
chercher à modifier la valeur de l'indice de boucle.
<item> Il est interdit  de se  brancher  (par  GOTO)  de l'extérieur  d'une 
boucle DO vers l'intérieur. Par contre, on peut très bien utiliser un GOTO 
pour s'échapper d'une boucle. 
     <item>
 Deux boucles DO sont soit emboitées, soit disjointes. En aucun  cas 
elles ne peuvent se chevaucher.
      <item> On peut préciser le pas, en utilisant la forme :
<tscreen><verb>
          DO étiquette  indice = début , fin , pas
</verb></tscreen>
     et aussi utiliser des boucles à indice de type  réel  (attention  aux 
erreurs d'arrondis).
</itemize>


<sect1> Entrées-Sorties séquentielles<p>

      
     Le point important est qu'un ordre d'entrée-sortie FORTRAN (lecture ou 
écriture) mentionne (au moins) trois choses :      
<itemize>
<item> Le « numéro d'unité logique » du fichier sur  lequel 
l'opération  doit 
être effectuée;
<item> Le « format » décrivant la structure  de  l'enregistrementà  lire  ou 
écrire;
<item> La liste des variables concernées.
</itemize>

    Il est également possible de préciser ce qu'il faut faire  si  l'ordre 
d'entrée-sortie se déroule mal, ou si on détecte une fin de fichier 
      
<sect2>WRITE<p>

     Exemples :
<tscreen><verb>
          WRITE  ( 6,100 ) A,B,C
          WRITE  ( 6,123 ) A, B+1 , ( T(K), K=1,N ) 
</verb></tscreen>

Le premier exemple signifie « Ecrire sur l'unité logique numéro 6  
les  contenus des variables A,B et C en utilisant la description d'enregistrement  donnée 
par l'instruction FORMAT d'étiquette100 (située  dans  la  même  unité  de 
programme) »  
<p>
Le second exemple montre une « boucle DO implicite »,  qui  parcourt  les  N 
premiers élements du tableau T.
      <p>
     Autre exemple de boucle  DO implicite :
<tscreen><verb>
          WRITE (6,421) (  ((10*I+J), J=1,I) , I=1,9 )
</verb      ></tscreen>
     qui imprime la suite de nombre  11,21,22,31,32,33,41...99  sur l'unité 
logique et dans le format que vous devinez.
      <p>
Le numéro d'unité logique 6 désigne  -en  général-  la  « sortie  standard » 
(votre écran), on peut mettre une étoile * si on ne s'en  souvient pas. 
<p>
Si on ne désire pas spécifier de manière précise le format d'écriture, on 
met aussi une étoile à la place de l'étiquette de format.
<p>
Dans ce  cas  le  compilateur  se  débrouille  pour  fabriquer  un  format 
convenable (de son point de vue !). C'est bien pratique lorsqu'on fait  de 
la mise au point par « espionnage », du style :
      <tscreen><verb>
          SUBROUTINE XYZ (A,B)
          WRITE (*,*) ' Je rentre dans XYZ avec A=',A,'et B=',B
               ...
          WRITE (*,*) ' Je sors de XYZ avec A=',A,' et B=',B
          RETURN
          END
</verb></tscreen>
et aussi pour les programmes « quick'n dirty ».


<sect2>READ<p>
      
Exemples :
<tscreen><verb>
          READ (5,100) X,Y,Z
          READ (5,100,END=123) A,B,C
          READ (5,100,END=123,ERR=987) U,V,W
</verb      ></tscreen>

     Il n'est guère difficile de deviner la signification du premier
exemple : « lire sur l'unité logique numéro 5 les nouvelles valeurs
des variables X,Y et Z, selon le format 100 ».
<p>
     Dans le second exemple l'option « END=123 » signifie qu'en cas de
fin de fichier il faut se dérouter à l'instruction portant l'étiquette
123.
<p>
     Le troisième exemple montre l'option « ERR=987 » qui indique :«
si une erreur se produit pendant la lecture (par exemple une lettre
dans une zone censément numérique) alors aller en 987 ».
<p>
     Le numéro 5 est affecté à l'entrée standard (votre clavier) ; on peut 
mettre une étoile à la place. On peut aussi mettre une étoile au  lieu  du 
numéro de  format,  la  lecture  s'effectue  alors  en  « format  libre »  ; 
c'est-à-dire que l'utilisateur tapera ses données séparées par des  blancs 
ou des virgules, les chaines de caractères étant entourées par des  quotes 
«  '  ».
<p>
     L'usage des formats libres est :
<itemize>
<item>  une  très  bonne  chose  pour  l'entrée  des   données   en   mode 
conversationnel;
<item> un gadget tout-à-fait douteux (voire nuisible)  pour  les  lectures 
sur fichiers.
</itemize>

<sect2>  FORMAT<p>

 Exemple :
<tscreen><verb>
          WRITE (*,100) I,J,K         
          ...
100       FORMAT ( 5X ,'Le ppcm de ',I2,' et ',I2,' vaut ',I4)
</verb></tscreen>

     Dans  cet  exemple  l'ordre  WRITE  provoque  l'écriture (sur la 
sortie standard) d'une ligne composée de :

<itemize>
<item> 5 blancs (format 5X)
<item> la chaine 'Le ppcm de '
<item> la valeur de l'entier I, sur deux caractères (format I2)
<item> la chaine ' et '
<item> la valeur de l'entier J, sur deux positions (format I2)
<item> la chaine ' vaut '
<item> la valeur de l'entier K, sur 4 caractères (format I4).
</itemize>
      
     L'instruction FORMAT (en fait c'est  une  déclaration)  n'a  de  sens 
qu'utilisée par un ordre READ ou  WRITE.  Il  y  a donc  nécessairement  un 
numéro d'étiquette devant.

<sect2> Quelques spécifications de format <p>
      
<itemize>
<item>    I : pour les entiers. Exemples I2 , I1 , I12 , etc..
<item>    A : pour les chaines de caractères :  la  chaine  'ABCDEF'écrite 
avec le format A3 donne ABC (troncation à 3 caractères),  avec  le  format 
A10 on obtient ABCDEF (cadrage à gauche sur 10positions).
<item>    F : pour les réels en « virgule fixe ». Par exemple  3.1416  écrit 
avec le format F6.2 donne  3.14  (6  positions,  dont  2  après  le  point 
décimal).
<item>    E : pour les réels « avec exposant » : Par exemple 3.1416 en format 
E11.5 s'écrit .31416E-01 (En tout 11 positions,  dont  5  pour  la  partie 
décimale, l'exposant Enn étant toujours sur les 4 caractères  les  plus  à 
droite).
<item>    X : pour laisser un blanc (ou ignorer un caractère en lecture).
<item>   /  :  pour  abandonner  la   ligne   en   cours   et   passer   à 
l'enregistrement suivant.
</itemize>

<sect2> Répétition de  FORMAT <p>

<itemize>
<item> La spécification « 5I4 » équivaut  à  « I4,I4,I4,I4,I4 »  .  (La  même
chose 
s'applique aux spécifications E,F,A,X ...).
<item> On peut faire répéter un groupe de  spécifications  en  plaçant   ce 
groupe entre parenthèses et en le  faisant  précéder  par  le  facteur  de 
répétition.
</itemize>

     Exemple : « 5(I3,X) »  équivaut à « I3,X,I3,X,I3,X,I3,X,I3,X ».
      
Il y a une règle très amusante qui s'applique au cas où  l'on  veut 
faire écrire plus de choses que le format n'en spécifie. Exemple :  
<tscreen><verb>
          WRITE  (*,100) A,B,C
100       FORMAT  (2I4)
</verb></tscreen>

     Cette règle dit :
<quote>
Si la parenthèse finale est rencontrée alors qu'il reste des données 
à traiter :
<itemize>
<item> s'il n'y a pas de groupes de spécifications entre  parenthèses,  le 
format est repris au début;
<item> s'il y a des groupes entre parenthèses,  l'exploration  reprend  au  
début du groupe dont la parenthèse de droite a été rencontrée la  dernière 
avant la parenthèse finale.
</itemize>
</quote>
     En réfléchissant un peu, c'est finalement très simple.


<sect2>  OPEN <p>

<tscreen><verb>
       OPEN  (1)
       OPEN  (1,FILE='FICH.ABC')
       OPEN  (1,FILE='TOTO.X',STATUS='OLD',ERR=123)
</verb      ></tscreen>

     Le premier exemple est une ouverture simple du fichier numéro 1.
Dans le second, on précise le nom du fichier que l'on veut associer au
numéro d'unité logique 1 (ici FICH.ABC). Dans le troisième, on précise
que le fichier que l'on veut ouvrir (TOTO.X) est censé exister déjà
(OLD), et qu'en cas d'erreur (si fichier absent, donc) il faut aller à
l'étiquette 123.  
<p> 
On peut donner comme STATUS la chaîne 'NEW', qui
signifie que le fichier n'existait pas préalablement, ou 'UNKNOWN' ...
<p> Il existe des quantités d'autres clauses, voir en particulier
l'annexe relative à l'utilisation des fichiers en accès direct.
<p>
     Il n'est pas nécessaire d'ouvrir les fichiers 5 et 6.

      
 <sect2>  CLOSE<p>

<tscreen><verb>
     CLOSE (1)
</verb></tscreen>
          ferme le fichier - préalablement ouvert - indiqué.
<p>
          Il est inutile de fermer les fichiers standards 5 et 6.


<chapt>Annexe : les nombres <p>

<sect>  Les entiers<p>

<sect1> Les types<p>

<tabular ca=table>
      type        <colsep>  occupation mémoire <colsep>     intervalle    
<rowsep><hline>
       INTEGER   <colsep>     32 bits (16 utiles)  <colsep>  -32768..+32767
<rowsep>
       INTEGER*2 <colsep>      16 bits  <colsep>              -32768..+32767
<rowsep>
       INTEGER*4 <colsep>     32 bits    <colsep>            -2**31..+2**31
</tabular>

      Les constantes entières ont le type INTEGER si elles sont  dans 
l'intervalle comprises entre -32768 et +32767, sinon  INTEGER*4. 

<sect1>Fonctions courantes<p>

      Les fonctions arithmétiques les plus courantes :

<itemize>
<item>      MIN0 ( ..... ) :   minimum de plusieurs expressions
<item>      MAX0 ( ..... ) :   maximum 
<item>      IABS ( expr  ) :   valeur absolue
<item>      MOD  ( e1,e2 ) :   reste de la division entière de e1 par e2.
</itemize>
      Dans certains cas  -assez particuliers, il est  vrai- on peut avoir  
besoin de  considérer  les entiers  comme  des «chaînes  de bits»,   et   de  
faire   des   masquages,   des  décalages,   des complémentations, etc ... 

<itemize>
<item>      NOT  ( expr  ) :   Complémentation.
<item>      IAND ( e1,e2 ) :   Produit (ET).
<item>      IOR  ( e1,e2 )  :  OU inclusif.
<item>      IEOR ( e1,e2 )  :  OU exclusif.

<item>      ISHFT( e1,e2 )  :  Les bits de e1 sont décalés de e2 positions
                        vers la gauche. Les positions vacantes sont
                        comblées par des 0. Décalage à droite si e2
                        est négatif.
<item>      IROT ( e1,e2 )   : Rotation  des  bits  de  e1, de e2 positions 
                        vers la gauche.     
</itemize>


      Il peut être commode d'utiliser à cette occasion les constantes
 hexadécimales, qui sont de la forme Z'012345FEDC'. Exemple :
 IAND(I,Z'000F'), qui permet de récupérer (par masquage) les 4 bits de poids 
faible de la variable I. 



<sect> Les réels<p>

<sect>Types<p>

<tabular ca=table>
type <colsep> occupation mémoire <colsep> mantisse <rowsep><hline>
     REAL <colsep>              32 bits <colsep>          24 bits <rowsep>
     DOUBLEPRECISION <colsep>   64 bits <colsep>          56 bits <rowsep>
</tabular>

      Ces deux types permettent de représenter des nombres compris
 (approximativement) entre  5.4*10**(-79) et  7.2*10**75 .

      Exemple de constantes :
<itemize>
<item>
       REAL             :   1.   -3.14   6.28E28   5.4E-79
<item>
       DOUBLEPRECISION  :   1.D12 6.281234567D-1 -3.D-27
</itemize>

<sect>Fonctions<p>

      Fonctions couramment utilisées, en version  REAL :
<itemize>
<item>      AINT  ( expr  )    troncation.
<item>      ANINT ( expr  )    arrondi.
<item>      ABS   ( expr  )    valeur absolue.
<item>      AMIN1 ( ..... )    minimum de plusieurs expressions.
<item>      AMAX1 ( ..... )    maximum         ..
</itemize>      
      En  DOUBLE PRECISION  ces fonctions s'appellent : DINT, DNINT, DABS, 
DMIN1 et DMAX1.


<sect>      La trigonométrie, et cie.<p>

<itemize>    
<item>      SQRT  ( expr  ) :    racine carrée.
<item>      EXP   ( e1,e2 ) :    e1 à la puissance e2.
<item>      ALOG  ( expr  ) :    log. népérien
<item>      ALOG10( expr  ) :    log. base 10
<item>      SIN   ( expr  ) :    sinus
<item>      COS   ( expr  ) :    cosinus
<item>      TAN   ( expr  ) :    tangente
<item>      ASIN  ( expr  ) :    arcsinus
<item>      ACOS  ( expr  ) :    arccosinus
<item>      ATAN  ( expr  ) :    arctangente
</itemize>
      Il  y  en  a  d'autres  ...  Les  équivalents   en   DOUBLEPRECISION 
s'appellent respectivement : DSQRT, DEXP, DLOG, DLOG10,  DSIN,  DCOS,DTAN, 
DASIN, DACOS, et DATAN.
 
<sect> Conversions explicites de type<p>

      Le  tableau  suivant  montre  l'ensemble  des  fonctions  de conversion 
de type.


<verb>
                            type du résultat
                  -------------------------------------+
                  !   int    int*4    real    dble     !
        +---------+------------------------------------+
        !  int    !          IDBL     FLOAT   DFLOAT   !
 type   !  int*4  !   ISINGL          FLOAT4  DFLT4    !
 arg.   !  real   !   IFIX   IFIX4            DBLE     !
        !  dble   !   IDINT  IFIXD4   SNGL             !
        !----------------------------------------------+
</verb>

<chapt>Annexe :  utilisation des chaînes de caractères <p>

Contrairement à son ancêtre FORTRAN IV, le langage  FORTRAN  77  reconnait 
l'existence du type prédéfini «chaîne de caractères». Ne  nous  en  privons 
donc pas. 

<sect>Déclaration<p>

La taille des chaînes de caractères est fixée lors  de  la
déclaration  des 
objets de type CHARACTER. Par exemple les déclarations :

<tscreen><verb>
                    CHARACTER*10 TRUC
                    CHARACTER*50  MACHIN
</verb></tscreen>
 fixent la taille des chaines TRUC et MACHIN à 10 et 50 caractères. 
La taille maximum est 255.

<sect>Constantes<p>

 Les constantes peuvent s'écrire sous trois formes :

<itemize>      
<item> Entre quotes : 'Hello ! 'C''est l''heure' . Il faut doubler les quotes 
internes.
<item> En  notation hexadécimale  : Z'1BFF000A' (pratique  pour 
la manipulation  des  caractères non  imprimables  ESC,LF,BELL,CR,BS, etc...)
<item> En  notation Hollerith :   7Hl'heure . Dans  cette notation, on  
représente  une  chaine  par  un entier  (la  longueur  de  la chaine, ici 7)
suivi par la lettre H, puis  le contenu. Cette notation antique et désuète   
oblige  le   
malheureux  programmeur   à  compter   les caractères, ce qui est 
particulièrement désagréable. 
</itemize>

<sect>Opérations sur les chaines de caractères<p>

<sect1>Concaténation, affectation, sélection<p>

 Exemple :

<tscreen><verb>
           CHARACTER*10 A,B
           CHARACTER*20 C,D
          ...
          C = A
          B = D
          C = A // B
          D(2:11) = C(1:5) // A(3:7)
</verb></tscreen>

     La première instruction copie le contenu de A dans  C.  Cétant   plus 
longue, les caractères de  droite  de  C  sont  remplis  avec  des  blancs 
(cadrage à gauche). <p>
      La  seconde instruction  copie les  premiers caractères  de D dans B 
(troncation). <p>
     La troisième instruction met bout-à-bout (concatène) les chaînes A  et 
B, le résultat étant transféré ensuite dans C.<p>
      La quatrième instruction concatène les 5 premiers  caractères  de  C 
avec les caractères 3  à  7  de  A,  le  résultat  étant  placé  dans  les 
caractères 2 à 11 de D (les autres caractères de D ne sont pas touchés par 
l'opération).
<p>

      On peut comparer  des  chaines  grâce  aux  opérateurs  habituels  :     
.LT. .LE. .EQ. .NE. .GE. .GT. . Pour faire la comparaison la  plus  courte 
des chaines est allongée (virtuellement) par des blancs à droite. 


<sect1>      Quelques fonctions<p>
      
<itemize>          
<item>     LEN retourne la longueur d'une chaine.
<item>     CHAR convertit un CHARACTER*1 en INTEGER,
<item>     ICHAR fait l'inverse.
<item>     INDEX (ch1,ch2) retourne un entier qui est la position de  départ  (à 
l'intérieur de ch1) d'une chaîne identique à ch2. (0 si ch2 n'apparait pas 
dans ch1).
</itemize>

<sect>Entrées-sorties<p>

     Enfin, rappelons que les lectures-écritures de chaînes se font  selon 
la spécification de format A.

     Exemple :
<tscreen><verb>
     WRITE (*,100) 'LITTLE','VERY_BIG_STRING'
100  FORMAT (2A8)
</verb></tscreen>
     provoque l'écriture de : LITTLE__VERY_BIG

<chapt>Annexe : passage de Paramètres <p>

La    communication    entre    unités    de     programmes     (programme 
principal,sous-programmes, fonctions) peut se faire de deux manières  très 
différentes : par passage de paramètres ou par partage d'une zone commune.

<sect>Passage de paramètres<p>

      Exemple (trivial) :

<tscreen><verb>
           PROGRAM  PP           
            INTEGER  A,B,C,D      
            READ  (*,*) A,B       
            CALL  SP(A,B,C)       
            CALL  SP(1,2,D)       
            WRITE (*,*) A,B,C,D
            STOP
           END

           SUBROUTINE   SP(X,Y,Z)
            INTEGER  X,Y,Z 
            Z = X + Y 
            RETURN  
           END  
</verb></tscreen>
      
On parle de <em/paramètres formels/
 quand on se place du  coté  de  l'unité  de 
programme appellée (X,Y et Z sont les paramètres formels  de  SP),  et  de 
<em/paramètres effectifs/ d'un appel (A,B,C paramètres effectifs du  premier  
appel  à  SP  dans  PP,  1,2,D  paramètres effectifs du second).
      <p>
La première chose à savoir est que les paramètres sont toujours passés 
<em/par 
adresse/. Ainsi, il est possible de  modifier  -  depuis  l'intérieur  d'un 
sous-programme - le contenu d'une variable  reçue  comme  paramètre  (dans 
notre exemple, il est clair que le sous-programme SP modifie son troisième 
argument). Les résultats d'expressions arithmétiques (et  les  constantes) 
utilisés comme paramètres effectifs sont traités de la même manière : dans 
l'appel CALL SP(A+B,0,C) le premier paramètre effectif 
sera en  fait  une  variable 
intermédiaire contenant le résultat de l'addition de A  et  B,  le  second 
paramètre une zone mémoire contenant la valeur 0.
<p>
La seconde chose -très importante- à savoir est que la  correspondance  de 
types entre arguments effectifs et arguments formels n'est  pas   vérifiée 
par  le  compilateur  FORTRAN.   Ainsi   l'appel   CALL   SP   (1.0,1.0,C) 
conduira-t-il à un résultat douteux. Il n'y a pas non plus de contrôle  du 
nombre de paramètres. Ces vérifications  sont  laissées  à  la  charge  du 
programmeur. Rappelons en particulier que les  constantes  entières  entre 
-32768 et 32767 sont de type INTEGER, et que les  constantes  plus  grandes 
sont en INTEGER*4.
      

<sect>Passage de fonctions ou sous-programmes en paramètres<p>

 Exemple :

<tscreen><verb>
            REAL FUNCTION  DERIV(F,X)
 C
 C Calcule la valeur de la dérivée de la fonction F en X
 C
            REAL F,X           
              DERIV =  ( F(X+0.01) - F(X-0.01) ) / 0.02
            RETURN
            END

            REAL FUNCTION  TEST (X)
 C
 C Un exemple de fonction à une variable réelle
 C
             TEST = X**2 + SIN(X)
            RETURN
            END

            PROGRAM  ESSAI
            EXTERNAL TEST
            REAL  TEST,POINT
              READ  (*,*) POINT
              WRITE  (*,*) 'Au point ',POINT,
      S                    'la derivee vaut',DERIV(TEST,POINT)
            STOP
            END
</verb></tscreen>

     La déclaration EXTERNAL TEST  (du  programme  principal)  signale  au 
compilateur FORTRAN que le nom TEST désigne une unité de programme (et non 
pas une variable).
<p>      
     Dans DERIV, il est «conseillé»  de  déclarer  le  type  du  paramètre 
formel F. Le compilateur arrive à déterminer que F est une  FUNCTION,  car 
le nom F est suivi de parenthèses, et aucun tableau F n'est déclaré.
<p>   
Si, dans le programme principal, on avait voulu passer  en  paramètre  une 
fonction  prédéfinie  (par  exemple   SIN),   alors   on   doit   utiliser 
l'instruction INTRINSIC SIN (au lieu d'EXTERNAL).
      
      
<sect>Tableaux Formels<p>

 Exemple :                  
<tscreen><verb>
       REAL FUNCTION SOMME(T,N)
       INTEGER N
       REAL T(N)
 C
 C Calcul de la somme des N elements du tableau T
 C
         INTEGER  I
         REAL  S
 C
         S = 0.0
         DO  100,I=1,N
             S = S + T(I)
 100     CONTINUE
         SOMME = S
         RETURN
       END   
</verb></tscreen>

Dans cet exemple le tableau (formel) T possède  une  dimension  (formelle) 
donnée par le paramètre (formel) N. C'est le seul cas de  taille  formelle 
possible, car T n'est qu'une référence à un objet  existant  par  ailleurs 
(dans  l'unité  appelante),  et  la  déclaration  de  T  ne  fait   aucune 
réservation de place mémoire. 

<sect>Adresses de retour alternatives<p>

 Exemple :
<tscreen><verb>
         PROGRAM  TRUC
           REAL  X,Y
           READ  (*,*) X,Y,F
           Y = F(X,*99)
           WRITE  (*,*) 'Resultat =',Y
           STOP
 C
C En cas d'erreur ................................
 99        WRITE  (*,*) 'F n''est pas definie en ',X
           STOP
         END

        REAL FUNCTION F ( X , * )
        REAL X,DENOM
         DENOM = X - 1.0
         IF  (DENOM .EQ. 0.0)  RETURN 1
            F = SIN(X) / DENOM
        RETURN
        END
</verb></tscreen>

Ici le second  paramètre  de  la  fonction  F  est  une  adresse  de retour  
alternative. Si l'instruction «RETURN 1» est exécutée  dans  F,  alors  un 
branchement est effectué à l'instruction 99  du  programme  principal.  On 
peut avoir plusieurs adresses de retour alternatives, c'est la  valeur  de 
l'expression  située  derrière  le  RETURN  qui  détermine  le  numéro  de 
l'adresse choisie.
      <p>
Dans l'unité appelante, n'oubliez pas de  mettre  une  étoile  devant  les 
étiquettes que vous passez en paramètres... 
<p>
Cette facilité  est  utilisée  très  souvent  pour  indiquer  (comme  ici)  
l'adresse d'une instruction à exécuter en cas d'anomalie. Elle est finalement
très 
voisine de la forme «READ(....END=...ERR=...)».


<chapt>Annexe : COMMON <p>

La définition de zones communes permet le partage d'un «pool» de  variables 
entre plusieurs unités de programmes. 

Exemple :

<tscreen><verb>
       INTEGER FUNCTION  DEPILE()  
       COMMON  /PILE/ H,T          
       INTEGER H,T(10)             
         DEPILE = T(H)              
         H = H - 1                  
       RETURN                      
       END                         

       SUBROUTINE  EMPILE(X)
       COMMON  /PILE/ H,T
       INTEGER  H,T(10),X
         H = H + 1
         T(H) = X
       RETURN
       END
</verb></tscreen>
      
      Dans  ces deux  unités l'instruction   COMMON  déclare  les variables  
H  et  T  comme  faisant  partie  de  la  zone  commune (globale)   nommée 
PILE.
<p>      
L'intention du programmeur est ici de définir un objet PILE, accessible par 
le biais de «primitives» : EMPILE, DEPILE,  VIDER,  etc  ...  L'usage  des 
COMMONs permet donc d'éviter  -  dans  certains  cas  -  des  passages  de 
paramètres inutiles. N'en abusez pas. Dans le  cas  où,  par  exemple,  un 
programme doit manipuler plusieurs piles,  on  préférera  passer  la  pile 
(hauteur + vecteur) en paramètre plutôt que définir une multitude de zones 
communes. A cet égard, la  philosophie  personnelle  de  l'auteur  est  la 
suivante:
   <p>   
On définit un COMMON chaque fois que l'on isole -dans  un  programme-  une 
entité unique destinée à être utilisé à  partir  de  plusieurs  unités  de 
programme. Le COMMON contient les variables propres  à  cette  entité,  et 
l'accès à ces variables ne doit sefaire qu'à partir d'un nombre  restreint 
de primitives d'accès.
<p>
Attention à l'ordre et au type des éléments d'un  COMMON,  le  compilateur 
FORTRAN ne vérifie pas la cohérence de type d'une unité à  l'autre....  En 
pratique il est très fortement conseillé de reproduire  textuellement  les 
instructions COMMON . 
<p>
Pour finir, notez que l'initialisation statique  (par  DATA) des  variables 
d'un COMMON ne peut se faire  qu'à  l'intérieur d'une  unité  de  programme 
BLOCK DATA (qui, d'ailleurs, ne sert qu'à çà).
<p>      
      Exemple : Si on veut initialiser la pile à vide :
<tscreen><verb>
         BLOCK DATA INIT
         COMMON /PILE/ H,T
         INTEGER H,T(10)
         DATA H / 0 /
         END
</verb></tscreen>

<chapt>Annexe : entrées-Sorties directes formattées<p>

Un fichier en accès direct peut être  assimilé  (approximativement)  à  un 
tableau d'enregistrements. L'accès (lecture  ou  écriture)  se  fait  donc 
toujours en précisant le numéro d'enregistrement (un entier positif).
<p>
 Exemple :
<tscreen><verb>
            PROGRAM  DEMOAD
 C
 C Demonstration de l'acces direct.
 C
 C le fichier AD.DAT contient des enregistrement de 20 caractères
 C l'utilisateur peut Voir ou Modifier chaque enregistrement.
 C 
            CHARACTER*1  COMMANDE
            CHARACTER*20 ENREG

            INTEGER  NUMERO
 C
 C
 C Ouverture du fichier AD.DAT en accès direct.
 C
            OPEN  ( 1 , FILE = 'AD.DAT',
      S               ACCESS = 'DIRECT',
      S                 FORM = 'FORMATTED'
      S                 RECL = 20          )
 C
 C On demande la commande ...   
 C
 1000       WRITE  (*,*) 'V(oir), M(odifier), S(top)'
            READ (*,1010) COMMANDE
 C
 C On regarde la commande ...
 C
            IF  (COMMANDE.EQ.'V')  THEN
 C
 C .... Voir ...
 C
                  WRITE  (*,*) 'Voir quel numéro ?'
                  READ  (*,*) NUMERO
                  READ (1,100,REC=NUMERO,ERR=1100) ENREG
 100              FORMAT  (A20)                 
                  WRITE  (*,*) 'Enreg',NUMERO,'=',ENREG
                  GOTO  1000
 C
 1100             WRITE  (*,*) 'Il n''y a pas d''enregistrement',
      S                              'numero',NUMERO                 
                  GOTO 1000
 C
             ELSE IF (COMMANDE.EQ.'M')  THEN
 C
 C .... Modifier ...
 C
                  WRITE  (*,*) 'Modifier quel numéro ?'
                  READ  (*,*) NUMERO
                  WRITE  (*,*) 'Mettre quoi à la place ?'
                  READ  (*,100) ENREG
                  WRITE (1,100,REC=NUMERO,ERR=1200) ENREG
                  GOTO  1000
 C
 1200             WRITE  (*,*) 'On ne peut pas modifer',
      S                   'l''enregistrement numero',NUMERO
                  GOTO  1000
 C
 C           ELSE IF  (COMMANDE.EQ.'S')  THEN
 C
 C .... stop ...
 C
 C                CLOSE  (1)
 C                STOP  'Ok.'
 C
             ELSE
 C
 C .... autre commande ...
 C
                  WRITE  (*,*) 'Je ne comprends que V,C ou S.'
                  GOTO  1000
 C
 C           ENDIF
 C
             END
</verb></tscreen>

Pour l'ouverture d'un fichier en  accès  direct,  il  faut  obligatoirement 
donner  les  clauses  « ACCESS='DIRECT',FORM='FORMATTED' » et   indiquer   la 
longueur  de  l'enregistrement  (en  octets)  par  « RECL=...»    qui   doit 
correspondre à la longueur des formats utilisés avec ce fichier.
<p>
Dans les ordres READ et WRITE, la  clause  «REC=...» permet  de  préciser  le 
numéro de l'enregistrement que l'on veutlire ou écrire.  Attention,  toute 
tentative de lecture d'unenregistrement absent se solde  par  une  erreur, 
que l'on peut (heureusement) récupérer par l'option «ERR=...» . 




</report>





