Sviluppo

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

Alessandro Cantatore
 

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

In questa lezione vedremo come sia possibile controllare il flusso di esecuzione dei programmi strutturandoli in modo che sia possibile eseguire un programma dall'interno di un altro.
L'uso di questi sottoprogrammi, più propriamente subroutine, rende molto più semplice la creazione di programmi complessi.

Le subroutine
Una subroutine è una porzione di codice richiamabile da più posti all'interno del programma principale. Essa può essere collocata nell'interno dello stesso file del programma principale o in un diverso file .CMD.
Il seguente diagramma mostra il flusso di esecuzione di una subroutine.

Diagramma chiamata subroutine

L'istruzione CALL dice all'interprete del REXX di ricercare all'interno del programma la corrispondente etichetta (label), un simbolo che indica l'inizio della subroutine.
Il REEX esegue la lista di istruzioni seguente l'etichetta finché non incontra l'istruzione RETURN che gli dice di riprendere il flusso di esecuzione dal programma principale, all'istruzione successiva alla chiamata (CALL) della subroutine.

Una subroutine può essere chiamata da più diverse posizioni del programma principale, cioè diverse istruzioni CALL possono richiamare la stessa subroutine. Il flusso di esecuzione dopo RETURN riprende sempre dalla riga seguente l'ultima istruzione CALL che è stata eseguita.

Ogni istruzione CALL può passare dei dati, chiamati argomenti, che la subroutine può determinare tramite l'istruzione ARG o la funzione ARG() e usare quando è in esecuzione.

L'istruzione CALL
La sintassi dell'istruzione CALL è la seguente:

CALL nomesub [argomento1, argomento2, . . . , argomenton]
dove:
nomesub
è il nome della subroutine. Il REXX cerca la corrispondente etichetta nel programma. Un etichetta consiste in un simbolo (cioè il nome dato alla subroutine) seguite dal carattere di due punti (":"). Per esempio:
nomesub:
Se il REXX non trova un'etichetta corrispondente, controlla tra le sue funzioni interne se ce nè una con lo stesso nome della subroutine, se la ricerca ancora fallisce cerca un file .CMD esterno con lo stesso nome della routine.
argomento1...n
rappresenta i dati che si vogliono passare. Questi vengono ricavati all'interno della subroutine tramite l'istruzione ARG o la funzione ARG().
Il seguente esempio mostra un programma che calcola il quadrato dei numero compresi tra 1 e 3 servendosi di una subroutine:
/* quadrato.cmd */
say
say "Questo è il programma principale"
do num = 1 to 3
   call square
   say " ------------"
   say "Di nuovo nel programma principale"
   say num "elevato al quadrato è" num2
   say " ------------"
end
exit

/* questa è la subroutine che eleva al quadrato num */
square:
say
say "    -> Questa è la subroutine!"
say
num2 = num * num
return

L'istruzione RETURN
L'istruzione RETURN riporta l'elaborazione alla routine principale del programma e da qui l'elaborazione riprende con l'istruzione successiva all'ultimo CALL.
La sintassi dell'istruzione RETURN è:

RETURN [espressione]
dove espressione rappresenta un parametro facoltativo che, se presente, è assegnato alla variabile speciale del REXX RESULT che può poi essere usata all'interno della routine principale.
Se espressione viene omessa non viene assegnato alcun valore a RESULT.

Subroutine esterne
Le subroutine esaminate nei precedenti paragrafi sono subroutine interne in quanto contenute nello stesso file della routine principale.
Le subroutine possono anche essere costituite da un programa REXX separato in un altro file. In tal caso vengono dette subroutine esterne.
Il seguente diagramma mostra il flusso di esecuzione di una subroutine esterna.

Diagramma chiamata subroutine esterna

In una subroutine esterna le varibili appartenenti alla routine chiamante non sono disponibili cioè visibili dalla subroutine stessa.
Perciò:

  1. i dati si possono passare alla subroutine solo come argomenti nell'istruzione CALL;
  2. i dati elaborati possono essere restituiti alla funzione chiamante solo tramite la variabile speciale RESULT usando l'istruzione RETURN. Se necessario la routine chiamante può poi suddividere il valore presente in RESULT in diverse variabili.

Nota: Le variabili della routine chiamante sono visibili nella routine interna a meno che non si usi l'istruzione PROCEDURE che vedremo più approfonditamente in seguito.

L'uso degli argomenti
Nell'esempio che segue è possibile addizionare due numeri scrivendo da riga di comando il nome del programma (SOMMA) seguito dai numeri da sommare.

/* somma.cmd */
arg num1 num2
say "La somma di" num1 "e" num2 "è" num1 + num2
I numeri introdotti dalla riga di comando sono assegnati, tramite l'istruzione ARG alle due variabili num1 e num2.
I dati passati al programma in questo modo vengono detti argomenti.
Quindi i due numeri introdotti di seguito al nome del programma stesso sono gli argomenti del programma.
Allo stesso modo anche le subroutine possono ricevere i dati dal programma principale.

Per assegnare gli argomenti alle variabili si può usare:

ARG
assegna il valore degli argomenti alle variabili traducendo i caratteri minuscoli in maiuscoli, allo stesso modo dell'istruzione PULL vista nelle lezioni precedenti.
PARSE ARG
assegna il valore degli argomenti alle variabili esattamente come sono immessi, cioè senza eseguire alcuna conversione da minuscolo a maiuscolo.
Per esempio in presenza dell'istruzione:
CALL cuoci "bianco", "fresco", "dolce"
se si vuole assegnare i valori "bianco", "fresco" e "dolce" alle variabili farina, zucchero e biscotto nella subroutine cuoci bisognerà usare la seguente espressione:
PARSE ARG farina, zucchero, biscotto
Se si vuole che gli argomenti vengano convertiti in maiuscolo (questo è utile quando si vuole comparare il valore di due stringhe di testo) bisognerà invece usare:
ARG farina, zucchero, biscotto
Essendo presenti delle virgole come separatore degli argomenti nell'istruzione CALL queste dovranno essere usate come segnaposti anche nelle corrisipondenti istruzioni ARG o PARSE ARG.
Per esempio usando l'istruzione:
CALL  parole "una stringa di parole", 5
i dati potrebbero essere rilevati usando:
parole:
PARSE ARG primo secondo terzo quarto resto, numero
I valori presenti nelle variabili sarebbero:
primo      ->     una
secondo    ->     stringa
terzo      ->     di
quarto     ->     parole
resto      ->     (nessun valore)
numero     ->     5

Il seguente esempio mostra:

  • CALL passa gli argomenti ad una subroutine
  • ARG assegna i valori degli argomenti a delle variabili
  • RETURN assegna un valore alla variabile RESULT.
  • RESULT è usato dal programma principale
/* MAKEBOX.CMD: programma principale. Chiede di immettere alcuni */
/* valori e mostra il risultato del calcolo                      */
say "Per calcolare il materiale necessario per fare una scatola"
say "Introdurre la lunghezza della scatola"
pull lunghezza
say "Introdurre la larghezza della scatola"
pull larghezza
say "Introdurre l'altezza della scatola"
pull altezza
/* chiama la subroutine passandogli i dati ricavati */
call box lunghezza, larghezza, altezza
/* riporta il valore restituito dalla variabile RESULT */
say "il materiale richiesto è" result "metri quadrati"
exit
La subroutine chiamata da MAKEBOX.CMD è:
/* BOX.CMD: calcola la superficie di */
/* una scatola incluso il coperchio  */
arg lungo, largo, alto
area = 2 * lungo * largo + 2 * largo * alto + 2 * lungo * alto
return area
Quando si esegue MAKEBOX.CMD i dati introdotti vengono raccolti tramite l'istruzione PULL e passati come argomenti, tramite CALL a BOX.CMD. L'area calcolata nella subroutine viene poi restituita a MAKEBOX.CMD dall'istruzione RETURN nella variabile RESULT.

Se ci si riferisce a delle variabili usando gli stessi nomi sia all'esterno che all'interno di una subroutine interna (cioè una routine situata nello stesso file da cui è chiamata) non è necessario includere le variabili come argomenti delle istruzioni CALL e ARG. Questo comunque influirebbe negativamente sulla chiarezza e leggibilità del programma per cui è buona norma usare una lista di argomenti per passare dei valori ad una subroutine anche quando non strettamente necessario.

La Funzione ARG()
Un altro metodo per passare degli argomenti ad una subroutine è basato sulla funzione ARG():

CALL NomeSubroutine [argomento_1, argomento_2 . . . argomento_n]
dove:
NomeSubroutine
è il nome della subroutine
argomento_1, argomento_2 . . . argomento_n
sono espressioni il cui valore è calcolato e ottenuto nella subroutine usando la funzione ARG():
ARG(1)
restituisce il primo argomento
ARG(2)
restituisce il secondo argomento
ARG(n)
restituisce l'ennesimo argomento
Nota: Il massimo numero di argomenti ammessi in un'istruzione CALL è 20.
Il seguente esempio mostra più chiaramente l'uso di ARG():
/* ARGESEMP.CMD */
say            /* inserisce riga vuota */
call inverti "primo", "secondo", "terzo", "quarto"
say
call dispari "primo", "secondo", "terzo", "quarto"
say
call pari "primo", "secondo", "terzo", "quarto"
exit         /* fine del programma principale */

inverti:     /* mostra in ordine inverso gli argomenti */
   say "argomenti invertiti:"
   say arg(4)", "arg(3)", "arg(2)", "arg(1)
return       /* fine della subroutine inverti */

dispari:     /* mostra solo gli argomenti dispari */
   say "argomenti dispari:"
   say arg(1)", "arg(3)
return       /* fine della subroutine dispari */

pari:        /* mostra solo gli argomenti pari */
   say "argomenti pari:"
   say arg(2)", "arg(4)
return
Nota: l'istruzione exit, alla fine della parte principale del programma è necessaria per impedire all'interprete del REXX di proseguire l'esecuzione con il codice successivo alla parte principale stessa. Provate a toglierla per vedere cosa succede. Se un programma che scrivete non funziona come vi aspettate controllate se avete messo un EXIT alla fine della parte principale del programma.


[Pagina precedente] [Sommario] [Pagina successiva]