Sviluppo

Corso di programmazione in REXX - Lezione 3 - nozioni di base

Alessandro Cantatore
 

Nota: i sorgenti descritti in questo numero sono stati raccolti nel file rxsource.zip (915 byte).

Le espressioni
Un'espressione rappresenta una serie di informazioni che si vogliono far valutare dall'interprete del REXX. Può essere la semplice somma di due numeri o tanto complessa come si vuole.
Il processo di lettura di un'espressione con la conseguente produzione di un risultato viene chiamato valutazione dell'epressione.
Le espressioni sono costituite da termini, cioè i dati che devono essere elaborati, e operatori, che rappresentano i calcoli da effettuare sui relativi termini.

Alcuni esempi di espressioni REXX:

/* espressioni aritmetiche              */
say 3 + 2           /* mostra "5"       */
say 3 * 2           /* mostra "6"       */
say 3 2             /* mostra "3 2"     */
say 3||2            /* mostra "32"      */

/* stringhe letterali                   */
say "box" "car"     /* mostra "box car" */
say "box""car"      /* mostra "box"car" */
say "box"||"car"    /* mostra "boxcar"  */

/* alcune variabili                     */
x = 6
y = 7
say x + y           /* mostra "13"      */
x = x + y
say x               /* mostra "13"      */

I termini
I termini di un'espressione sono i pezzi individuali di informazione su cui si vuol far lavorare l'interprete REXX. I tipi di termini che costituiscono un'espressione sono:

Numeri stringhe che il REXX può calcolare. Vengono riconosciuti dal REXX come valori costanti. Per esempio:
25     3.14159     -6     1989
Stringhe letterali qualsiasi cosa compresa in una coppia di virgolette semplici o doppie:
"mercoledì"   "C:\PROGRAMMI"   "10 luglio 1997"
Variabili simboli usati per dati che possono cambiare. Quando una variabile viene usata in un'espressione, il REXX la valuta usandone il valore corrispondente:
data = 30                /* memorizza il numero 30        */
                         /* nella variabile DATA          */

mese = marzo             /* memorizza la stringa "marzo"  */
                         /* nella variabile MESE          */

say data mese            /* mostra "30 marzo"             */
Chiamate di funzioni provocano speciali elaborazioni dei dati.
Alcune di esse sono incluse nell'interprete del REXX, altre possono essere create dall'utente in REXX o in altri linguaggi di programmazione. Quando l'interprete REXX incontra una chiamata di funzione, esegue i relativi calcoli, riportando poi, come termine dell'espressione, il risultato di tali calcoli.
Per esempio:
say time()               /* mostra l'ora corrente         */

say substr("REXX", 2, 1) /* mostra "E", cioè un carattere */
                         /* a partire dal secondo         */

I principali operatori
Gli operatori più comuni sono quelli aritmetici (di somma, sottrazione, moltiplicazione e divisione) e quelli di concatenazione.

Alcuni esempi di operatori aritmetici sono:

/* addizione, sottrazione e moltiplicazione  */
say 14 + 5               /* mostra "19"      */
say 14 - 5               /* mostra "9"       */
say 14 * 5               /* mostra "70"      */

/* divisione normale                         */
say 14 / 5               /* mostra "2.8"     */

/* mostra solo la parte intera del risultato */
say 14 % 5               /* mostra "2"       */

/* mostra solo il resto della divisione      */
say 14 // 5              /* mostra "4"       */

Nota: l'uso del REXX per i calcoli matematici verrà approfondito in una delle prossime lezioni.

Gli operatori di concatenazione servono ad unire una o più stringhe:

  • tramite uno spazio se i termini dell'espressione sono separati da uno o più spazi:
    say "vettura"    "lenta"     /* mostra "vettura lenta" */
    aggettivo = "lenta"
    say "vettura" aggettivo      /* mostra "vettura lenta" */
    say "vettura"    aggettivo   /* mostra "vettura lenta" */
    
  • consecutivamente, tramite l'omissione di spazi, se il REXX è in grado di riconoscere i singoli termini:
    aggettivo = "lenta"
    say "vettura"aggettivo       /* mostra "vetturalenta"      */
    nome = "vettura"
    say nomeaggettivo            /* mostra "NOMEAGGETTIVO"     */
                                 /* perché il REXX non è in    */
                                 /* grado di riconoscere i due */
                                 /* termini                    */
    say nome""aggettivo          /* mostra "vetturalenta"      */
                                 /* perché le virgolette       */
                                 /* permettono al REXX di      */
                                 /* riconoscere i termini      */
    
  • consecutivamente, tramite l'uso dell'operatore doppia barra verticale ("||"):
    aggettivo = "lenta"
    say "vettura" || aggettivo   /* mostra "vetturalenta"      */
    nome = "vettura"
    say nome || aggettivo        /* mostra "vetturalenta"      */
    say nome    ||   aggettivo   /* mostra "vetturalenta"      */
    say 4 5                      /* mostra "4 5"               */
    say 4 || 5                   /* mostra "45"                */
    say (4||5) / 3               /* mostra "15"                */
                                 /* le parentesi sono usate per*/
                                 /* forzare la concatenazione  */
                                 /* prima della divisione      */
    

Precedenza degli operatori
Come si vede nell'ultimo esempio la concatenazione è valida anche con le stringhe numeriche.
Nell'espressione: " say (4||5) / 3" le parentesi sono necessarie per forzare il REXX a concatenare le due cifre 4 e 5 prima di dividere il risultato della concatenazione per 3.
Senza le parentesi sarebbe stata eseguita prima la divisione 5/3 il cui risultato 41.66666667 verrebbe poi concatenato a 4 mostrando così sullo schermo: 41.66666667.

Il REXX dà precedenza alla divisione rispetto alla concatenazione. Infatti il REXX prevede un insieme di regole che definiscono l'ordine in cui le varie operazioni di un'espressione devono essere eseguite.

Come regola di base l'espressione viene valutata da sinistra a destra, ma l'ordine di elaborazione viene modificato dalla presenza di parentesi e dalla precedenza degli operatori. Cioè alcune operazioni acquisiscono una maggiore priorità e vengono elaborate prima di altre indipendentemente dall'ordine di apparizione nell'espressione. Per esempio la moltiplicazione o la divisione hanno maggior priorità di somma e sottrazione e queste ultime precedono a loro volta l'operatore di concatenazione.

Per cambiare l'ordine di valutazione, per esempio per dividere una somma, è necessario racchiudere le operazioni con minor priorità tra parentesi.
Le parentesi hanno anche spesso il vantaggio di aumentare la comprensibilità del programma.

Le funzioni
Per operazioni più complesse il REXX include un set di funzioni.
Una funzione restituisce sempre un valore, rappresentato nell'espressione da un simbolo detto chiamata di funzione. Tutte le chiamate di funzione consistono di un nome seguito da parentesi.
Non ci deve essere alcuno spazio tra il nome della funzione e la parentesi altrimenti l'espressione non viene considerata valida! Un esempio di chiamata di funzione:

say length("parola")    /* mostra sullo schermo la lunghezza */
                        /* dell'argomento "parola"           */
Il dato su cui si vuol fare operare la funzione viene detto argomento o parametro della funzione.
Nell'esempio precedente l'argomento è la stringa letterale "parola" ed il valore prodotto dalla funzione è il suo valore di ritorno.
Il valore di ritorno dipende dall'argomento introdotto. Nel nostro caso il valore restituito è "6" cioè il numero di caratteri che compongono l'argomento "parola".
Nel caso di un argomento differente, per esempio:
say lenght("argomento più lungo") /* mostra sullo schermo la lunghezza    */
                                  /* dell'argomento "argomento più lungo" */
sullo schermo verrà mostrato "19.

L'argomento di una funzione può essere esso stesso un'espressione.
Per esempio la funzione ABS() restituisce il valore assoluto (positivo) di un numero. Se l'argomento di ABS() è un'espressione aritmetica, questa verrà valutata prima ed il suo risultato sarà poi passato come argomento alla funzione.
Per esempio in:

say abs(2 - (50 * 2))            /* mostra "98" */
prima viene calcolato il risultato di 2 - (50 * 2), cioè "-98", e poi questo viene passato ad ABS().

Se una funzione permette o richiede più argomenti, questi dovranno essere separati da una virgola:

say copies("=", 80)    /* mostra una sequenza di 80 caratteri "=" */

Le funzioni, a volte, non necessitano di alcun argomento. Per esempio la funzione DATE() usata per mostrare la data dell'orologio di sistema accetta diversi argomenti:

say date()         /* senza argomenti mostra la data corrente come */
                   /* per esempio: 8 Oct 1997                      */

say date("W")      /* mostra il giorno della settimana, in inglese */
                   /* "Weekday". Per esempio: "Wednesday"          */

say date("S")      /* dove "S" è l'iniziale di "Sorted" (ordinato) */
                   /* mostra la data come anno-mese-giorno.        */
                   /* Per esempio "19971008"                       */

La funzione DATATYPE() riporta il tipo di dati da essa valutato:

str1 = "ABC"       /* una stringa di caratteri                     */
str2 = "12"        /* una stringa numerale                         */
say datatype(str1) /* mostra sullo schermo "CHAR"                  */
say datatype(str2) /* mostra sullo schermo "NUM"                   */

Una chiamata di funzione può essere inclusa in una parte qualsiasi di un'espressione. L'interprete del REXX esegue l'elaborazione corrispondente alla funzione chiamata, sostituendo poi il valore risultante prima di valutare la restante parte dell'espressione. L'esempio seguente:

say length("parola") + 10 - length("a")
equivale a:
say 6 + 10 - 1
cioè la lunghezza di "parola" + 10 - la lunghezza di "a".

Comparazione di dati
Tramite la comparazione i dati vengono controllati più che manipolati.
La comparazione fa uso dei seguenti operatori:

OPERATORE SIGNIFICATO
"=" uguale a
"\=" oppure "<>" oppure "><" non uguale
">" più grande di
">=" maggiore di o uguale a
"\>" non più grande di
"<" minore di
"<=" minore di o uguale a
"\>" non minore di
Il carattere "\" nega l'operatore di comparazione che lo segue, cambiando ad esempio "uguale a" in "non uguale a".

Il segno di uguaglianza ("=") ha un significato differente a seconda della sua posizione nella linea di codice. Per esempio:

ammonto = 5           /* assegna il valore 5 alla variabile */

say ammonto = 5       /* compara il valore della variabile ammonto */
                      /* con 5. Se l'uguaglianza viene soddisfatta */
                      /* mostra "1" (VERO), altrimenti "0" (FALSO) */
Generalmente quando il segno = si trova all'inizio dell'espressione rappresenta un operazione di asegnamento, negli altri casi rappresenta un'operazione di comparazione.
Solo nell'istruzione PARSE, come vedremo nelle prossime lezioni, o quando è racchiuso in un commento, ha un significato differente.

Valori logici: VERO e FALSO
Il risultato di un'operazione di comparazione può assumere solo due valori differenti: VERO (cui corrisponde il valore 1) o FALSO (cui corrisponde il valore 0).
Per esempio:

/* alcune comparazioni */
say 5 = 5                   /* mostra '1' (VERO)   */
say 5 <> 5                  /* mostra '0' (FALSO)  */
say 5 = 4                   /* mostra '0'          */
say 2 + 2 = 4               /* mostra '1'          */
say 2 + 2 = 5               /* mostra '0'          */

quanta = 2 + 3              /* assegna il risultato della somma */
                            /* di 2 e 3 alla variabile quanta   */

say "mele" = "banane"       /* mostra '0' (FALSO)  */

frutta = "banane"           /* assegna il valore "banane" alla  */
                            /* variabile frutta                 */
say frutta = "mele"         /* mostra '0'          */
say frutta = "banane"       /* mostra '1'          */

say quanta frutta           /* mostra "5 banane"   */

say quanta frutta = "4 banane"  /* mostra '0'    */
say quanta frutta = "5 prugne"  /* mostra '0'    */
say quanta frutta = "5 banane"  /* mostra '1'    */

Combinazione di espressioni
E' spesso utile combinare tra loro due o più esperssioni ricavandone un unico risultato del tipo VERO-FALSO.

Si possono combinare delle espressioni di comparazione:

  • tramite l'operatore di AND, rappresentato dal carattere &, si ottiene un risultato VERO solo quando entrambe le espressioni danno un risultato VERO:
    frutta = "pere"
    numero = 10
    say frutta = "mele" & numero = 10         /* mostra '0'   */
    say frutta = "pere" & numero = 5          /* mostra '0'   */
    say frutta = "pere" & numero = 10         /* mostra '1'   */
    
    Solo nel terzo esempio entambe le comparazioni sono vere ed il risultato è quindi vero.
  • tramite l'operatore di OR, rappresentato dal carattere |, si ottiene un risultato FALSO solo quando entrambe le comparazioni danno il risultato di FALSO:
    frutta = "pere"
    numero = 10
    say frutta = "mele" | numero = 10         /* mostra '1'   */
    say frutta = "pere" | numero = 5          /* mostra '1'   */
    say frutta = "pere" | numero = 10         /* mostra '1'   */
    say frutta = "mele" | numero = 5          /* mostra '0'   */
    

Uso della comparazione per il controllo dei programmi
Il REXX ha un set di istruzioni che controllano il flusso di esecuzione del programma scegliendo l'azione appropriata in una data situazione.
Tale situazione è determinata dalla verifica di una condizione tramite gli operatori di comparazione.

Nelle istruzioni del tipo IF (se) espressione THEN... (allora...), il risultato dell'espressione deve essere solo 0 (FALSO) o 1 (VERO) perché il codice venga ritenuto valido.
Per esempio:

PRONTO = "SI"                  /* assegna il valore "SI" alla variabile  */

IF PRONTO = "SI" THEN...       /* dato che la comparazione di "PRONTO"   */
                               /* con "SI" dà come risultato 1, viene    */
                               /* eseguita la linea di codice successiva */

  • Tracing
    Nel caso si voglia controllare la sequenza di elaborazione di uno script REXX, per esempio se un programma produce risultati inaspettati, si può usare l'istruzione TRACE.
    Tale istruzione mostra come l'interprete del REXX valuta le espressione durante l'esecuzione del programma.
    Le opzioni più usate sono:
    TRACE Intermediates Mostra immediatamente il risultato di ciascuna operazione.
    TRACE Results Mostra solo il risultato finale di ciascuna espressione dopo che è stata valutata
    E' sufficiente specificare solo la prima lettera dell'opzione:
    TRACE I
    espressione 1
    ...
    espressione n
    
    Il seguente esempio mostra come viene usata l'istruzione TRACE:
    /* ITRACE.CMD: mostra come un'espressione viene */
    /* valutata, operazione per operazione          */
    x = 9
    y = 2
    trace I                          /* abilita il tracing    */
    if x + 1 > 5 * y then            /* se il risultato della */
                                     /* comparazione è '1'    */
    say "x è abbastanza grande!"     /* ...mostra questo.     */
    
    L'esecuzione del programma mostra sullo schermo:
    [C:\]ITRACE
         6 *-*   If x + 1 > 5 * y;
           >V>     "9"
           >L>     "1"
           >O>     "10"
           >L>     "5"
           >V>     "2"
           >O>     "10"
           >O>     "0"
           >>>     "0"
    [C:\]
    
    I simboli significano:
    *-* è in corso il tracing di un'istruzione. Il numero che precede il simbolo è il numero di linea del codice.
    >V> valore della variabile
    >L> valore di un'espressione letterale
    >O> risultato di un'operazione
    >>> il risultato finale dell'espressione
    Nell'esempio precedente, dato che 10 non è maggiore di 10, il risultato è '0', cioè FALSO perciò la frase "x è abbastanza grande!" non viene mostrata sullo schermo.

    Nel caso si desideri controllare solo il risultato finale delle espressioni presenti nel programma, si dovrà invece usare

    TRACE R
    espressione 1
    ...
    espressione n
    
    Il seguente esempio mostra un'impiego pratico di TRACE R:
    /* RTRACE.CMD */
    x = 9
    y = 2
    trace R                       /* abilita il tracing.   */
    if x + 1 > 5 * y then         /* se il risultato della */
                                  /* comparazione è '1'    */
    say "x è abbastanza grande"   /* ...mostra questo.     */
    
    Questa volta avremo sullo schermo:
    [C:\]RTRACE
         5 *-*   If x + 1 > 5 * y;
           >>>     "0"
    [C:\]
    
    Anche in questo caso il simbolo >>> indica il risultato finale e ancora la frase "x è abbastanza grande" non viene mostrata perché non si verifica la condizione necessaria (10 > 10).

  • [Pagina precedente] [Sommario] [Pagina successiva]