Les premiers pas
Cette page présente les principales fonctionnalités de JOVIAL. Ils traitent des valeurs, de l'entreposage, des calculs, des opérateurs, des fonctions intégrées, du flux de contrôle, des sous-routines, des programmes, des directives du compilateur, des macros du compilateur et, enfin, des fonctionnalités avancées du langage.
Les valeurs
Les types de valeurs fournies par JOVIAL reflètent les applications du langage de programmation; elles sont orientées vers l'ingénierie et la programmation de contrôle plutôt que, par exemple, la programmation commerciale et d'entreprise. Les valeurs JOVIAL sont :
- Les valeurs entières, étant des nombres entiers signés ou non signés. Elles sont utilisées pour le comptage. Par exemple, un entier peut être utilisé pour compter le nombre de fois qu'une boucle est répétée ou le nombre de contrôles effectués sur un processus.
- Les valeurs flottantes, étant des nombres avec des facteurs d'échelle «flottants». Elles sont utilisées pour les quantités physiques, en particulier lorsque l'intervalle de mesure ne peut pas être prédite avec précision. Par exemple, les valeurs flottantes sont fréquemment utilisées pour représenter la distance, la vitesse, la température, le temps,...
- Les valeurs fixes, étant des nombres avec des facteurs d'échelle constants. Elles sont parfois utilisées pour les quantités physiques (principalement pour gagner du temps et/ou d'entreposage) lorsque l'intervalle de valeurs est étroite et prévisible. Par exemple, des valeurs fixes peuvent être utilisées dans un calcul devant être exécuté sur un ordinateur pour lequel le matériel à virgule flottante n'est pas disponible ou est trop lent.
- Les valeurs de chaîne de bits, étant des séquences de chiffres binaires (bits). Elles sont utilisées pour la communication avec des dispositifs «marche/arrêt» ou pour contrôler des parties du programme lui-même. Par exemple, une chaîne de bits peut être utilisée pour représenter les réglages des commutateurs sur une console de commande.
- Les valeurs de chaîne de caractères, étant des séquences de caractères. Elles sont utilisées pour la communication avec des personnes. Par exemple, une chaîne de caractères peut être envoyée à un terminal d'opérateur pour signaler une défaillance d'une partie du système.
- Les valeurs d'état, étant des mots spéciaux. Elles sont utilisées pour décrire l'état du système, ou d'une partie particulière du système, à un moment donné. Par exemple, les valeurs d'état «V(OK)», «V(WEAF)» ou «V(BAD)» peuvent être utilisées pour indiquer l'état d'une cellule d'alimentation.
- Les valeurs de pointeur, étant des adresses de données, significatives uniquement dans le programme. Elles sont utilisées pour localiser des données indirectement. Par exemple, une liste d'éléments peut utiliser des pointeurs pour connecter chaque élément à l'élément suivant de la liste.
- Les valeurs de table, étant des collections de valeurs rassemblées pour former un seul objet de données. Elles sont utilisées pour les constructions appelées «tableaux» et «structures» dans d'autres langages. Par exemple, une table peut être utilisée pour entreposer des relevés de température effectués toutes les 10 secondes pendant une période de test donnée.
- Les valeurs de bloc, étant des collections de valeurs rassemblées dans une région de la mémoire. Elles sont utilisées pour prendre en charge la gestion de la mémoire. Par exemple, certaines données devant être paginées en entrée et en sortie de la mémoire ensemble peuvent être placées dans un bloc.
L'entreposage
Lorsqu'un programme JOVIAL est exécuté, chaque valeur sur laquelle il opère est entreposée dans un élément. L'élément a un nom, étant déclaré puis utilisé dans le programme lorsque la valeur de l'élément est extraite ou modifiée.
Un élément est déclaré par une instruction JOVIAL appelée instruction de déclaration. La déclaration fournit au compilateur les informations dont il a besoin pour allouer et accéder au stockage de l'élément. Voici une instruction déclarant un élément entier :
- ITEM COUNT U 10
Cette déclaration indique que la valeur de COUNT est un entier étant entreposé sans signe sur dix bits ou plus. La notation est compacte : «U» signifie qu'il s'agit d'un entier non signé, «10» signifie qu'il nécessite au moins 10 bits. Nous disons «au moins» dix bits car le compilateur JOVIAL peut allouer plus de dix bits. (Cette allocation gaspille un peu d'espace de données, mais peut donner lieu à un code plus rapide et plus compact.)
JOVIAL ne nécessite pas que vous donniez le nombre de bits dans la déclaration d'un élément entier. Si vous l'omettez, JOVIAL fournit une valeur par défaut dépendant de l'implémentation de JOVIAL que vous utilisez. En voici un exemple :
- ITEM TIME S;
Cette instruction déclare TIME comme étant le nom d'une variable entière item signée et possédant le nombre de bits par défaut. Sur une implémentation de JOVIAL, cela équivaudrait à la déclaration suivante :
- ITEM TIME S 15;
L'élément TIME occupe 16 bits (signe compris). Dans une autre implémentation, cela équivaudrait à :
- ITEM TIME S 31;
Dans cette brève introduction, nous ne pouvons pas considérer chaque type d'élément en détail (comme nous venons de le faire pour les éléments entiers). À la place, une liste d'exemples suit, une déclaration pour chaque type de valeur.
Exemple | Description |
---|---|
|
Un élément entier signé, occupant au moins trois bits et accueillant des valeurs de -3 à +3. |
|
Un élément flottant dont la valeur est entreposée sous forme de coefficient variable (mantisse) et de facteur d'échelle variable (exposant). Le «30» spécifie trente bits pour la mantisse et détermine ainsi la précision de la valeur. Le nombre de bits de l'exposant est spécifié par l'implémentation, et non par le programme. Il est toujours suffisant pour prendre en charge une large gamme de nombres. |
|
Un élément fixe, dont la valeur est entreposée avec une échelle fixe, à savoir deux bits à gauche du point binaire et treize bits fractionnaires. Il accepte donc une valeur dans la plage -4 < valeur < +4 avec une précision de 1/(2**14). |
|
Un élément de chaîne de bits dont la valeur est une séquence de dix bits. Il peut donc contenir, par exemple, les paramètres de dix commutateurs marche/arrêt de la console. |
|
Un élément de chaîne de caractères dont la valeur est une séquence de quatre-vingts caractères. Il peut donc contenir, par exemple, le message «WARNING: Cooling system failure» (avec de nombreuses positions de caractères restantes). |
|
Un élément d'état dont la valeur peut être considérée comme «V(RED)», «V(YELLOW)» ou «V(GREEN)» mais étant en fait entreposé de manière compacte sous forme d'entier. Ainsi, un programmeur peut attribuer «V(RED)» à une variable pour indiquer une défaillance du système de refroidissement au lieu d'utiliser un entier (probablement non mnémonique). |
|
Un élément pointeur, dont la valeur est l'adresse d'un objet de données de type DATA. |
Les éléments ne sont que les données scalaires (à valeur unique) de JOVIAL. Le JOVIAL possède également des tables et des blocs, permettant de créer des tableaux et d'autres structures de données.
Voici un exemple de déclaration de table :
- TABLE GRID (1:10, 1:10);
- BEGIN
- ITEM XCOORD U;
- ITEM YCOORD U;
- END
Le tableau GRID comporte deux dimensions. Chaque dimension contient dix entrées. Chaque entrée se compose de deux éléments, XCOORD et YCOORD. Voici un exemple de déclaration de bloc :
- BLOCK GROUP;
- BEGIN
- ITEM FLAG B;
- TABLE DATA(100);
- ITEM POINT U;
- END
Le bloc GROUP contient l'élément FLAG et le tableau DATA.
Les éléments, les tableaux et les blocs peuvent également être déclarés à l'aide de noms de type. Un nom de type est défini dans une déclaration de type. Voici un exemple de déclaration de type :
- TYPE COUNTER U 10;
Le nom de type COUNTER peut être utilisé pour déclarer des entiers de dix bits. Par exemple :
- ITEM CLOCK COUNTER;
Les calculs
Dans le cas le plus simple, le calcul est effectué par une instruction d'affectation. En voici un exemple :
- AVERAGE = (X1 + X2)/2;
Le côté droit de cette affectation est une formule ; elle forme la somme de X1 et X2 et la divise par 2. Les détails de l'opération dépendent de la manière dont Xl et X2 sont déclarés. Si X1 et X2 sont déclarés en virgule flottante, le calcul a de fortes chances de produire le résultat attendu. En revanche, si X1 et X2 sont déclarés fixe (F), la mise à l'échelle doit être effectuée par le programmeur pour s'assurer que le calcul réussira. Et si X1 et X2 sont déclarés en chaîne de caractères, le compilateur le rejettera car JOVIAL ne convertit pas automatiquement les valeurs dans les types requis par les opérateurs.
Dans l'exemple venant d'être donné, les parenthèses montrent que l'addition est effectuée avant la division. Lorsque les parenthèses ne sont pas fournies, JOVIAL reconnaît l'ordre d'évaluation habituel. Voici un exemple :
- POLY = BETA*X1**2 - GAMMA*X2 + DELTA;
JOVIAL applique ses «règles de priorité» à la formule de cette mission et l'interprète ainsi comme :
- POLY = (((BETA*(X1**2)) - (GAMMA*X2)) + DELTA);
Les exemples venant d'être donnés illustrent l'utilisation de formules sur le côté droit d'une instruction d'affectation. Une formule peut également apparaître sur une partie du côté gauche d'une instruction d'affectation, par exemple en tant qu'indice d'un tableau. En plus de leur rôle important dans les instructions d'affectation, les formules peuvent apparaître à de nombreux autres endroits du langage de programmation : en tant que paramètres réels de fonctions et de procédures, en tant que condition dans une instruction if,...
Étant donné que JOVIAL possède un certain nombre de types de valeurs, il doit disposer de plusieurs moyens de convertir un type de valeur en un autre type. Dans la plupart des cas, vous devez indiquer explicitement la conversion. En voici un exemple :
- ITEM MARK U 10;
- ITEM TIME F;
- ...
- MARK = (* U 10 *) (TIME);
La valeur de l'élément flottant TIME est convertie en une valeur entière de dix bits avant d'être affectée à l'élément entier de dix bits MARK. Si vous laissez l'opérateur de conversion en dehors de cette affectation, le compilateur signalera une erreur. Le compilateur détecte les situations dans lesquelles un type de valeur est involontairement affecté ou combiné à un type de variable différent.
Les opérateurs
Les opérations fournies dans JOVIAL reflètent les applications du langage de programmation : elles déterminent ce que le langage peut et ne peut pas faire. Ainsi, JOVIAL est fort en calcul numérique et en logique de contrôle, mais dispose d'opérations minimales pour le traitement de texte.
JOVIAL ne dispose d'aucune opération d'entrée-sortie ou de maintenance de fichiers car il est supposé qu'un programme JOVIAL s'exécute dans un environnement relativement spécialisé fournissant des sous-routines pour ces opérations.
Certaines opérations de JOVIAL sont représentées par des opérateurs, d'autres par des fonctions intégrées.
Les opérateurs JOVIAL sont résumés dans le tableau suivant :
Type | Opérateurs | Opération |
---|---|---|
Arithmétique | + - | Signes préfixes |
** | Exponentielle | |
* / MOD | Multiplier, diviser et modulo | |
+ - | Infixe additionner et soustraire | |
Relationnelle | < > = | Inférieur à, supérieur à, égal |
<= >= <> | Inférieur ou égal, supérieur ou égal, différent | |
Logique | NOT | (préfixe) "pas" |
AND OR | "et", "ou" | |
XOR EQV | «exclusif ou», «équivalent» |
Un opérateur arithmétique prend comme opérandes des valeurs entières, flottantes ou fixes et produit comme résultat une valeur entière, flottante ou fixe. Les classes de types ne peuvent pas être mélangées. Par exemple, une valeur fixe ne peut pas être ajoutée à une valeur flottante à moins que l'une ne soit explicitement convertie dans le type de l'autre.
Un opérateur relationnel compare deux valeurs quelconques du même type et produit une valeur booléenne comme résultat. Un opérateur logique prend des valeurs de chaîne de bits et produit également un résultat booléen. (Une valeur booléenne est une chaîne de bits d'un bit, représentant "true" ou "false", selon qu'elle est égale à un ou à zéro.)
Fonctions intégrées (Built-In Functions)
Les fonctions intégrées de JOVIAL fournissent des opérations avancées et spécialisées n'étant pas couvertes par les opérateurs JOVIAL. Elles sont résumées dans le tableau suivant :
Fonction | Résultat |
---|---|
LOC(r) | Un pointeur vers l'objet référencé par r |
NEXT(p,i) | Un pointeur vers le i-ème objet de données après celui sélectionné par p |
NEXT(s,i) | La i-ème valeur d'état après la valeur d'état a |
BIT(b,i,n) | Une chaîne de n bits commençant au i-ème bit de la chaîne de bits b |
BYTE(c,i,n) | Une chaîne de n caractères commençant au i-ème caractère de la chaîne de caractères c |
SHIPTL(b,n) | Chaîne de bits b décalée vers la gauche de n bits |
SHIFTR(b,n) | Chaîne de bits b décalée vers la droite de n bits |
ABS(x) | Valeur absolue de x |
SGN(x) | +1, 0 ou -1 pour x>0, x=0, x<0 |
BITSIZE(x) | Taille logique de x en bits |
BYTESIZE(x) | Taille logique de x en octets |
WORDSIZE(x) | Taille logique de x en mots |
LBOUND(t,d) | Borne inférieure de la d-ième dimension du tableau t |
UBOUND(t,d) | Borne supérieure de la d-ième dimension du tableau t |
NWSDEN(t) | Nombre d'octets alloués à chaque entrée de la table t |
FIRST(s) | Première valeur d'état dans la liste d'état pour s |
LAST(s) | Dernière valeur d'état dans la liste d'état pour a |
Un exemple d'utilisation d'une fonction intégrée est :
- C = BYTE("ABCDEF",2,3);
La fonction intégrée extrait «BCD» de la chaîne de caractères «ABCDEF».
Deux des fonctions intégrées, BIT et BYTE, peuvent être utilisées comme pseudo-variables. Sous cette forme, elles apparaissent comme la cible d'une affectation et sont interprétées «à l'envers». En voici un exemple :
- C = "ABCDEF";
- BYTE(C,2,3) = "XYZ";
Cette affectation modifie les deuxième, troisième et quatrième caractères de C en «XYZ». La valeur de C après l'affectation est donc «AXYZEF».
Les flux de contrôle
Pour un flux de contrôle structuré, JOVIAL dispose d'une instruction if, d'une instruction case et d'une instruction loop avec une instruction exit facultative. Des exemples de ces instructions suivent.
Voici un exemple d'une instruction if :
- IF SPEED < LIMIT:
- FLAG = TRUE;
- ELSE
- BEGIN
- FLAG = FALSE;
- VIOLATION = VIOLATION+1;
- END
Si SPEED est inférieur à LIMIT, cette instruction définit FLAG sur TRUE et ne fait rien d'autre. Si SPEED n'est pas inférieur à LIMIT, l'instruction définit FLAG sur FALSE et incrémente VIOLATION. Les quatre dernières lignes de l'exemple sont une instruction composée ; la paire BEGIN-END regroupe les affectations à FLAG et VIOLATION dans une seule instruction composée contrôlée par la clause ELSE.
La clause ELSE d'une instruction if est facultative : lorsqu'elle est omise, aucune action n'est entreprise lorsque la condition est fausse. De plus, les instructions if peuvent être imbriquées, ce qui permet de créer des structures de contrôle complexes. Cependant, lorsque les instructions if deviennent volumineuses et compliquées, vous pouvez parfois utiliser une instruction case pour clarifier les choses.
Voici un exemple d'énoncé de cas :
- CASE NUM;
- BEGIN
- (DEFAULT): TYPE-V(OUT'OF'RANGE);
- (1,3,5,7,11,13,17,19): TYPE-V(PRIME);
- (2,4,6,8,10,12,14:16,18,20): TYPE-V(NONPRIME);
- END
Cette instruction case définit TYPE sur l'une des trois valeurs d'état, en fonction de la valeur de l'élément entier NUM. Si NUM est en dehors de l'intervalle de 1 à 20, la valeur d'état est "V(OUT'OF'RANGE)". Si NUM est dans l'intervalle et est premier, la valeur d'état est "V(PRIME)". Si NUM est dans l'intervalle mais n'est pas premier, la valeur d'état est "V(NONPRIME)". Chaque fois que l'instruction est exécutée, la valeur de NUM est comparée à la liste de valeurs entre parenthèses. Si elle correspond à l'une d'entre elles, l'instruction sur cette ligne est exécutée. La notation "8:10" signifie "8,9,10".
Le sélecteur de cas (NUM dans l'exemple venant d'être donné) peut être un entier, un bit, un caractère ou une formule d'état. Il n'est pas inhabituel qu'une routine soit dominée par une seule instruction case, et les instructions case sont souvent imbriquées dans des instructions case plus grandes.
Les instructions de boucle sont utilisées pour répéter une séquence d'instructions. Voici un exemple d'instruction de boucle :
- FOR I:0 BY 1 WHILE I<1000;
- BEGIN
- VAL = INPUT;
- IF VAL < 0;
- EXIT;
- GIVEN(I) = VAL;
- END
Cette instruction utilise la fonction INPUT pour obtenir une valeur d'entrée et affecte cette valeur à VAL. Elle affecte des valeurs d'entrée à GIVEN(1), GIVEN(2), GIVEN(3), et ainsi de suite jusqu'à ce que GIVEN(999) ait été affecté ou qu'une entrée négative soit rencontrée. Les exemples utilisent une instruction EXIT, provoquant une sortie immédiate de la boucle englobante.
JOVIAL possède également une forme de boucle ne comportant que la clause WHILE ; elle peut être utilisée lorsque la boucle ne nécessite pas d'index. De nombreux calculs peuvent être écrits sous forme de boucle WHILE (continuant jusqu'à ce qu'une condition de fin soit remplie) entourant une instruction case (sélectionnant l'action appropriée à chaque fois dans la boucle).
JOVIAL possède des instructions GO TO et des étiquettes d'instruction facultatives les accompagnant. De nombreux programmeurs évitent d'utiliser les instructions et les étiquettes GO TO, conformément au style de programmation actuel ; mais elles sont là en cas de besoin.
Enfin, JOVIAL possède une instruction STOP. Sa signification dépend de l'implémentation particulière ; mais son but est de fournir un retour contrôlé à l'environnement du programme.
Les sous-routines
Un programme JOVIAL est un ensemble de sous-routines regroupées de la manière décrite plus loin dans cette introduction. Idéalement, ces sous-routines sont petites. Lorsqu'une sous-routine donnée devient trop grande, une partie de celle-ci est extraite et transformée en une sous-routine distincte. De cette façon, chaque sous-routine est suffisamment petite pour être comprise, améliorée, testée et, plus tard dans la vie du programme, modifiée.
Une sous-routine peut être soit une procédure, étant appelée dans une instruction d'appel de procédure, soit une fonction, renvoyant une valeur et est utilisée dans une formule.
Voici un exemple de procédure :
- PROC RETRIEVE(CODE:VALUE);
- BEGIN
- ITEM CODE U;
- ITEM VALUE F;
- VALUE = -99999.;
- FOR I:0 BY 1 WHILE I<1000;
- IF CODE = TABCODE(I);
- BEGIN
- VALUE = TABVALUE(I);
- EXIT;
- END
- END
La procédure RETRIEVE possède un paramètre d'entrée CODE et un paramètre de sortie VALUE. Si la valeur de CODE est trouvée dans la table globale à laquelle appartient l'entrée TABCODE, la valeur associée TABLVALUE est renvoyée. Si la valeur de CODE n'est pas trouvée, la valeur «-99999.» est renvoyée.
Cette procédure pourrait être écrite sous forme de fonction, comme suit :
- PROC FIND(CODE) F;
- BEGIN
- ITEM CODE U;
- FIND = -99999.;
- FOR I:0 BY 1 WHILE I<1000;
- IF CODE = TABCODE(I);
- BEGIN
- FIND = TABVALUE(I);
- EXIT;
- END
- END
La fonction FIND possède un paramètre d'entrée CODE et une valeur de retour, étant désignée dans la fonction par le nom de fonction FIND.
L'instruction d'affectation suivante a le même résultat qu'une instruction d'appel de procédure sur RETRIEVE :
- VALUE = FIND(CODE);
La fonction FIND renvoie soit la valeur associée à la valeur de CODE dans la table, soit la valeur «-99999.» indiquant que la valeur de CODE n'a pas été trouvée.
Dans ces exemples, la recherche a eu lieu dans une table globale contenant 1000 entrées. Les sous-routines peuvent être écrites pour accepter une table de n'importe quelle longueur comme paramètre. Voici la fonction FIND réécrite pour rechercher une table fournie comme paramètre :
- PROC FIND(CODE,TAB);
- BEGIN
- ITEM CODE U:
- TABLE TAB(*);
- BEGIN
- ITEM TABCODE U;
- ITEM TABVALUE F;
- END
- FIND = -99999.:
- FOR I:0 BY 1 WHILE I<UBOUND(TAB,0);
- IF CODE = TABCODE(I);
- BEGIN
- FIND = TABVALUE(I);
- EXIT:
- END
- END
Cette fonction accepte la table à rechercher comme paramètre réel. La déclaration du paramètre formel de la table utilise le caractère * pour indiquer que les limites doivent être prises à partir des limites de la table donnée comme paramètre réel. La fonction intégrée UBOUND est alors utilisée dans l'instruction de boucle pour contrôler le nombre de fois que la boucle est exécutée.
Les sous-routines peuvent également être récursives ou réentrantes. Une sous-routine récursive doit avoir l'attribut REC dans sa déclaration et une sous-routine réentrante doit avoir l'attribut RENT dans sa déclaration.
Les programmes
Un programme est composé de modules. Un module est une partie d'un programme pouvant être compilée séparément. Un programme doit avoir un, et un seul, module de programme principal. Il peut avoir n'importe quel nombre de modules de procédure et de modules compool.
Le module de programme principal contient les actions à effectuer dans le programme. L'exécution du programme démarre à la première instruction du module principal du programme et se poursuit jusqu'à ce qu'une instruction d'arrêt ou la dernière instruction du module principal du programme soit atteinte.
Un module de procédure contient des procédures devant être partagées. Considérez le module de procédure suivant, contenant une déclaration externe pour la sous-routine FIND :
- START
- |COMPOOL 'DATA';
- DEF PROC FIND(CODE,TAB);
- BEGIN
- ITEM CODE U;
- TABLE TAB(*);
- BEGIN
- ITEM TABCODE U;
- ITEM TABVALUE F;
- END
- FIND = -99999.;
- FOR I:0 BY 1 WHILE I<UBOUND(TAB,0);
- IF CODE = TABCODE(I);
- BEGIN
- FIND = TABVALUE(I);
- EXIT;
- END
- END
- TERM
Le module de procédure commence par le mot réservé START et se termine par le mot réservé TERM. Il contient une directive COMPOOL fournissant un lien avec le module compool DATA et une définition de sous-programme externe (indiquée par le mot réservé DEF).
Le mot réservé DEF indique qu'une déclaration de données ou une définition de sous-programme est externe et peut donc être utilisée dans d'autres modules. Le mot réservé REF indique qu'une déclaration de données ou une définition de sous-programme est externe dont la spécification DEF correspondante est donnée dans un autre module.
Un module compool contient des informations à partager :
- START COMPOOL DATA;
- DEF TABLE PRIVILEGE(100);
- BEGIN
- ITEM NUMBER U;
- ITEM RATING F;
- END
- DEF TABLE ASSIGNMENT(999);
- BEGIN
- ITEM KEY U;
- ITEM COORDINATE F;
- END
- DEF ITEM LIMIT U;
- REF PROC FIND(CODE,TAB) F;
- BEGIN
- ITEM CODE U;
- TABLE TAB(*);
- BEGIN
- ITEM TABCODE U:
- ITEM TABVALUE F;
- END
- END
- TERM
Le compool DATA contient trois déclarations de données externes (spécifications DEF) et une référence de sous-routine externe (spécification REF).
Voici un exemple de module de programme principal utilisant ces modules de procédure et de compool :
- START |COMPOOL ('DATA');
- PROGRAM MAIN;
- BEGIN
- FOR I:0 BY 1 WHILE I < UBOUND(PRIVILEGE,0);
- IF FIND(I,PRIVILEGE) = FIND(I**2,ASSIGNMENT);
- STOP 21;
- STOP 22;
- END
- TERM
Ce module de programme principal utilise les tables déclarées dans le module compool et la fonction FIND définie dans le module procédure et référencée dans le module compool. Le programme est constitué du module de programme principal, du module compool DATA et du module procédure.
Directives du compilateur
Les directives du compilateur donnent des informations au compilateur sur la façon d'interpréter et de traiter le programme. La section précédente a présenté la directive compool, permettant le partage de données entre les modules. D'autres directives fournissent des informations au compilateur sur l'optimisation, le contrôle des registres, le format de liste, la compilation conditionnelle, le traçage,... :
- Pour la liaison des modules :
- |COMPOOL 'C1' (AA,BB);
- |LINKAGE FORTRAN;
- Pour l'optimisation :
- |LEFTRIGHT;
- |REARRANGE;
- |ORDER;
- |INTERFERENCE XX:YY;
- |REDUCIBLE;
- Pour le contrôle du registre :
- |BASE X'ITEM 2;
- |ISBASE X'ITEM 2;
- |DROP 2;
- Pour les options de liste :
- |LIST;
- |NOLIST;
- |EJECT;
- Pour la compilation conditionnelle :
- |BEGIN A;
- |END;
- |SKIP A;
- Divers :
- |COPY 'INSERT';
- |TRACE XX;
- |INITIALIZE;
Les macros du compilateur
La fonction de définition de JOVIAL (J73) permet la définition et l'utilisation de macros. Voici un exemple de macro simple :
- DEFINE REDALERT "CONDITION-V(RED) AND STATIONS-V(CALLED)";
Le REDALERT de définition de nom est associé à la chaîne de définition indiquée ci-dessus entre guillemets. Lorsqu'un nom de définition est indiqué dans le texte d'un programme, le compilateur remplace la chaîne de définition associée. Par exemple, considérons l'instruction suivante :
- IF REDALERT;
- BATTLEPLAN(1);
Le compilateur remplace la chaîne de définition par le nom de définition REDALERT pour obtenir l'instruction suivante :
- IF CONDITION=V(RED) AND STATIONS=V(CALLED);
- BATTLEPLAN(1);
Les macros sont pratiques car elles permettent des représentations succinctes pouvant être facilement modifiées. Elles sont puissantes car elles peuvent être utilisées de manière structurée pour développer un langage spécialisé.
La capacité de définition de JOVIAL (J73) permet également l'utilisation de paramètres dans les macros. De plus, des contrôles de liste peuvent être spécifiés dans la déclaration de définition déterminant si la macro doit être affichée sous sa forme macro, sa forme développée ou les deux.
Fonctionnalités avancées
Les fonctionnalités avancées de JOVIAL (J73) permettent au programmeur d'exercer un contrôle sur la manière dont les données sont représentées et allouées. Si le programmeur ne spécifie pas le positionnement et l'allocation, le compilateur effectue ces tâches. Dans certains cas, cependant, le positionnement doit être non standard pour permettre la communication avec un périphérique nécessitant un format particulier.
Le positionnement des données est réalisé par des tables spécifiées et l'allocation par la déclaration de recouvrement.
Caractéristiques dépendantes de l'implémentation
Chaque implémentation de JOVIAL (J73) possède des caractéristiques spéciales. Les paramètres d'implémentation de JOVIAL aident le programmeur à écrire des programmes pouvant être indépendants de la machine. Par exemple, le paramètre d'implémentation BITSINWORD donne le nombre de bits dans un mot pour une implémentation donnée.