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 ...
.LT. ( < ) .GT. ( > )
.LE. ( ) .GE. ( )
.EQ. ( = ) .NE. ( # )
.NOT. (non) .AND. (et) .OR. (ou)
.EQV. (équivalence) .NEQV. (ou exclusif)
//
Identificateurs et constantes reliés par des opérateurs. Exemples :
A + B * ( C ** D )
(1.LE.K).AND.(K.LE.MAX)
PATH // '/' // NOM // '.' // EXT
Autres types de données : Réels double-précision, Complexes (simple et double précision), Fractionnels, Virgules fixes, etc ...
Une 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 identificateur. Un type est associé à chaque variable
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.
Scalaire : donnée unique désignée par un nom.
Tableau : collection d'objets du même type.
Une déclaration de tableau se fait en mentionnant - après son nom - la liste des intervalles de ses indices.
Exemple :
REAL TAB(5:12,3,0:20)
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.
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 :
TAB(6,2,0)
.
Pendant l'exécution, si un indice déborde des bornes indiquées, le résultat est indéfini.
Un programme est composé d'une ou plusieurs unités de programme :
La portée des identificateurs de variables et des étiquettes est limitée à une unité de programme.
Les noms des sous-programmes, fonctions et zones communes (COMMON) sont accessibles à partir de toute unité.
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).
Un exemple de programme FORTRAN :
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
Une variable est déclarée en citant : son type, son nom et, (pour les tableaux) les bornes des indices.
Principaux types :
INTEGER INTEGER*2 INTEGER*4
REAL COMPLEX DOUBLE PRECISION
LOGICAL
CHARACTER*1 .... CHARACTER*256
Exemple :
INTEGER*4 A(20,3),B
CHARACTER*1O C(0..9)
LOGICAL D(3,4,8:12)
Ces instructions déclarent :
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'initialisation statique d'une variable, par opposition à l'initialisation dynamique qui se fait à l'exécution au moyen d'une instruction d'affectation.
Exemples :
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' /
Le dernier exemple utilise des facteurs de répétition : les 3 premiers élements de NAMES contiendront 'AAAAAAAAAA', les 8 autres 'XXXXXXXXXX'.
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.
Cette unité de programme commence par la ligne :
PROGRAM nom
Exemple 1 :
PROGRAM ESSAI
INTEGER I
C
DO 1000 I=1,10
WRITE (*,*) ' Bonjour !'
1000 CONTINUE
C
STOP
END
SUBROUTINE ECHANG ( X,Y )
INTEGER X,Y,INTER
C
INTER = X
X = Y
Y = INTER
C
RETURN
END
Les sous-programmes sont appelés par l'ordre CALL. Exemple :
CALL ECHANG( T(I) , T(I+1) )
INTEGER FUNCTION MAX (N1,N2)
INTEGER N1, N2
C
IF (N1 .GE. N2) THEN
MAX = N1
ELSE
MAX = N2
ENDIF
C
RETURN
END
Les fonctions sont appelées à partir des expressions. Elles retournent toujours une valeur.
Exemple d'appel de fonction :
I12 = 2 * MAX(A+1,B+2) - MAX (C,10)
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
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 gags plutôt difficiles à déceler).
Exemple typique d'erreur :
REAL FUNCTION F (X)
REAL F, X
F = X + 1.0
RETURN
END
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 !
Autre source d'erreurs : ne pas oublier de déclarer le type d'une fonction appelée dans l'unité appelante. Exemple d'erreur :
INTEGER FUNCTION CARRE (N)
INTEGER N
CARRE = N * N
RETURN
END
INTEGER FUNCTION P4 (N)
INTEGER N
P4 = CARRE ( CARRE ( N ) )
RETURN
END
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 ».
Cette unité de programme un peu spéciale sert uniquement à l'initialisation statique (par DATA) des zones communes. Elle commence par la ligne :
BLOCKDATA nom
et ne peut contenir que :
(Pour plus d'informations se reporter à l'annexe sur l'utilisation des zones communes).
Exemple : PAS ( N , P ) = PAS ( N-1 , P-1 ) + PAS ( N , P )
Le déroulement d'une affectation « var = expression » est le suivant :
Ainsi, si les variables I et R sont respectivement de type INTEGER et REAL, les instructions :
I = 1
R = I / 2.0
provoquent l'affectation de la valeur 0.5 à R, tandis que :
I = 1
R = I / 2
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).
C'est une «non-opération», qui sert uniquement à poser une étiquette (en particulier dans les boucles DO).
Exemple :
DO 1000 K=1,N
A(K) = B(K) + 1
1000 CONTINUE
Provoque l'arrêt complet du programme en cours.
Exemple : GOTO 1234
Provoque un saut (branchement) à l'instruction (de la même unité de programme) qui porte l'étiquette 1234.
Exemple : GOTO (1010,2000,3000,1515),I+1
Si l'expression I+1 a pour valeur 1, alors saut à l'étiquette 1010. Si la valeur est 2, saut à 2000; etc.
Si la valeur calculée estt inférieure à 1 ou supérieure au nombre d'étiquettes citées, on passe simplement à l'instruction suivante.
Instruction de la forme : IF ( condition ) instruction
Exemple :
IF ( M .LT. FT(K) ) M = T(K)
K = K + 1
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) ).
Le « IFlogique » est très souvent employé en compagnie de l'instruction GOTO, c'est-à-dire sous la forme :
IF( condition ) GOTO etiquette
C'est le « GOTO conditionnel ».
Forme générale :
IF ( condition1 ) THEN
bloc 1
ELSE IF ( condition2 ) THEN
bloc 2
ELSE IF ( condition3 ) THEN
bloc 3
....
ELSE
bloc-else
ENDIF
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 ...
Si les conditions sont toutes fausses, c'est le bloc-else qui est exécuté.
Le nombre de parties ELSE IF n'est pas limité (on peut ne pas en mettre). La partie ELSE est également facultative.
Exemples :
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
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 :
IF ( Expression ) Etiquette1,Etiquette2,Etiquette3
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.
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 :
IF (M-T(K)) 100,200,200
100 M = T(K)
200 K = K + 1
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).
Exemple : DO 100 K=1,N
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).
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.
Exemple
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
Quelques remarques :
DO étiquette indice = début , fin , pas
et aussi utiliser des boucles à indice de type réel (attention aux
erreurs d'arrondis).
Le point important est qu'un ordre d'entrée-sortie FORTRAN (lecture ou écriture) mentionne (au moins) trois choses :
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
Exemples :
WRITE ( 6,100 ) A,B,C
WRITE ( 6,123 ) A, B+1 , ( T(K), K=1,N )
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) »
Le second exemple montre une « boucle DO implicite », qui parcourt les N premiers élements du tableau T.
Autre exemple de boucle DO implicite :
WRITE (6,421) ( ((10*I+J), J=1,I) , I=1,9 )
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.
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.
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.
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 :
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
et aussi pour les programmes « quick'n dirty ».
Exemples :
READ (5,100) X,Y,Z
READ (5,100,END=123) A,B,C
READ (5,100,END=123,ERR=987) U,V,W
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 ».
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.
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 ».
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 « ' ».
L'usage des formats libres est :
Exemple :
WRITE (*,100) I,J,K
...
100 FORMAT ( 5X ,'Le ppcm de ',I2,' et ',I2,' vaut ',I4)
Dans cet exemple l'ordre WRITE provoque l'écriture (sur la sortie standard) d'une ligne composée de :
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.
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 :
WRITE (*,100) A,B,C
100 FORMAT (2I4)
Cette règle dit :
Si la parenthèse finale est rencontrée alors qu'il reste des données à traiter :En réfléchissant un peu, c'est finalement très simple.
- s'il n'y a pas de groupes de spécifications entre parenthèses, le format est repris au début;
- 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.
OPEN (1)
OPEN (1,FILE='FICH.ABC')
OPEN (1,FILE='TOTO.X',STATUS='OLD',ERR=123)
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.
On peut donner comme STATUS la chaîne 'NEW', qui signifie que le fichier n'existait pas préalablement, ou 'UNKNOWN' ...
Il existe des quantités d'autres clauses, voir en particulier l'annexe relative à l'utilisation des fichiers en accès direct.
Il n'est pas nécessaire d'ouvrir les fichiers 5 et 6.
CLOSE (1)
ferme le fichier - préalablement ouvert - indiqué.
Il est inutile de fermer les fichiers standards 5 et 6.