14 settembre, 2019
Visibilità (scope) lessicale e dinamica - 3
Continuo da qui la serie di post elementari sui linguaggi con visibilità delle variabili lessicale e/o dinamica.
Però questo è più una diversione su come venivano definite le variabili, globali rispetto alle locali quando ho cominciato, tanto tempo fa. Mi riferisco al Fortran ((IV o 66) o 77) con l'avvertenza che allora avrei dovuto scrivere tutto maiuscolo, tranne qualche eccezione nel 77 (p.es. Apollo). Allora i sistemi operativi erano tanti, diversi e altrettante le varianti per i compilatori. Occorreva adeguarsi alla macchina e evitare le particolarità; per me adeguarsi a DEC, quelli del VAX. Benché il linguaggio fosse vecchio di più di 20 anni era di gran lunga il più usato e lo sarebbe rimasto ancora per parecchio tempo anche se insidiato dal BASIC (sui PC) e dal C (su Unix).
Il programmino proposto da Ming-Ho, l'avrei scritto così:
program ming_ho
call setx(1)
print *, ig()
end
function jf(ia)
common /cox/ ix
jf = ix + ia
end
function ig()
ix = 2
ig = jf(0)
end
subroutine setx(n)
common /cox/ ix
ix = n
end
Forse è il caso di commentare il codice; anzi devo premettere che appena iniziata la lettura del post di Ming-Ho mi è subito venuto da pensare che le ambiguità sulla visibilità (scope) delle variabili nel Fortran non c'era. Cioè non c'erano le variabili globali, sono tutte locali. Ma possono essere condivise, con i common. Non che il common non potesse generare bugs ma questo sarebbe un altro discorso (lungo).
Ah! una nota: ho cambiato il nome alle variabili e funzioni per adeguarmi alla convenzione dei nomi impliciti, per gli interi premetto una i ai nomi di Ming-Ho; la funzione f() la rinomino in jf() per evitare amibuità con if, cosa che sarebbe possibile (non esistono parole riservate in Fortran) ma che potrebbe rendere quixotica la comprensione del codice.
L'esame de codice rivela una prima particolarità che lo distingue dagli altri linguaggi usati allora (C e Pascal): il main, il programma principale è di solito all'inizio, eventualmente indicato dall'istruzione program che ne definisce il nome.
Nel mio caso il main è composto da una chiamata alla subroutine setx che setta il valore alla variabile globale (cioè in common) che verrà utilizzata dalla funzioni if(). Segue l'istruzione di scrivere il valore della funzione ig(). end termina il main; potrei scrivere anche end nome-del-programma ma nessuno lo faceva, neache per funzioni e subroutines.
In questo caso l'istruzione call setx(1) potevo sostituirla con la coppia common /cox/ ix seguita da ix = 1. In un programma più complesso una routine di settaggio delle variabili globali acquista senso e oggi faccio il didascalico. Notare che posso scrivere common /cox/ n e poi n = 1, l'importante è di inserire il valore 1 nei primi 4 bytes di cox. Inoltre il common potrebbe essere senza nome, così common n. setx non deve ritornare un valore e allora conviene definirla come subroutine e quindi chiamarla con call.
La funzione jf() usa la variabile ix memorizzata nel common cox. A questa variabile somma l'argomento ia e questa somma è il valore ritornato. Notare la particolarità: si usa il nome della funzione per indicare il valore della funzione. Esiste anche l'istruzione return ma non ritorna niente; indica l'abbandono della funzione (o subroutine) e il ritorno al chiamante.
Nella funzione ig() setto la variabile ix ma questa è locale e non verrà utilizzata; anzi probabilmente il compilatore eliminerà questa istruzione (non ho verificato, una volta, sulla la mia macchina era così). ig() ritorna poi la chiamata a jf() con argomento 0. Non agisco sulla variabile nel common e quindi qui il common non compare.
La subroutine setx assegna il valore passato come argomento al common. Essendo una subroutine non torna un valore al chiamante.
Non resta che provare il programma (il file ld.f produrrà l'eseguibile ld); lo compilo ed eseguo ottenendo:
$ gfortran -o ld ld.f
$ ./ld
1
$
OK, vero che è più semplice? o sono solo io.
🔴
Iscriviti a:
Commenti sul post (Atom)
Nessun commento:
Posta un commento