Types et opérateurs
Tout programme manipule de l’information, qui peut revêtir un certain nombre de formes simples prédéfinies dans un langage, ou être construite par composition de telles formes simples : ce sont les types de données, caractérisés pour l’ensemble des valeurs possibles, et les opérateurs définis sur ces valeurs.
Types scalaires prédéfinis
Ils sont au nombre de 5 en Fortran : entier, réel, complexe, logique et caractère. Ils sont tous paramétrables par un paramètre de type (KIND) pour en définir diverses variantes ou sous-types :
nom_de_type (KIND = paramètre de sous-type)
Il existe dans chaque cas un sous-type privilégié, correspondant à la valeur par défaut du paramètre KIND pour ce type, et désignant le type du Fortran 77 (pour des raisons de compatibilité ascendante).
Réciproquement, le paramètre de type d’un objet x s’obtient par la fonction prédéfinie KIND (x). L’ensemble des paramètres KIND disponibles dépend du compilateur.
Le sous-type d’une constante s’écrit en suffixant sa valeur par le paramètre KIND voulu (sous forme d’une constante) ; ex :
347_INT_SHORT avec la déclaration préalable :
Exemple
PARAMETER (INT_SHORT = 2)
■ Le type entier (INTEGER) est un intervalle fini de l’ensemble mathématique des entiers relatifs. On peut choisir de manière portable le sous-type voulu en spécifiant le nombre minimal r de chiffres décimaux requis, en prenant comme valeur du paramètre KIND celle de la fonction prédéfinie :
SELECTED_INT_KIND (r)
Réciproquement, la fonction prédéfinie RANGE (x) fournit le nombre maximal de chiffres décimaux autorisés par le sous-type (entier) de l’objet x.
■ Le type réel (REAL) est une approximation de l’ensemble mathé-matique des réels, formée de nombres rationnels (y compris 0) de la forme :
m • be où m (la mantisse) et e (l’exposant) sont des entiers relatifs, et b = 2 ou 16 en pratique selon l’architecture de la virgule flottante disponible.
On peut choisir de manière portable un sous-type réel en spécifiant la précision p souhaitée, et /ou l’intervalle des valeurs représentables désigné par r (pour 10 –r à 10 r en valeur absolue), hors 0, en prenant comme valeur du paramètre KIND celle de la fonction prédéfinie :
SELECTED_REAL_KIND (p, r)
L’ancien type DOUBLE PRÉCISION correspond à la nouvelle spécification :
REAL (Kind = KIND (0D0))
où l’objet 0D0 représente le réel zéro dans ce sous-type (= 0 ×100)
■ Le type complexe (COMPLEX) correspond au produit cartésien de deux types réels identiques : les composantes réelle et imaginaire. Un sous-type se définit donc par le même paramètre de type que pour les réels. Les constantes complexes se dénotent par une paire de nombres entre parenthèses ; exemple : (0 , 1.0).
Les trois types numériques partagent le même ensemble d’opé-rateurs, dénotés classiquement, par ordre de priorité algébrique croissante :
+ et – (unaires ou binaires) * et /
* * (exponentiation)
Ces opérateurs polymorphes agissent pour chaque type selon ses règles propres ; c’est ainsi que par exemple 8 / 5 donne l’entier 1 (troncature vers zéro).
■ Le type logique ou booléien (LOGICAL) correspond aux deux valeurs de vérité de la logique binaire, dénotées .FALSE. et .TRUE. .
Le paramétrage de ce type correspond seulement à des encombre-ments restreints, et dépend du compilateur. Par défaut, l’encombre-ment est d’un mot numérique (comme pour les types « par défaut » INTEGER et REAL, le type COMPLEX correspondant à deux mots). Les opérateurs logiques sont les suivants, par ordre de priorité croissante :
.EQV. et .NEQV. (équivalence et ou exclusif respectivement)
.OR.
.AND.
.NOT.
■ Le type caractère (CHARACTER) correspond au jeu de caractères disponibles sur la machine cible (celle sur laquelle le programme s’exécute). Le paramètre de type KIND pour les caractères est une exi-gence asiatique ; il peut aussi donner accès à des jeux de caractères mathématiques, chimiques, musicaux…
En fait, ce type correspond en Fortran aux chaînes de caractères : il admet donc un second paramètre : LEN, qui définit la longueur de la chaîne (vide le cas échéant) ; un caractère est une chaîne de longueur 1 (valeur par défaut du paramètre LEN).
Les constantes chaînes s’encadrent au choix par des guillemets
(”) ou des apostrophes. Le type caractère admet un opérateur interne : la concaténation, notée //.
On peut accéder à une sous-chaîne d’une chaîne par la notation : chaîne (a : b) ; exemple : ”0123456789” (N : N). Si a est omis, il vaut 1 ; si b est omis, c’est la longueur de la chaîne.
Par ailleurs, Fortran dispose d’opérateurs de comparaison, dont le résultat est du type logique par défaut, admettant deux noms distincts :
< <= == /= >= >
.LT. .LE. .EQ. .NE. .GE. .GT.
Ils sont applicables à deux opérandes d’un type scalaire quelconque, sauf complexe (qui n’admet que == et /=) et logique.
Types structures (ou « dérivés »)
C’est un type construit correspondant à un produit cartésien d’ensembles (champs) hétérogènes. Il est considérés comme scalaire par opposition aux tableaux, bien qu’il puisse contenir des champs tableaux. Ce type s’appelle article en Pascal, et enregistre-ment en Cobol. Le nom de type dérivé adopté par la norme est regret-table, car il reprend celui d’un concept du langage Ada qui n’a aucun rapport.
Un type structure se définit par une énumération de champs, chacun ayant un nom particulier et ses propres caractéristiques.
Exemple
TYPE client
INTEGER CODE
CHARACTER (LEN = 50) nom
CHARACTER (30) ville
INTEGER code-postal, & solde
END TYPE client
Un objet de ce type se déclare ainsi :
TYPE (client) quidam
En Fortran 90, les structures ne sont pas paramétrables, quant à leur forme (comme en Pascal, en C ou en Ada), mais on peut dimen-sionner un champ POINTER sur tableau (§ 2.4). On peut obliger le compilateur à implémenter les champs dans l’ordre spécifié en dotant le type de l’attribut SEQUENCE :
TYPE client ; SEQUENCE
INTEGER code, etc.
L’accès à un champ d’un objet structure se dénote à l’aide du caractère %.
Exemple
quidam % nom
Une valeur structure se construit en énumérant les valeurs des champs dans l’ordre.
Exemple
quidam = CLIENT (1, ”Dupont”, ”Paris”, 75001, 0)
Tableaux
Un tableau est une collection de données homogènes. Cette homogénéité a permis de bâtir des architectures matérielles massivement parallèles, dites vectorielles, pour appliquer simultanément une même opération à tout ou partie d’un tableau. Fortran 90 s’adapte à ce progrès technologique, en traitant le tableau comme un objet de « première classe » (comme en PL /1), escorté d’une panoplie d’outils favorisant le calcul vectoriel.
En Fortran, la structure de tableau est une propriété de l’objet (et non un type) ; elle se définit par les caractéristiques suivantes :
— son rang, ou nombre de dimensions ( 7 en Fortran) ; par convention, tout scalaire est de rang 0 ;
— chaque dimension possède un intervalle de définition, donné par deux entiers, et une étendue, qui est la longueur de cet intervalle (bornes comprises). En Fortran 90, une étendue peut être nulle, le tableau étant alors vide ;
— la taille d’un tableau est le produit de ses étendues. Un tableau vide est de taille 0 ;
— son profil est le vecteur (tableau de rang 1) de ses étendues. Le profil d’un scalaire est le vecteur vide. Deux tableaux sont dits compatibles s’ils ont le même profil ; par convention, un scalaire est compatible avec tout tableau.
Fortran 90 permet de définir des tableaux à profil explicite (constant ou calculable), et à profil différé (tableaux dynamiques).
Dans le cas d’un profil explicite, la structure du tableau est indiquée dans un attribut de dimension par la liste des intervalles de définition de ses diverses dimensions :
(i1 : s1 , i2 : s2 , … , in : sn ) avec n 7
la borne inférieure (in 🙂 pouvant être omise lorsqu’elle vaut 1.
Exemple
PARAMETER (N=5,M=10)
DIMENSION T3 (N , 0 : M , N + M)
Un tableau à profil différé est défini dynamiquement ; son attribut de dimension n’en précise que le rang, par une liste de caractères
« : » . Il reçoit en outre l’attribut ALLOCATABLE (à rapprocher de CONTROLLED en PL /1).
Exemple
REAL, ALLOCATABLE : : MAT (: , 🙂 ! rang = 2
Dans le cours du calcul, une fois les dimensions déterminées, le tableau est « créé » avec les dimensions voulues par une instruction ALLOCATE (§ 4.1).
L’accès à un élément de tableau s’opère à l’aide d’une liste d’indices (expressions entières quelconques) en nombre égal au rang du tableau.
Exemples
MAT (i , j + k)
ou T3 (1 , i * j , k /i + 2)
On peut aussi accéder à un sous-tableau, de deux manières :
— avec une notation par triplet, correspondant à une pseudo-boucle qui dénote une suite d’indices en progression arith-métique.
Exemple
T3(2:N,M:1:–1,1:M:2)
La notation a : b : r représente la progression de premier terme a et de raison r extraite de l’intervalle a : b. La raison par défaut est 1 (équivalent à la notion de tranche en Ada). Des notations simplifiées existent, pour désigner tout le début de l’intervalle de définition dans une dimension (: b), toute la fin (: a), ou l’intervalle en entier (:) ;
— avec un indice vectoriel.
Exemple
INTEGER, DIMENSION (4) : : INDEX = (/ 2, 0, 1, 10/)
DIMENSION VECT (0 : 20)
alors VECT (INDEX) désigne le vecteur :
(/ Vect (2), Vect (0), Vect (1), Vect (10) /)
Un indice vectoriel peut contenir des valeurs en double, avec certaines limitations quant à leur emploi, lorsque l’opération entraîne une sémantique ambiguë.
Objets pointés
Un objet pointé est créé dynamiquement par le programmeur, et reste sous son contrôle. Un tel objet se définit par son modèle (type + rang le cas échéant), et par une variable (POINTER), qui recevra l’adresse de l’objet une fois créé.
Exemple
INTEGER, POINTER : : P ! pointeur vers un objet entier
TYPE maillon ! élément d’une liste chaînée
INTEGER valeur
TYPE (maillon), POINTER : : succ
END TYPE maillon
TYPE (maillon), POINTER : : premier, temp
REAL, POINTER : : PVECT (:) ! pointeur vers un vecteur ! réel
Fortran 90 laisse une certaine ambiguïté dénotationnelle : l’identificateur déclaré avec l’attribut POINTER désigne tantôt le pointeur, tantôt l’objet pointé, selon le contexte syntaxique ; ainsi :
temp = maillon (10, premier) ! objet pointé
temp => premier ! pointeur
De même, le champ Succ du maillon d’adresse Premier se dénote (à la manière d’Ada) : Premier % Succ.
La constante (valeur symbolique) adresse notée NIL en Pascal et NULL en PL /1 ou Ada s’obtient par une instruction sur pointeur (s) en Fortran 90 :
NULLIFY (temp) ! temp : = NIL en Pascal.
La création dynamique d’un objet pointé se réalise par le même ordre ALLOCATE que pour les tableaux à profil différé.
Exemple
ALLOCATE (temp, pvect (0 : 10))
Fortran 90 permet encore de redéfinir dynamiquement une variable statique ou automatique, voire un paramètre, qui doit alors recevoir l’attribut TARGET dans sa déclaration (pour permettre au compilateur d’optimiser la gestion des autres variables).
Exemple
TARGET : : CIBLE (10, 10)
Un pointeur est associé dynamiquement à une cible par une affectation d’adresse (=> ; § 4.2.1).
Instructions de déclaration
Typage des objets
Il existe deux sortes d’objets (ou données) : les constantes, et les variables. Les variables se désignent toujours par un identificateur. Les constantes peuvent aussi le cas échéant être nommées (§ 3.2, attribut PARAMETER). Les objets nommés (constantes et variables) doivent être typés en Fortran. Ce typage s’opère soit implicitement,
d’après la lettre initiale du nom de l’objet ; soit explicitement, au moyen d’une déclaration de type de l’objet. Par défaut, tout objet nommé non déclaré est du type entier si son nom commence par une lettre de I à N, et réel sinon.
Le typage implicite peut être modifié au moyen d’une instruction de déclaration IMPLICIT associant un ensemble de lettres à une spécification de type. Par défaut, on a ainsi :
IMPLICIT INTEGER (I-N), REAL (A-H, O-Z)
Au contraire, si l’on veut proscrire tout typage par défaut (pour des logiciels hautement critiques par exemple), on peut utiliser la déclaration :
IMPLICIT NONE
Une déclaration IMPLICIT se place en premier lieu dans une unité de programme (après d’éventuelles déclarations d’importation USE : § 6).
1. Structure générale du langage
1.1 Exemple de programme Fortran 90
1.2 Architecture des programmes
1.3 Structure lexicale
2. Types et opérateurs
2.1 Types scalaires prédéfinis
2.2 Types structures (ou « dérivés »)
2.3 Tableaux
2.4 Objets pointés
3. Instructions de déclaration
3.1 Typage des objets
3.2 Les deux syntaxes orthogonales de déclaration
3.3 Liste des attributs de déclaration
4. Charpente algorithmique des programmes
4.1 Expressions
4.2 Instructions simples
4.3 Schémas algorithmiques
5. Procédures
5.1 Définitions
5.2 Classification des procédures par localisation
5.3 Paramètres et modes de transmission
5.4 Caractéristiques spécifiques aux fonctions
5.5 Blocs d’interface et applications
5.6 Macrofonctions
6. Modularité
6.1 Présentation
6.2 Entités visibles et privées
6.3 Importation des ressources d’un module
7. Entrées-sorties
7.1 Fichiers
7.2 Ordres généraux
7.3 Instructions de lecture-écriture
7.4 Les fichiers de texte
8. Liste des procédures prédéfinies
8.1 Fonctions distributives
8.2 Fonctions-attributs
8.3 Fonctions de transformation
8.4 Sous-programmes prédéfinis
9. Conclusion
Pour en savoir plus