3. Eléments du langage REXX


3.1 Composition d'un programme

3.2 Variables

3.3 Opérateurs

3.4 Divers

3.5 Instructions

3.6 Fonctions internes

3.7 Fonctions externes

retour introduction


3.1 Composition d'un programme

Tout programme commence obligatoirement par /* */ au minimum, ou mieux par un cartouche contenant sa description. Cette ligne de commentaire indique qu'il s'agit de REXX lorsque l'environnement interprète d'autres langages en parallèle (EXEC2 sous VM, CLIST sous TSO...).
Bien qu'il n'y ait pas de déclaration préalable des variables, leur récapitulatif ou initialisation placés au début aideront à la compréhension du programme.
L'instruction Exit, facultative si c'est la dernière ligne, est obligatoire pour séparer le corps principal du programme des sous routines.
Plusieurs clauses peuvent cohabiter sur une même ligne, séparées par des points virgules, mais à éviter pour plus de clarté. Celui de fin de ligne est facultatif et n'est jamais mis en pratique. Inversement une instruction peut être écrite sur plusieurs lignes, chaque partie incomplète étant terminée par une virgule pour indiquer la continuation.
Les commentaires délimités par /* */ peuvent prendre une ou plusieurs lignes ou être à la suite d'une clause.
Pour résumer et illustrer les propos précédents :

/* REXX ------------------------------------------+
! Nom du pgm, fonction                            !  
! Appel par ...                                   !
! Dépendances (programmes, services)              !
! Fichiers en entrée et sortie                    !
! Programmeur, date, modifications                !
+------------------------------------------------*/
Parse Arg aaa bbb             /* données passées */

prt  = 'PRINT32'              /* initialisations */
fic1 = 'ENTREE TXT A'
fic2 = 'SORTIE LISTING A'
i = 0; j = 0; k = 0      /* compteurs de boucles */

...			      /* corps principal */
...
Call ROUTINE1              /* appel sous routine */
...
Exit 0        /* fin du programme, code retour 0 */

ROUTINE1:            /* label de la sous routine */
...
Return xxx          /* sortie de la sous routine */

Bien qu'indifférent il est d'usage d'écrire en minuscules mais commencer les mots clés par une majuscule. Pour plus de lisibilité les noms des sous routines internes et labels sont en capitales ainsi que les noms des sous programmes et commandes extérieurs, sauf sous Linux pour ces derniers.

retour

3.2. Variables

REXX ne possède que trois variables réservées : Rc, Result et Sigl qui seront décrites par la suite. Aucune déclaration préalable n'est nécessaire, le type unique est une chaîne de caractères de longueur quelconque (ce sont bien des initialisations en tête de l'exemple ci-dessus et non pas des déclarations).

3.2.1 Variables simples

Une variable non affectée retourne simplement son nom :

Say salut           /* affiche salut à l'écran */
salut = 'Bonjour'
Say salut           /* affiche Bonjour */

Les chaînes de caractères sont encloses entre apostrophes ou guillemets :

j = 'Aujourd''hui'  /* apostrophe doublé */
j = "Aujourd'hui"   /* ou entre guillemets */

La concaténation de chaînes de caractères s'effectue de plusieurs façons :

a = 'jour'; b = 'Mes'; c = 'dames'; d = 'sieurs'
Say 'Bon'a  b||c 'et' b||d  /* répond Bonjour Mesdames et Messieurs */

'Bon'a est une concaténation implicite entre la chaîne et une variable, sans espace intermédiaire dans le résultat ; avec espace intermédiaire entre a b ; enfin b||c est une concaténation explicite entre deux variables, sans espace intermédiaire.
Ou sur plusieurs lignes en utilisant la virgule de continuation :

deb = 'Bonjour',
      'Mesdames',
      'et Messieurs'

Deux contraintes suivant la version de l'interpréteur :
- la longueur d'une chaîne littérale (par exemple 'Hello') peut être limitée ;
- idem pour la longueur d'une variable (place en mémoire).

3.2.2 Variables indicées

Outre les variables simples REXX utilise des pseudo tableaux : stems, dont les éléments sont des variables ayant un nom indicé. Cet indice peut être une variable :

fleurs.1 = 'rose'   /* initialisation */
fleurs.2 = 'résédas'
fleurs.3 = 'oeillet'
Do i = 1 To 3       /* lecture du stem */
  Say fleurs.i
End

Une bonne pratique, bien utile, consiste à mettre dans le stem 0 le nombre d'éléments le composant.

Le nombre de dimensions n'est pas limité. Comme une variable simple un élément non affecté retourne son nom :

fleurs.1.1.2 = 38   /* troisième dimension */
Say fleurs.4        /* non initialisé, répond fleurs.4 */

Stricto sensus le stem est une variable indicée à une dimension. Par extension on appelle ainsi les variables à plusieurs indices. Les stems ne sont pas des structures comme dans les PL/1 ou COBOL, on ne peut pas recopier fleurs. dans plantes. en une seule instruction, mais faire seulement une initialisation globale :

fleurs. = '0'

retour

3.3. Opérateurs

3.3.1 Arithmétiques

Les opérations arithmétiques sont effectuées lorsque le contenu des variables est numérique, sinon c'est une erreur à l'exécution :

x = 8; y = -0.6
Say x * y           /* répond -4.8 */

Pour vérifier le contenu d'une variable :

Datatype(x)         /* retourne NUM si numérique sinon CHAR */
Datatype(x,'NUM')   /* retourne 1 (vrai) ou 0 (faux) */

Les calculs prennent en compte 9 chiffres par défaut, la précision est ajustée par Numeric Digits :

Say Digits()        /* répond 9 (défaut) */
Numeric Digits 12   /* précision passée à 12 chiffres */

Outre les quatre opérations élémentaires : +, -, * et /, REXX comprend la division entière %, le reste de la division entière // et la puissance ** (l'exposant doit être un entier positif, négatif ou zéro).

3.3.2 Comparaisons

Les opérateurs de comparaison sont : égal =, plus grand que >, plus petit que <, plus grand ou égal à >=, plus petit ou égal à <=, différent de <>. Doublés : ==, >>, << signifient strictement égal, strictement plus grand que, etc. Le résultat d'une comparaison est 1 pour vrai et 0 pour faux :

'a '  =  'a'        /* répond vrai, REXX ignore le blanc */
'a '  == 'a'        /* répond faux */

La comparaison de nombres s'effectue suivant la précision définie. Il sera plus avantageux de forcer la comparaison de grands nombres en mode caractère, à condition qu'ils aient strictement le même format :

a = 12356789012; b = 123456789013	
If '*'a < '*'b Then ...

sinon en mode numérique la comparaison précédente serait limitée à 123456789 (précision par défaut) et a et b considérés égaux.

3.3.3 Logiques

Les opérateurs logiques sont et &, ou |, ou exclusif &&, et le préfixe non logique \ (barre de fraction inversée).
Les opérations d'une instruction sont effectuées de gauche à droite, avec la préséance : préfixe (+, -, \), puissance, multiplication et division, addition et soustraction, comparaisons et enfin opérateurs logiques.
En principe la multiplication est plus performante que la division, la comparaison "inférieur à" plus performante que "supérieur à".

retour

3.4 Divers

En EBCDIC (grands systèmes) l'ordre croissant de codage des caractères est lettres minuscules, majuscules puis chiffres. En ASCII c'est l'inverse : chiffres, majuscules puis minuscules.
En EBCDIC, pour les codes pages européens, l'opérateur ou s'écrit ! (point d'exclamation), la concaténation !! (deux points d'exclamation). En ASCII ou et la concaténation utilisent une et deux barres verticales (ASCII 124).

Outre la notation décimale (ou sous forme de puissance si la représentation du nombre dépasse la précision définie) les nombres peuvent être exprimés sous forme de puissance multiple de 3 :

Numeric Form 'ENGINEERING' 
Say 88889 * 2       /* répond 178E+3 */

Enfin REXX reconnaît les représentations binaire et hexadécimale :

'00011111'b         /* 31 en binaire */
'001F'x	            /* 31 en hexadécimal */

Attention aux concaténations provoquant des erreurs de syntaxe :

'*'x	            /* interprétée comme chaîne hexadécimale, écrire : */
'*'||x
'/*' 	            /* début de commentaire, écrire : */
'/'||'*'

retour

3.5 Instructions

Les instructions sont présentées ci dessous par thème, la liste des mots clés est généralement détaillée dans les documentation et aide en ligne fournies avec les logiciels.

3.5.1 Générales

Address

Précise à quel environnement REXX doit soumettre les commandes système (voir le paragraphe 4.2.1), par exemple :

Address 'TSO'
Say Address()       /* répond TSO */
Drop

Annule l'assignation d'une ou plusieurs variables ; dans le cas d'un stem c'est l'ensemble de la structure qui redevient non initialisée :

Drop salut          /* salut n'est plus initialisée */
Drop table.         /* toutes les variables indicées dont le nom commence par table.
                       ne sont plus initialisées */

Ne pas confondre avec vider le contenu d'une variable, c'est à dire lui affecter une chaîne de longueur nulle (mais le caractère '00'x a une longueur de 1) :

salut = ''

L'instruction Drop détruira les tableaux ou chaînes de caractères volumineux devenus inutiles dans le flot d'exécution du programme et libérera ainsi de l'espace mémoire.

Exit

Termine le programme et transmet éventuellement un code retour (nombre entier) à l'appelant.

Interpret

Demande d'exécuter une expression, pour autant que sa syntaxe soit correcte. A éviter en général et à proscrire si le programme doit être compilé.

calcul = '8*3'
Interpret 'Say' calcul	/* traduit en : Say 8*3 et répond 24 */

ou à l'aide de la fonction Value() :

Say Value(calcul)
Numeric

Comme expliqué au paragraphe 3.3.1 Numeric Digits x modifie la précision des calculs, Numeric Form la représentation des nombres. La troisième option, Numeric Fuzz x, réduit de x chiffres la précision des comparaisons (0 par défaut), à éviter.

Pull, Push, Queue

Ce sont les instructions de manipulation des données dans la pile. Son utilisation sera vue en détail par la suite au paragraphe 4.1. Pull lit une ligne dans la pile ou attend une entrée clavier ci celle-ci est vide, Push ajoute une ligne en position dernière entrée - première sortie (LIFO) alors que Queue place la ligne suivant dernière entrée - dernière sortie dans la pile (ou première entrée - première sortie FIFO). Pour les nostalgiques, l'inversion du contenu de deux variables par la pile :

a = 3               /* MOV  AH, 3h */
b = 6               /* MOV  AL, 6h */
Push a              /* PUSH AH     */
Push b              /* PUSH AL     */
Pull a              /* POP  AH     */
Pull b              /* POP  AL     */
/* ou bien en FIFO : */
Queue b
Queue a
Pull  a
Pull  b

Mais on écrira simplement, si les deux chaînes à échanger ne contiennent pas de blanc :

Parse Value a b With b a
Pull, Say

Pour poser une question et attendre la réponse (saisie clavier validée par la touche Entrée) :

Say 'D''accord (O/N) ?'
Pull rep .
Signal

C'est le "GOTO" tant décrié, mais pourquoi pas si le débranchement au label spécifié est sans retour :

If ... Then Signal FIN 16
...
FIN:
Arg retc
Say 'Erreur fatale ...'
Exit retc

Signal est aussi utilisé pour l'interception et le traitement des erreurs d'exécution, voir § 4.5.

3.5.2 Structures conditionnelles

If - Then, Else, Nop

C'est la structure conditionnelle classique, avec possibilité d'imbrication :

If x > y | x > z Then ...
Else If ....
  Else ...

et utilisation de blocs d'instructions :

If x > y Then
  Do
    ...
  End
Else
  Do
    ...
  End

Les clauses If... Then et Else sont placées sur deux lignes ou sinon obligatoirement séparées par un point virgule. Si une condition n'est suivie d'aucun traitement préciser l'instruction Nop qui ne fait rien.

Select

La structure Select traite les choix multiples :

Select
  When reponse = 'YES'   Then ...
  When reponse = 'NO'    Then ...
  When reponse = 'MAYBE' Then
    Do
      ...
    End 
  Otherwise
End /* Select */

Les instructions dépendant de la première condition vraie rencontrée sont exécutées, les tests suivants abandonnés ; contrairement au langage C (structure "switch case") il n'est pas nécessaire de spécifier un "break" à chaque cas. Si aucune condition n'est remplie il faut obligatoirement une clause Otherwise, même sans instruction précisée, sinon c'est une erreur à l'exécution.

3.5.3 Boucles répétitives

Do, End
Do ; ... ; End

est un bloc d'instructions utilisé dans les structures conditionnelles.

Do n ; ... ; End

est la forme de boucle la plus simple. Une clause If... Then peut être écrite ainsi, sans gain notable de performance :

Do (a > b); ... ; End  /* si vrai équivaut à Do 1 */

Une autre forme, dite contrôlée, est :

Do i = j To k By x ; ... ; End

ou j, k et x peuvent être positifs ou négatifs, entiers ou décimaux. Si l'instruction By est omise l'incrément est de 1 par défaut. Enfin le nombre d'itérations peut être fixé :

Do i = j To k By x For y; ... ; End
Iterate, Leave

Le déroulement d'une boucle est altérée par les instructions Iterate, passe à l'itération suivante, ou Leave, quitte la boucle, sans exécuter les clauses restantes :

Do i = 1 To 5
  If i = 3 Then Iterate	 /* si i = 3 on passe */
  Say i                  /* affichera 1 2 4 5 */
End
Do While, Do Until, Do Forever

La condition While est testée avant chaque itération. Elles se succèdent tant que la condition est vraie :

Do While i < 6; ...; End

La condition Until est testée après chaque itération. Elles se succèdent jusqu'à ce que la condition soit réalisée, les instructions dans la boucle sont exécutées au moins une fois :

Do Until i > 5; ...; End

Enfin la boucle perpétuelle Forever comporte obligatoirement une sortie par l'instruction Leave :

Do Forever
  ...
  If ... Then Leave
End

Les deux types, contrôle et condition peuvent être associés :

 If ... Then Do While ... 

3.5.4 Parsing

L'instruction la plus puissante et la plus riche du langage, le parsing, découpe une chaîne de caractères suivant différents critères. La forme la plus simple est :

Parse Value 'chien chat souris' With x y z

La séparation s'effectue par défaut à chaque espace, ainsi la variable x contiendra 'chien', y 'chat' et z 'souris'. C'est une alternative élégante à l'initialisation classique de variables :

Parse Value '1 2 3 4' With a b c d  /* a=1, b=2, etc */

Si la chaîne est contenue dans une variable la syntaxe devient (le mot clé With n'est précisé qu'avec Parse Value, sinon c'est une erreur de syntaxe) :

animaux = 'chien chat souris'
Parse Var animaux x y z

Quelques variations :

Parse Var animaux x y   /* x contiendra 'chien', y le reste soit 'chat souris'  */

animaux = 'chien chat'	/* trois variables mais deux éléments, */
Parse Var animaux x y z	/* z sera vide */

Parse Var animaux . y .	/* seul le deuxième élément est récupéré dans y */

Le découpage par les espaces est de loin le plus fréquent, mais peuvent suivre d'autres séparateurs :

Parse Value Date('E') With jour '/' mois '/' annee

la fonction Date() retourne une chaîne , il faut donc bien employer la syntaxe Parse Value. Si le séparateur est défini dans une variable celle-ci est mentionnée entre parenthèses :

sep = ';'
Parse Var a b (sep) c

La dernière méthode précise les positions dans la chaîne initiale, en absolu ou en relatif, dans l'exemple 7ème position puis + 6 caractères :

chaine = 'AlbertAlfredAlexis'
Parse Var chaine x 7 y +6 z

Cette syntaxe remplace efficacement une succession laborieuse de "substrings" lors de la lecture d'enregistrements de fichiers par exemple.
Plusieurs méthodes de découpage peuvent être employés dans une même clause. Pour éliminer d'éventuels blancs restants on ajoute un point :

Parse Var chaine x ',' y z .

Outre le découpage de chaînes de caractères :

Parse Arg aa bb	    /* récupère les données passées en argument ou bien : */
Parse Arg aa , bb   /* paramètres séparés par une virgule */

Parse Pull x y z    /* lit une ligne dans la pile et la découpe en x, y, z ;
                       si la pile est vide attend une entrée au clavier */

Parse Value Linein(fichier) With x y z
/* lit une ligne du fichier et la découpe en x, y, z, WinX et Linux seulement */
	
Parse Version ver   /* donne la version de l'interpréteur REXX */

Pour convertir en majuscules on précisera Upper, par exemple: Parse Upper Var. Arg est la forme abrégée de Parse Upper Arg, Pull l'abréviation de Parse Upper Pull, à proscrire sous Linux et autres Unix ! Pour convertir en minuscules c'est Parse Lower...

Et enfin pour le nom de l'environnement, le mode d'appel et le nom du fichier source :

Parse Source env
/* env = 'WindowsNT COMMAND C:\Program Files\Objrexx\rexxtry.rex' */
  ('COMMAND' : appelé comme programme, comme 'SUBROUTINE' ou 'FUNCTION') */

3.5.5 Appel de sous routines et programmes

Call, Return

L'instruction Call appelle une sous routine interne ou un autre programme REXX (recherche effectuée dans cet ordre), en passant éventuellement des données en argument. Les apostrophes ou guillemets sont importants dans la syntaxe :

Call UTIL1 arg      /* routine interne ou programme REXX externe */
Say Result          /* chaîne de caractères en retour */

Call 'UTIL2' arg    /* programme REXX externe uniquement */
Say Result          /* chaîne de caractères en retour */

Pour appeler tout programme externe, REXX ou autre :

"CALL UTIL3" arg    /* ici CALL est une commande système */
Say Rc              /* uniquement code retour dans Rc */

"UTIL3" arg         /* appel implicite */
Say Rc              /* uniquement code retour dans Rc */

Sous WinX et Linux mentionner le nom complet du programme extérieur si son chemin n'est pas défini dans la variable d'environnement "PATH".
On ne peut passer en argument que des variables simples ou indicées mais pas de stem entier.

Une sous routine interne commence par son label : son nom suivi de deux points, et se termine par l'instruction Return. Cette dernière renvoie une chaîne de caractères lisibles dans la variable Result, par exemple : Return 'OK'. Il en est de même pour un programme extérieur appelé par l'instruction Call et terminé par l'instruction Return. La deuxième forme d'appel d'une sous routine est comme une fonction, voir le paragraphe 3.6.

D'une manière générale l'instruction rencontrée Return interrompt le traitement et provoque le retour à l'appelant. Si elle est dans le corps du programme principal celui-ci se termine, mais ne peut retourner qu'un code numérique à l'environnement ; utiliser plutôt Exit dans ce cas. En programmation structurée les corps principal et sous routines n'ont qu'un seul point d'entrée et un seul point de sortie.

Une sous routine peut être exécutée de façon récursive, c'est à dire qu'elle s'appelle elle même, mais sauf cas très particulier cette méthode doit être évitée.

La deuxième syntaxe de l'instruction Call permet l'interception et le traitement d'événements, voir le paragraphe 4.5.

Procedure, Expose

Sans spécification particulière les variables sont communes (globales) au programme et à ses sous routines. L'instruction Procedure placée derrière le label fait que toutes les manipulations de variables à l'intérieur d'une routine sont oubliées (variables locales) lors du retour au programme appelant, même si elles portaient les mêmes noms.

x = 4; y = 8        /* initialisation de x et y */
Call MAROUTINE      /* appel sous routine */
Say x y z           /* x et y valent toujours 4 et 8 */ 
...                 /* et z n'est pas connue */
Exit

MAROUTINE:
Procedure
x = 'aa'; y = 'bb'; z = 'cc'	
Return

Pour que la variable z de l'exemple précédent soit conservée au retour préciser :

Procedure Expose z

L'instruction ajoutée Expose, suivie du nom des variables, y compris les stems, indique que celles-ci doivent être conservées lors du retour au programme principal.
Les variables d'un sous programme externe ne sont pas reconnues par l'appelant.

retour

3.6. Fonctions internes

REXX possède une collection très riche de fonctions, présentées ici par thème. Elles sont appelées suivant deux modes :

jour = Date('E')    /* comme une fonction */	

Call Date 'E'       /* ou comme une sous routine, */
jour = Result       /* son résultat lu dans Result */

L'option de la fonction, ici 'E', placée entre apostrophes évite l'interprétation intempestive d'une éventuelle variable E ou e.
Une sous routine s'appelle aussi sous forme de fonction, de même qu'un sous programme extérieur. L'interpréteur recherche dans l'ordre parmi les sous routines du programme, les fonctions internes et enfin les programmes externes (voir l'instruction Call, § 3.5.1). Les fonctions peuvent être imbriquées comme le montrent certains exemples ci-après.

3.6.1 Générales

Address()

Indique le nom de l'environnement auquel sont soumises les commandes système (voir § 3.5 et § 4.2).

Arg(n)

Retourne le n ième argument passé (voir Parse Arg ), ou leur nombre si n est omis, à condition que ceux-ci soient séparés par des virgules :

Call MAROUTINE 'a', , 'c'

MAROUTINE:
Say Arg()           /* répond 3 (éléments) */
Say Arg(2)          /* vide */
Say Arg(3)          /* répond 'c' */
Datatype(a,t)

Détermine le type de la variable a, suivant la syntaxe :

Say Datatype(a)        /* répond NUM ou CHAR suivant a */
Say Datatype(a,'NUM')  /* répond 1 si vrai sinon 0 */
Say Datatype(a,'W'),   /* nombre entier ? */

D'autres options testent si a est une chaîne alphanumérique ('A'), en majuscules ('U'), minuscules ('L'), mixte ('M') ou un nombre binaire ('B') ou hexadécimal ('X').

Errortext(n)
Renvoie le message associé au code erreur n, voir le paragraphe 4.5.1.
Queued()
Nombre de lignes restant à lire dans la pile, voir le paragraphe 4.1.
Sourceline(n)

Si n spécifié retourne la n ième ligne du programme (n inférieur ou égal au nombre de lignes), sinon son nombre de lignes.

Symbol(a)

Précise le statut de a :

a = 4
Symbol('a')         /* retourne 'VAR' (variable) */
Symbol(a)           /* retourne 'LIT', a interprétée = 4 */
Symbol('b')         /* retourne 'LIT', b non initialisée */
Symbol(b)           /* même résultat */
Symbol('*')         /* répond 'BAD', symbole invalide */
Trace()

Pour suivre le déroulement à l'écran de tout ou partie d'un programme lors de sa mise au point :

Trace('A')          /* "trace all", début du suivi */
...
Trace('O')          /* "trace off", arrêt */

All est la plus complète des options de Trace(). Veiller à limiter le nombre d'itérations des boucles sinon gare à un défilé sans fin à l'écran !

Value(a)

Suivant l'utilisation d'apostrophes :

Value('a')          /* retourne la valeur de la variable a */
a = 'b'; b = 5
Value(a)            /* interprète a  et répond 5
                       ou erreur de syntaxe si l'interprétation n'est pas possible */
Var('a')

Retourne 1 si a est un nom de variable ou bien 0. Le nom de la variable doit être entre apostrophes sinon elle sera interprétée et la réponse sera 0.

3.6.2 Numériques

Abs(n)

Valeur absolue de n.

Bitand(a,b,c), Bitor(a,b,c), Bitxor(a,b,c)

Opérations logiques respectivement et, ou, ou exclusif, bit par bit, entre les chaînes a et b. La variable c facultative complète la chaîne la plus courte sur sa droite. Par exemple le complément d'une chaîne binaire :

Say C2x(Bitxor('1100'b,'1111'b)  /* '0011'b */
B2x(b), X2b(h)

Conversion d'un nombre binaire en hexadécimal et réciproquement. La conversion directe binaire - décimal n'existant pas on utilise deux fonctions :

Say  X2d(B2x('11111111'))  /* 255 */
C2d(a), C2x(a), D2c(n), X2c(a)

Conversion de caractère à nombre décimal ou hexadécimal et inversement.

/* Pour retrouver le code ASCII d'un caractère : */
C2x('1')            /* 31 en hexadécimal */
C2d('1')            /* 49 en décimal */

/* Pour convertir un nombre entier du format "packed decimal" en décimal : */
a = 'R4]'           /* 535
                       24D */ 
a = C2x(a)			/* '52345D' */
If Right(a,1) = 'C' Then s = 1	/* test signe */
Else s = -1			/* 'B' ou 'D' si < 0 */
n = Left(a,Length(a)-1) * s	/* n = -52345 */

/* et inversement de décimal à "packed decimal" : */
If Sign(n) > 0 Then s = 'C'
Else s = 'D'
a = X2c(Abs(n / 1)||s)  /* n / 1 élimine les zéros non significatifs */
D2x(n,l), X2d(h,l)

Conversion de décimal à hexadécimal et réciproquement, longueur l facultative. Pour additionner deux nombres hexadécimaux :

D2x(X2d('20') + X2d('10'))	/* '30'x */
Digits()

Donne le nombre de chiffres pris en compte dans les calculs ; défaut 9, voir § 3.3.1.

Form()

Définit la représentation des nombres : SCIENTIFIC ou ENGINEERING, voir § 3.3.1.

Format(n,a,b,x,y)

Fixe la représentation du nombre n, a chiffres partie entière, b décimales après :

n = 123.45678
Format(n,6)         /* '   123.45678' */
Format(n,,1)        /* '123.5', arrondi à 1 décimale */

Right(Format(n,,2),9,'*')||'FRF' /* '***123.46FRF' */

Format(n,,,,0)      /* '1.2345678E+2', force la notation 
                        exponentielle (attention E0 est omis) */

Format(123E10,,,0)  /* '1230000000000', force la notation décimale) */

/* Pour éliminer le préfixe +, les zéros précédents ou suivants : */
+004.00 + 0         /* donne 4.00 */
+004.100 / 1        /* donne 4.1  */

/* Quel que soit n : */
Parse Value Format(n / 1,,,0) With e '.' d
e = Length(e) - (e < 0)  /* nbre de chiffres partie entière sans le signe */
d = Length(d)               /* nbre chiffres partie décimale */
Fuzz()

Nombre de chiffres ignorés lors des comparaisons ; défaut 0, voir § 3.3.1.

Max(x,y,z), Min(x,y,z)

Maximum, minimum d'une suite de nombres.

Random(x,y)

Donne un nombre aléatoire compris entre x et y (défaut 0 à 999 si non précisé). Le nombre maximum retourné étant 99999, effectuer la concaténation de plusieurs nombres aléatoires pour obtenir plus grand.

Sign(n)

Retourne -1 si n négatif, zéro si nul ou 1 si positif.

Trunc(n,d)

Tronque n à d décimales ou à sa partie entière par défaut, alors que Format() arrondit. Pour l'entier algébrique :

n = Trunc(n) + (n > 0)  /* par excès */
n = Trunc(n) - (n < 0)  /* par défaut */

3.6.3 Date et heure

Date()

Indique la date système en différents formats dont :

Date('E')           '04/02/03'
Date('S')           '20030204'
Date('D')           '35'		(rang dans l'année)			  
Date('B')           '730756'	(nombre de jours depuis le 1/01/0001)

Attention, l'origine de Date('B') peut varier d'une version à l'autre et différer de celle prise par un autre logiciel.
Certaines versions de REXX proposent des fonctions de conversion de format et de calcul entre dates (sinon voir § 4.7).

Time()

Donne par défaut l'heure système, sur 24h, sous la forme 'hh:mm:ss'. Plusieurs options et suivant la version possibilité de conversion et calcul de durées. En particulier, pour chronométrer :

Say Time('E')	    /* initialisation, t0 = 0 */
Say Time('E')	    /* temps écoulé en secondes depuis t0 */
Say Time('R')	    /* temps écoulé en secondes depuis t0 et remise à zéro du chronomètre */

3.6.4 Chaînes de caractères

Abbrev(a,b,n)

Vérifie si b est une abréviation de a. Test effectué sur n caractères si spécifié :

Abbrev('PRINT','PRI')	/* retourne 1, vrai */
Abbrev('PRINT','PRI',4)	/* retourne 0, faux */
Center(a,n,c)

Produit une chaîne de n caractères comprenant a centrée à l'intérieur. Le caractère de complément est spécifié dans c sinon c'est l'espace par défaut.

Changestr(b,a,c)

Rend la chaîne de caractères a dans laquelle les caractères b trouvés sont changés par ceux dans c ; voir aussi la fonction Translate().

Compare(a,b,c)

Compare les chaînes a et b, retourne 0 si égales, sinon la position du premier caractère différent ; c précise un caractère de complément sur la droite de la chaîne la plus courte sinon l'espace est utilisé par défaut.

Copies(a,n)

Reproduit n fois la chaîne a.

Countstr(b,a)

Compte les occurences des caractères b dans la chaîne a. A défaut de cette fonction la méthode de comptage consiste à faire la différence de longueur des chaînes avant et après suppression des caractères b, voir la fonction Translate().

Delstr(a,x,y)

Retourne a tronquée avant x, ou élimine y caractères au milieu de la chaîne à partir de x (inverse du substring ) :

Delstr('abcdef',3)    /* retourne 'ab' */
Delstr('abcdef',3,2)  /* retourne 'abef' */
Insert(b,a,x,y,c)

Insère b dans a après le x ième caractère (ou au début si non spécifié), b étant tronquée à la longueur y ou complétée à cette longueur avec le caractère c (espace par défaut).

Left(a,x,c), Right(a,x,c)

Prélève les x (entier positif ou zéro) caractères à gauche ou à droite de a, complétés si besoin par le caractère c (ou espace par défaut) respectivement à la suite ou avant.

Length(a)

Compte le nombre de caractères dans a.

Overlay(b,a,x,y,c)

Remplace les caractères de a par ceux de b, à partir de la x ième postion, tronqués à une longueur y ou complétés si besoin par le caractère c.

Overlay('zz','abcdef')          /* 'zzcdef' */
Overlay('zz','abcdef',4)        /* 'abczzf' */
Overlay('zz','abcdef',2,3,'?')	/* 'azz?ef' */
Pos(b,a,x), Lastpos(b,a,x)

Recherche la chaîne b dans a, à partir du x ième caractère. Pos() retourne la première position trouvée, Lastpos() la dernière, sinon 0 :

Pos('ab','abababab',4)	/* 5 */
Laspos('ab','abababab')	/* 7 */
Reverse(a)

Renverse l'ordre des caractères d'une chaîne : 'abcd' devient 'dcba'.

Space(a,0)

Pour supprimer les blancs dans une chaîne :

Space('ab  cd',0)          /* 'abcd', blancs supprimés */

Et pour supprimer un caractère dans la chaîne :

Changestr('abcd",'b',' ')  /* 'a cd' */
Space('a cd', 0)           /* 'acd' */
Strip(a,o,c)

Supprime le caractère c (espace si non spécifié), en début ou fin (mais pas au milieu) de la chaîne a suivant l'option o :

Strip(' ab cd ','L')	 /* supprime le blanc précédent*/
Strip('  ab cd  ')       /* les précédents et suivants */
Strip('123000','T','0')  /* les '0' suivants */
Substr(a,x,y,c)

Substring : extrait les y caractères de a à partir du x ième, complétés si besoin par le caractère c (espace par défaut) ; si y non précisé le reste de a à partir de x.

Translate(a,r,t,d)

Remplace dans a les caractères mentionnés dans t par ceux dans r et ceux qui ne sont pas mentionnés par d (blanc par défaut) ; plusieurs usages plus ou moins complexes :

/* Conversion en majuscules et inversement en minuscules : */
Translate('abcd')                                  /* en majuscules */
Translate('ABCD',Xrange('a','z'),Xrange('A','Z'))  /* en minuscules ou, plus simple : */ 
Parse Lower Var maj min

/* Echange de caractères : */
Translate('ABCD','23','BC')   /* 'A23D' */
Translate('ABCD',,'AC','.')   /* '.B.D' */
Translate('abababc',' ','b')  /* 'a a a c' */

/* Réordonner des caractères : */
Translate('1234','ABCD','1342')	 /* 'ADBC' */
Verify(a,r,o,x)

Retourne 0 si tous les caractères de a sont dans la chaîne de référence r, sinon la position du premier étranger. Si l'option o est Match (Nomatch par défaut), retourne la position dans a du premier caractère concordant. Le test démarre au x ième caractère si précisé :

Verify('aabb','abcdefg')        /* retourne 0 */
Verify('aabb','abcdefg','M')    /* retourne 1 */
Verify('aabb','abcderg','M',4)	/* retourne 4 */
Xrange(d,f)

Génère la chaîne des octets compris entre d et f :

Xrange('c','h')      /* 'cdefgh' */
Xrange('01'x,'05'x)  /* '0102030405'x */

3.6.5 Listes de mots

On appelle ainsi des chaînes constituées de groupes de caractères, les mots, séparés par des espaces :

noms = 'Pierre Paul et Jacques'

Les fonctions suivantes sont basées sur le parsing suivant les blancs.

Delword(a,x,n)

Elimine de la liste a, à partir du x ième mot, les n (entier positif ou zéro) mots ou tous si n non spécifié. C'est l'inverse de la fonction Subword() décrite plus loin.

Space(a,n,c)

Sépare les mots par n caractères c (défauts respectifs : un, espace) :

Space('ab  cd',0)        /* 'abcd', blancs supprimés */
Space('abc  def',2,'+')	 /* 'abc++def' */
Subword(a,x,n)

Extrait de a, à partir du x ième mot, les n mots, ou tous si n non spécifié.

Word(a,n)

Retourne le n ième mot de a. Pour constituer une liste de référence :

jours = 'lundi mardi mercredi jeudi vendredi samedi dimanche'
jour  = Word(jours,(n//7 + 1))
Wordlength(a,n)

Donne le nombre de caractères composant le n ième mot dans a.

Wordpos(b,a,n)

Recherche le mot b dans la liste a, à partir du n ième :

 
Wordpos('et',noms)         /* répond 3 */
Wordpos('ou',noms)         /* répond 0 */
Wordpos('Jacques',noms,3)  /* répond 4 */
Words(a)

Nombre de mots dans la liste a.

3.6.6 Spécifiques aux environnements

Sous WinX et Linux les fichiers sont accédés à l'aide de fonctions particulières qui seront décrites au chapitre 4. En outre la fonction Filespec() extrait d'un nom complet de fichier le disque (sous DOS), le chemin et le nom.

Sous les grands systèmes les fichiers sont accédés par la commande "EXECIO", expliquée au chapitre 4. La version de REXX sous TSO possède des fonctions propres :
- Listdsi(), Sysdsn() : renseignements sur les fichiers (voir § 4.4.1),
- Outtrap() : récupére la réponse d'une commande système (voir § 4.2.2),
- Sysvar() : données système,
- Userid() : identité de l'utilisateur.

retour

3.7. Fonctions externes

3.7.1 Extensions de l'interpréteur

Les interpréteurs IBM proposent des bibliothèques de fonctions complémentaires, contenues en fichiers ".dll" sous WinX et ".so" sous Linux.
On charge au choix la bibliothèque entière ou seulement les fonctions désirées. Celles-ci s'utilisent ensuite comme les fonctions internes.

Chargement de la bibliothèque entière
If RxFuncQuery('SysLoadFuncs') Then Do
  retc = RxFuncAdd('SysLoadFuncs','rexxutil','SysLoadFuncs')
  If retc = 0 Then Call SysLoadFuncs
  Else Say 'ERREUR...'
End

la première clause teste si SysLoadfuncs est présente (retourne 0) ou non (1). Si non, chargée puis invoquée ensuite celle-ci ajoute toutes les fonctions de la bibliothèque rexxutil. Le chemin d'accès de cette dernière est soit défini dans le 'PATH', soit son nom complet est précisé.
Ce chargement n'est effectué qu'une fois pour toutes les fenêtres de commandes ouvertes. Pour retirer la bibliothèque, fermer toutes ces fenêtres ou :

Call SysDropFuncs   /* retourne 0 si OK */
Chargement individuel

On ne charge que les fonctions désirées, une à une (soit leur nom est répété, soit elles sont rebaptisées et seront utilisées sous ce nouveau nom) :

Call RxFuncAdd 'SysGetKey', 'rexxutil', 'SysGetKey'
...
x = SysGetKey()
...
Call RxFuncDrop 'SysGetKey'  /* pour la retirer */

3.7.2 Modules externes

D'autres interpréteurs mettent à disposition ces fonctions en modules individuels interfaçables (résultat dans Result ) :

Call 'RXCLS'        /* si PATH défini, sinon préciser le chemin complet */

Voir les conventions d'interface dans la documentation fournie pour développer des fonctions personnalisées suivant ce principe.

Enfin on utilisera simplement des programmes ou commandes système qui ne retourneront qu'un code numérique, voir le paragraphe 4.2.



© G. Navarre, 2003 - 2006, màj 26/04/2021.

retour