Corso di programmazione in REXX - Lezione 2 - approfondimento


Simboli

Le variabili sono parte di una classe di elementi del linguaggio REXX chiamati simboli I simboli sono:

Il REXX determina dal contesto in cui si trova un simbolo, se questo è una parola chiave, un'etichetta o una variabile. La logica seguita dell'interprete è la seguente:
  1. Se la prima parola letta dall'interprete è un simbolo ed è seguito da:
    1. un segno di uguale (=), l'espressione viene interpretata come un assegnamento: il simbolo è una variabile cui viene assegnato il valore dell'espressione che segue il segno di uguale.
    2. un segno di due punti (:), è un'etichetta segnalante l'inizio di una subroutine.
  2. Se il simbolo è nella lista delle parole chiave del REXX, viene interpretato di conseguenza.
  3. Se il simbolo inizia con un numero viene interpretato come un valore costante.
  4. Se il simbolo non soddisfa alcuna delle precedenti condizioni, il simbolo viene interpretato come variabile e il REXX sostituisce ad essa il valore corrispondente precedentemente memorizzato.

Costanti e variabili

I simboli che iniziano con una cifra (0-9), un punto (.) o un segno (+ o -) sono costanti in quanto ad essi non può essere assegnato un valore e non possono perciò essere usati come variabili.
Alcuni esempi di costanti sono:

77           /* un numero intero                   */
.0004        /* corrisponde a 0,0004               */
1.2e6        /* notazione scientifica (1,2 * 10^6) */
42nd         /* non è un numero ma una costante    */
Il simbolo 42nd (quarantaduesimo in inglese) pur non essendo un numero è una costante valida il cui valore corrisponde sempre a 42ND. Tutti i numeri validi sono costanti, ma non tutte le costanti sono numeri validi.
Il valore di default per un simbolo, variabile o costante, corrisponde al nome del simbolo stesso convertito in lettere maiuscole. Una variabile cui non è ancora stato assegnato un valore contiene questo valore di default

Simboli composti

Una speciale classe di simboli, in cui variabili e costanti sono combinate insieme per creare dei gruppi di variabili logicamente correlate, è costituita dai simboli composti. Una variabile contenente un punto viene trattata come un simbolo composto.
Alcuni esempi di validi simboli composti sono:

file.3
riga.colonna
array.d.g
I simboli composti possono essere utili per creare degli insiemi di variabili che possono venire elaborate in base al loro nome composito.
Supponiamo di avere il seguente gruppo di variabili:
mese.1 = "gennaio"
mese.2 = "febbraio"
...
...
mese.12 = "dicembre"
se in un programma usiamo la variabile corrente, assegnando ad essa un valore compreso tra 1 e 12 dalla variabile composta mese.corrente potremo ottenere il nome del mese corrispondente.
/* mese.cmd */
mese.1 = "gennaio"
mese.2 = "febbraio"
mese.3 = "marzo"
mese.4 = "aprile"
mese.5 = "maggio"
mese.6 = "giugno"
mese.7 = "luglio"
mese.8 = "agosto"
mese.9 = "settembre"
mese.10 = "ottobre"
mese.11 = "novembre"
mese.12 = "dicembre"
say "Immettere un numero compreso da 1 a 12 per avere il nome del mese..."
pull corrente
say "Al numero" corrente "corrisponde" mese.corrente
Usando dei loop cioè dei comandi che permettono di ripetere più volte una serie di istruzioni, che vedremo più approfonditamente in seguito, possiamo elencare tutti i valori memorizzati in modo molto semplice.
/* lista.cmd */
mese.1 = "gennaio"
mese.2 = "febbraio"
mese.3 = "marzo"
mese.4 = "aprile"
mese.5 = "maggio"
mese.6 = "giugno"
mese.7 = "luglio"
mese.8 = "agosto"
mese.9 = "settembre"
mese.10 = "ottobre"
mese.11 = "novembre"
mese.12 = "dicembre"
do i = 1 to 12      /* ripete 12 volte */
   say "mese" i "=" mese.i
end
Come vedremo poi, è pratica comune memorizzare il numero totale delle variabili nell'elemento 0:
/* lista_1.cmd */
mese.0 = 12
mese.1 = "gennaio"
mese.2 = "febbraio"
mese.3 = "marzo"
mese.4 = "aprile"
mese.5 = "maggio"
mese.6 = "giugno"
mese.7 = "luglio"
mese.8 = "agosto"
mese.9 = "settembre"
mese.10 = "ottobre"
mese.11 = "novembre"
mese.12 = "dicembre"
do i = 1 to mese.0
   say "mese" i "=" mese.i
end

Stem e tail

La prima parte di un simbolo composto, incluso il punto, viene detta stem. Lo stem è seguito da una o più parti, costanti o variabili, separate da un punto che vengono dette tail.
L'insieme delle variabili accomunate da un unico stem viene detto array.
Lo stem può essere usato anche per riferirirsi contemporaneamente a tutte le variabili parte dell'array, inizializzandole, per esempio ad un dato valore:

punti. = 0
in questo modo tutte le singole variabili, parti dell'array punti avrebbero il valore 0, cioè punti.0 = 0, punti.1 = 0, punti.2 = 0, ecc.

Array multidimensionali

Come abbiamo appena affermato lo stem può essere seguito da una o più tail creando così array a più dimensioni.
Nel caso volessimo creare un gioco basato su una scacchiera, per esempio il gioco della dama, un array bidimensionale sarebbe utile per identificare le singole caselle. Definendo le pedine bianche con "b", le dame bianche con "B", le pedine nere con "n" e le dame con "N", la scacchiera potrebbe essere inizializzata come segue:

/* dama.cmd */

/* inizializza tutti gli elementi al valore di una stringa vuota */
board. = ""
/* posiziona le pedine */
do col = 1 by 2 to 7
   board.1.col = "b"
end
do col = 2 by 2 to 8
   board.2.col = "b"
end
do col = 1 by 2 to 7
   board.3.col = "b"
end
do col = 2 by 2 to 8
   board.6.col = "n"
end
do col = 1 by 2 to 7
   board.7.col = "n"
end
do col = 2 by 2 to 8
   board.8.col = "n"
end

Variabili speciali

Nel REXX ci sono 3 variabili speciali cui viene automaticamente assegnato un valore:

RESULT
memorizza il valore restituito da una subroutine tramite l'istruzione return.
SIGL
memorizza il numero della linea da cui viene chiamata un'etichetta
RC
memorizza il valore restituito dall'esecuzione di un comando (ha lo stesso scopo dell'ERRORLEVEL dei file batch)

La funzione Symbol()

Spesso può essere necessario controllare che il nome di un simbolo non sia già stato usato per definire un'altra variabile. A questo scopo si usa la funzione Symbol() con il nome che si vuole controllare come parametro.
Il valore restituito da Symbol può essere:

BAD
Il nome non è un simbolo REXX valido
VAR
E' il nome di una variabile cui è stato assegnato un valore
LIT
E' una costante o il nome di una variabile cui ancora non è stato assegnato alcun valore
Create il seguente programma per verificare come funziona Symbol():
/* SYMBOL.CMD */
alfa = 11
say "Symbol(""alfa"") =" Symbol("alfa")   /* variabile inizializzata     */
say "Symbol(""beta"") =" Symbol("beta")   /* variabile non inizializzata */
say "Symbol(""33"") =" Symbol("33")       /* costante                    */
say "Symbol("")&#@"") =" Symbol(")&#@")   /* simbolo non valido          */
Un uso di Symbol() è quello di assicurarsi che una variabile sia stata inizializzata prima di impiegarla in un'operazione:
/* SYMBOL1.CMD */
if Symbol("cash") = LIT
   then cash = 0
cash = cash + 100
say "cash = "cash
Perché il risultato ottenuto dalla funzione Symbol() possa essere considerato valido è indispensabile racchiudere tra virgolette il nome del simbolo che si vuole controllare. Se si omettessero le virgolette l'interprete REXX sostituirebbe al nome del simbolo il valore corrispondente.
Tornando al precedente esempio Symbol(alfa) sarebbe valutato come Symbol(11).

L'istruzione procedure

Quando si scrive una subroutine di un programma complesso può capitare di non ricordarsi i nomi di tutte le variabili precedentemente usate. E' sempre possibile rileggersi tutto il codice precedentemente scritto, ma oltre al tempo sprecato si correrebbe il rischio di lasciarsi sfuggire qualche variabile. Con l'istruzione procedure è possibile usare nella subroutine nomi di variabili già usate in precedenza, con la sicurezza che queste vengano interpretate come variabili differenti.
L'istruzione procedure può essere usata solo come prima istruzione di una subroutine interna.

/* PROCED.CMD */
count = 999
alfa = 123456
list = 3 4 5 6 7

say "inizialmente count =" count
say "inizialmente alfa =" alfa
say "inizialmente list =" list

call average list          /* chiama la subroutine "average" */

say "nella procedura principale count =" count
say "nella procedura principale alfa =" alfa
say "nella procedura principale list  =" list
exit                       /* termina il programma           */

/* questa è la subroutine "average"                          */
average:
procedure
arg a b c d e
/* count è una variabile differente dal precedente count     */
count = (a + b + c + d + e) / 5
alfa = 654321
say "nella routine ""average"" count =" count
say "nella routine ""average"" alfa =" alfa
say "nella routine ""average"" list =" list
return
Nel caso sia necessario esporre nella soubroutine alcune delle variabili esterne, si può aggiungere l'istruzione expose a procedure facendola seguire dalla lista delle variabili da esporre:
procedure expose nomevarabile_1 nomevariabile_2 ... nomevariabile_n
Per capire meglio il funzionamento di procedure e expose può essere utile modificare più volte proced.cmd cancellando l'istruzione procedure o sostituendola con procedure expose seguita dal nome di una o più variabili.

Altri mezzi di memorizzazione dati

Le variabili sono il mezzo principale di memorizzazione e manipolazione dei dati all'interno di un programma REXX. Altri sistemi che permettono di condividere dati con altri programmi sono le code (queues) e i file.
In una delle seguenti lezioni vedremo come interagire sia con le queue che con i file.


a cura di Alessandro Cantatore

[Pagina precedente] -- [Sommario] -- [Home Page] -- [Pagina successiva]