Sviluppo

Corso di programmazione in REXX - Lezione 5 - nozioni avanzate

Alessandro Cantatore
 

Annidamento di più istruzioni IF
E' possibile districarsi da complicate situazioni di scelta tra diverse condizioni annidando diverse istruzioni IF.
Il seguente esempio mostra come da due decisioni successive si possono ottenere quattro diversi risultati:

. . .
if tempo = "bello" then do
   if campo = "libero" then
      say "andiamo a giocare a pallone?"
   else
      say "andiamo a fare una passeggiata?"
   end
else do
   if giocatori = 2 then
      say "giochiamo a scacchi?"
   else
      say "giochiamo a poker?"
   end
Notate come le varie istruzioni sono state indentate per rendere più comprensibile il programma.
Il seguente diagramma di flusso rappresenta la logica di esecuzione:

Se si fosse usato SELECT al posto delle istruzioni IF annidate, sarebbe stato necessario usare più volte anche l'operatore logico &:

. . .
select
   when tempo = "bello" & campo = "libero" then
      say "andiamo a giocare a pallone?"
   when tempo = "bello" & campo \= "libero" then
      say "andiamo a fare una passeggiata?"
   when tempo \= "bello" & giocatori = 2 then
      say "giochiamo a scacchi?"
   otherwise
      say "giochiamo a poker?"
   end /* select */
Sebbene entrambi le versioni diano lo stesso risultato, la versione con gli IF annidati è molto più comprensibile e più efficiente essendo necessarie meno comparazioni che nella versione che usa SELECT.
L'uso di SELECT è invece senz'altro preferibile quando non siano presenti delle scelte dipendenti tra loro (come nel caso dei due IF dipendenti dal risultato di if tempo = "bello"), ma solo scelte da valutare contemporaneamente tra diverse possibili condizioni.

Uso di DO...END per evitare ambiguità
E' consigliabile usare la coppia di istruzioni DO...END quando in una serie di scelte non sia presente sempre l'alternativa introdotta da ELSE.
Nel seguente esempio si può erroneamente pensare che ELSE faccia riferimento al primo IF, mentre invece l'interprete del REXX assume sempre si riferisca al primo IF che lo precede:

if tempo = "bello" then
   if campo = "libero" then
       say "andiamo a giocare a pallone?"
else
   say "dobbiamo mettere l'impermeabile?"
Usando DO...END è invece possibile modificare il flusso di esecuzione ottenendo il risultato desiderato e rendendo anche più leggibile il programma:
if tempo = "bello" then do
   if campo = "libero" then
      say "andiamo a giocare a pallone?"
   end
else
   say "dobbiamo mettere l'impermeabile?"

L'istruzione NOP

Le istruzioni THEN e ELSE devono essere seguite da un'istruzione: non è sufficiente un semplice carattere di punto e virgola.
L'istruzione NOP viene usata proprio per indicare che nessuna operazione deve essere eseguita.
Questa operazione può essere utile nei casi in cui ci siano delle istruzioni IF annidate senza che per ognuna di esse sia prevista un'azione alternativa. L'esempio del precedente paragrafo, grazie all'istruzione NOP può funzionare correttamente anche senza l'uso di DO...END:

if tempo = "bello" then
   if campo = "libero" then
      say "andiamo a giocare a pallone?"
   else
      nop
else
   say "dobbiamo mettere l'impermeabile?"

L'istruzione ITERATE
L'istruzione ITERATE, all'interno di un loop, permette di saltare da una parte qualsiasi della lista di istruzioni comprese nel loop alla condizione di esecuzione del loop stesso.
Allo stesso modo di LEAVE può essere introdotta da THEN o ELSE.
Dopo ITERATE, se il ciclo è del tipo DO UNTIL o DO WHILE viene testata la validità della condizione successiva, se è specificato un contatore questo viene incrementato.
Se dopo il test della condizione o l'incremento del contatore il loop è ancora attivo l'elaborazione riprende dalla prima istruzione del loop stesso:

DO variabile = espressione_i BY delta TO espressione_t
   istruzione1
   istruzione2
   IF espressione THEN DO
      istruzione3
      istruzione4
      ITERATE
   END
   istruzione5
   istruzione6
END
Il seguente diagramma di flusso mostra il funzionamento di ITERATE.

Istruzioni DO composite
E' possibile combinare in un unico loop sia la verifica di una condizione che l'incremento di un contatore.
Il seguente esempio mostra l'implementazione di una versione semplificata della funzione POS in grado di riportare la posizione di una stringa in un testo. Anche se alcuni costrutti possono essere non molto chiari (funzioni e subroutine saranno trattati nella prossima lezione) la sintassi del loop dovrebbe essere abbastanza comprensibile:

/* POSIZ.CMD                                             */
/* uso: posiz(stringa, testo)                            */

/* controlla gli argomenti immessi                       */
if arg() \= 2 then         /* se non ci sono 2 argomenti */
   return                  /* restituisce ""             */
if arg(1, "O") then        /* se il secondo argomento è  */
   return                  /* nullo restituisce ""       */

/* assegna gli argomenti alle variabili stringa e testo  */
parse arg stringa, testo

/* calcola la massima posizione possibile per la stringa */
maxpos = length(testo) - length(stringa) + 1

/* cerca "stringa" in "testo"                            */
do risultato = 1 to maxpos,
   until substr(testo, risultato, length(stringa)) = stringa
   end

/* restituisce la posizione di "stringa" o "0" nel caso  */
/* questa non sia presente in testo                      */
if risultato > maxpos then
   risultato = 0
return risultato
La funzione ARG() viene usata per controllare la validità degli argomenti.
Nel loop è presente prima la parte relativa al contatore (risultato = 1 to maxpos) poi, (notate la virgola usata per spezzare un'unica espressione su due righe), tramite la funzione SUBSTR() viene verificato se la porzione di testo che comincia ad una distanza di risultato dall'inizio di testo e lunga quanto stringa sia uguale a stringa. Nel caso ciò si verifichi, il loop viene interrotto in quanto la condizione del UNTIL diventa vera e la funzione può quindi restituire il risultato.
Nel caso la condizione di UNTIL non venga mai soddisfatta il loop verrà interrotto dal contatore quando risultato sarà diventato maggiore di maxpos.

Annidamento di loop
Spesso un programma è costituito da più loop annidati e può essere necessario, al verificarsi di una condizione, uscire non solo dal loop corrente ma anche da uno gerarchicamente superiore.
Per ottenere questo è necessario dare un nome al loop specificando un contatore fittizio:

DO esterno = 1
   .
   .
   .
END
Questo equivale ad un DO FOREVER. Per uscire da un determinato loop è sufficiente specificare il suo nome dopo l'istruzione LEAVE:
DO esterno = 1
   .
   .
   DO interno = 1
      .
      .
      IF espressione THEN
         LEAVE esterno
      .
      .
   END
   .
   .
END
Se espressione risulta vera, tramite l'istruzione LEAVE esterno vengono immediatamente terminati entrambi i loop.


[Pagina precedente] [Sommario] [Pagina successiva]