Regole di scope
Nel seguito quando faremo riferimento a un generico modulo,
nel caso di moduli di libreria è da intendersi come nel modulo
di definizione o nel modulo di implementazione.
Livelli di scope
Lo scope di livello 0 (ovvero lo scope globale) è costituito
da tutti i nomi di costanti, tipi, variabili e funzioni dichiarati in
tutti i moduli al livello più esterno. L'univocità degli
identificatori è garantita dal meccanismo di qualificazione.
Una dichiarazione di funzione apre un livello di scope più
interno nel quale vengono dichiarati gli argomenti formali e gli altri
identificatori locali. Tutti questi identificatori vengono rilasciati
all'uscita dalla funzione.
Nome di modulo
I nomi di modulo devono essere univoci tra quelli coinvolti nel modulo
che si sta compilando. Un modulo può essere IMPORTato anche
più volte, ma di fatto viene incluso solo una volta. Esempio:
MODULE NavalBattle
IMPORT m2, math
E' lecito importare più volte lo stesso modulo: solo la prima
importazione ha effetto, le altre vengono ignorate. Un modulo può
importare sè stesso, anche se l'operazione viene ignorata.
Il modulo di implementazione importa sempre il rispettivo modulo di
definizione. Il modulo m2runtime viene importato
implicitamente da tutti i moduli.
Dichiarazioni di CONST, TYPE, valori dei tipi enumerativi, VAR,
FUNCTION e argomento formale di funzione
L'ID deve essere univoco tra gli ID dello stesso livello di scope del
modulo. Il tentativo di dichiarare due ID omonimi nello stesso livello di
scope del modulo dà un errore fatale di sintassi. Di conseguenza
se l'ID dichiarato è omonimo di un altro dichiarato nello stesso
modulo ma in uno scope più esterno, il nuovo ID maschera quest'ultimo.
E' possibile dichiarare ID omonimi di ID esportati da altri moduli: in
questo caso se l'ID viene successivamente usato senza qualificazione,
il compilatore presume che ci si riferisca all'ID dichiarato nel modulo
corrente.
La dichiarazione esplicita di un tipo precedentemente dichiarato FORWARD
è l'unico caso in qui lo stesso ID viene ri-dichiarato nello
stesso scope dello stesso modulo.
In questo brano di codice indichiamo nella colonna di sinistra il livello
di scope dell'identificatore dichiarato nella stessa riga. Il livello
0 è il livello di scope globale del modulo, mentre i livelli di
scope più interni prendono numeri superiori.
CONST
0 DB_NAME = "REGISTRATIONS"
TYPE
0 Direction = (N, NE, E, SE, S, SW, W, NW)
0 Position = RECORD latitude, longitude: REAL END
VAR
0 air_carrier, submarine: RECORD
head: Direction
loc: Position
END
0 FUNCTION Radiants(
1 deg: INTEGER, min: INTEGER, sec: INTEGER): REAL
1 VAR r: REAL
BEGIN
r = PI/180.0*(itor(m2.abs(deg))
+ itor(m)/60.0 + itor(sec)/3600.0)
IF deg >= 0 THEN
RETURN r
ELSE
RETURN -r
END
END
Gli identificatori DB_NAME Direction N NE E SE S SW W NW Position
air_carrier submarine Radiants sono registrati nel livello di scope
dove queste dichiarazioni sono fatte. I nomi di campo latitude
longitude head loc sono locali ai rispettivi RECORD dentro i
quali sono dichiarati. Gli argomenti formali deg min sec
della funzione sono locali alla funzione stessa.
Dichiarazione dei nomi di campo di un tipo RECORD
I nomi di campo di un tipo RECORD devono essere univoci all'interno del
RECORD stesso, ma non sottostanno a nessuna altra restrizione.
Identificatori usati nelle espressioni e nelle istruzioni
Se l'ID è qualificato indica l'ID allo scope globale
di un modulo importato. La qualificazione degli ID del modulo corrente
è consentita, sebbene non necessaria; in tal caso l'ID individuato
è il primo individuato ricercando dal livello di scope corrente
verso quelli più esterni del modulo.
Se l'ID non è qualificato esso viene ricercato nello
scope corrente e poi nei livelli di scope più esterni del modulo
corrente. Se non trovato nel modulo corrente, esso viene cercato nei
moduli importati: se trovato zero volte è un errore di sintassi;
se trovato una sola volta il nome è risolto, se trovato 2 o
più volte viene generato un errore fatale per ID ambiguo.
Nell'esempio precedente della funzione Radiants, sia
il modulo m2 che il modulo math esportano
l'identificatore abs, pertanto è stato necessario
qualificare il nome m2.abs per risolvere l'ambiguità.
Esempio:
BEGIN
submarine[head] = N
submarine[loc] = { Radiants(+45, 00, 00), Radiants(-25, 00, 00) }
print("Submarine: in position\n")
END
Tutti gli identificatori di questo esempio sono non qualificati. Essi
verranno ricercati per prima nel modulo corrente, procedendo dal
livello di scope corrente verso i livelli più esterni. Nel caso di
print esso verrà trovato nel modulo m2
come unica altra ricorrenza. Notare che la costante enumerativa
E ha lo stesso nome di math.E: per ottenere
quest'ultima, la qualificazione sarà obbligatoria.
|