linguaggi/s02/20260224.md
... ...
@@ -105,7 +105,7 @@ Il ciclo di vita di un RdA si divide in fasi ben precise gestite dal chiamante e
105 105
5. Deallocazione dello spazio sulla pila (si arretra il Puntatore al Top).
106 106
6. Ripristino del Contatore di Programma all'indirizzo di ritorno salvato.
107 107
108
-### 4. Esempio di Ricorsione: Il Fattoriale
108
+### Esempio di Ricorsione: Il Fattoriale
109 109
110 110
Prendiamo come esempio la funzione fattoriale: `fact(n) { if (n<=1) return 1; else return n * fact(n-1); }`
111 111
![20260214_2026-02-24_13-47-58](assets/imgs/20260214_2026-02-24_13-47-58.png)
... ...
@@ -197,33 +197,38 @@ Consideriamo il seguente pseudo-codice:
197 197
**Come si comporta in memoria?**
198 198
Il codice della funzione `foo` deve accedere sempre alla stessa variabile `x` (quella dichiarata globalmente a valore 10, memorizzata nel Record di Attivazione - RdA - del main).
199 199
200
+![20260214_2026-02-24_14-50-43](assets/imgs/20260214_2026-02-24_14-50-43.png)
201
+
200 202
- Anche se chiamiamo `foo` dall'interno di `fie` (dove esiste una x locale a 0), lo scope statico impone che `foo` "veda" solo l'ambiente in cui è stata definita (il main).
201 203
- Il meccanismo: A run-time, in cima alla pila c'è l'RdA di `foo` (il Puntatore SP guarda lì). Per trovare la x giusta, il sistema non la cerca semplicemente "indietro" nella pila dinamica, ma usa i puntatori di scope per determinare prima qual è l'RdA corretto a cui appartiene quella variabile (in questo caso l'RdA del main). Una volta trovato l'RdA giusto, accede a x tramite l'offset calcolato rispetto a *quell'*RdA, ignorando totalmente la x locale di fie.
202 204
203
-![20260214_2026-02-24_14-50-43](assets/imgs/20260214_2026-02-24_14-50-43.png)
204 205
x tramite offset relativo a tale RdA (e non relativo a SP)
205 206
206
-Record di attivazione per scoping statico
207
+### Link Dinamico vs Link Statico
208
+
207 209
![20260214_2026-02-24_14-52-46](assets/imgs/20260214_2026-02-24_14-52-46.png)
208
-Link dinamico:
209
-– puntatore all’RdA precedente sulla pila (RdA del chiamante)
210
-• Link statico:
211
-– puntatore all’RdA del blocco che contiene immediatamente il testo del blocco in esecuzione
212
-• Osserva:
213
-– link dinamico dipende dalla sequenza di esecuzione del programma
214
-– link statico dipende dall’annidamento statico (nel testo) delle dichiarazioni delle procedure
215
-
216
-Catena Statica: esempio
210
+Nel Record di Attivazione (RdA), quando si usa lo scope statico, sono presenti due puntatori fondamentali che servono a scopi diversi:
211
+
212
+- **Link Dinamico:** Punta all'RdA della procedura _chiamante_ (quella precedente sulla pila). Dipende esclusivamente dalla **sequenza di esecuzione** del programma a run-time.
213
+- **Link Statico:** Punta all'RdA del blocco che **contiene testualmente** la procedura in esecuzione (il blocco "padre" nel codice sorgente). Dipende esclusivamente dall'**annidamento statico** del codice scritto dal programmatore.
214
+
215
+### Esempio
216
+
217 217
Sequenza di chiamate a run time A, B, C, D, E, C
218 218
![20260214_2026-02-24_14-55-43](assets/imgs/20260214_2026-02-24_14-55-43.png)
219
-le linee tratteggiate sono link statici
220
-
221 219
![20260214_2026-02-24_14-56-18](assets/imgs/20260214_2026-02-24_14-56-18.png)
222
-Se un sottoprogramma è annidato a livello k, allora la catena è lunga k
220
+**Risoluzione delle Variabili** (Come trovare la 'x' giusta)
221
+Se un sottoprogramma (es. $E$) è annidato a livello $k$, la sua catena statica è lunga $k$.
222
+Quando il programma deve accedere a una variabile _non locale_ $x$:
223
+
224
+1. **Cosa fa il Compilatore:** Determina a livello statico a quale blocco appartiene la variabile (es. "la $x$ si trova 2 livelli più in alto"). Associa al nome della variabile un indice $h$:
225
+ - $h=0$: Variabile locale (trovata nell'RdA corrente).
226
+ - $h>0$: Variabile non locale definita $h$ blocchi sopra. Il compilatore dice al programma _quanti passi_ fare, ma non conosce l'indirizzo esatto in memoria.
227
+2. **Cosa succede a Run-time:** Il programma usa il Link Statico per "risalire" di $h$ RdA. Una volta raggiunto l'RdA corretto (es. risalendo dal blocco $E$ al blocco $C$, e poi al blocco $A$), utilizza un offset per accedere fisicamente alla variabile.
223 228
224
-se sono in e e sto cercando una var x non locale allora vado in c e poi vado in a
225
-questo grazie ai link statici (questi puntatori sono determinati a runtime)
226
-Esempio
229
+> **Nota**: Se un sottoprogramma è annidato a livello k, allora la catena è lunga k
230
+
231
+_Esempio Pratico:_ Se la funzione $A$ è definita nel `main`, il suo link statico punterà sempre all'RdA del `main`. Se $A$ modifica $x$, modificherà sempre la $x$ del `main`, indipendentemente da chi ha chiamato $A$ a run-time.
227 232
228 233
```
229 234
{int x;
... ...
@@ -242,64 +247,32 @@ B();
242 247
}
243 248
```
244 249
245
-Struttura main con dentro a e b e b con dentro c
246
-
247 250
![20260214_2026-02-24_15-05-26](assets/imgs/20260214_2026-02-24_15-05-26.png)
248
-la x che viene modificata e' sempre quella del main visto che viene modificata da A e il puntatore di catena statica di A punta al main. Le altre x non vengono modificate da A.
249
-C modifica la propria x (visto che la dichiara ed e'quindi locale)
250
-
251
-il compilatore dice di risalire di 1 il record di attivazione. A lo fa e trova a x del main (con un offset)
252
-
253
-se in C avessi la variabile pippo chee e' definita nel main il compilatore mi direbbe che pippo e' definito in main (2 livelli sopra) e quindi quando devo manipolarla o chiamarla salgo due livelli e ne uso il valore
251
+(non si capisce molto)
254 252
255
-Il compilatore sa dove sono dichiarate le variabili ma non sa la loro posizione a runtime (quindi ci dice solo quanto andare in su ma il dove va deciso a runtime grazie alla catena statica)
253
+- la x che viene modificata e' sempre quella del main visto che viene modificata da A e il puntatore di catena statica di A punta al main. Le altre x non vengono modificate da A.
254
+- C modifica la propria x (visto che la dichiara ed e'quindi locale)
256 255
257
-Dal punto di vista del supporto a run time
258
-Come viene determinato il link statico del chiamato?
256
+Quando una procedura $Ch$ (chiamante) invoca una procedura $P$ (chiamato), **è il chiamante che deve determinare e passare il Link Statico al chiamato**.
257
+Affinché $Ch$ possa chiamare $P$, $P$ deve essere nel suo scope visibile. Ci sono due casi, basati sulla distanza di annidamento ($k$) tra $Ch$ e $P$:
259 258
260
-es sopra
261
-sono nel main, chiamo B devo inizializzre il puntatore di catena statica di B, so che B e' inizializzato dentro al main quindi inizializzo il suo puntatore al main (me)
262
-Ora B chiama A, come posso inizializzare il suo puntatore? B sa che A e' allo stesso livello di annidamento di A e quindi gli basta risalire di (0) livelli e passare il puntatore a A.
263
-In generale o X e' inizializzato dentro a A (e quindi il suo indirizzo e' A) oppure Si calcola livello di annidamento di A - X e si risalgono i A-X livelli e si assegna l'indirizzo a X
259
+- **Caso 1 ($k=0$):** $P$ è definito _immediatamente dentro_ $Ch$.
260
+ - _Soluzione:_ $Ch$ passa a $P$ semplicemente il proprio Stack Pointer (SP). L'RdA di $Ch$ diventa il Link Statico di $P$.
261
+- **Caso 2 ($k>0$):** $P$ è definito in un blocco $k$ passi "fuori" da $Ch$ (cioè $Ch$ e $P$ condividono un blocco padre o nonno comune).
262
+ - _Soluzione:_ $Ch$ risale la **propria** catena statica di $k$ passi per trovare l'RdA del blocco in cui è definito $P$, e passa quel puntatore come Link Statico a $P$.
264 263
265
-e'il chiamante a determinare il link statico del chiamato
266
-Info a disposizione del chiamante:
264
+_Nota di Visibilità:_ Un blocco non può chiamare un altro blocco "fratello" se non lo "vede" (es. se $B$ e $C$ sono definiti dentro $A$, e $D$ è definito dentro $C$, il blocco $B$ non può chiamare $D$ direttamente).
267 265
268
-- annidamento statico dei blocchi (determinata dal compilatore)
269
-- proprio RdA
270
-
271
-Come determinare il puntatore di Catena statica (CS)
272
-il chiamante Ch conosce l'annidamento dei blocchi:
273
-
274
-- quando Ch chiama P sa se la definizione di P e':
275
- - immediatamente inclusain Ch (k=0)
276
- - in un blocco k passi fuori da Ch
266
+![20260214_2026-02-24_15-32-13](assets/imgs/20260214_2026-02-24_15-32-13.png)
277 267
278
-– nessun altro caso possibile:
279
-• perché P deve essere in scope!
280
-– nel caso a destra:
281
-• chiamate: A, B, C, D, E, C
282
-– con i dati di catena statica:
283
-• A; (B,0); (C,1); (D,0); (E,1); (C,2)
268
+### Ripartizione dei Compiti e Costi Computazionali
284 269
285
-Se k=0:
286
-– Ch passa a P il proprio SP
287
-•Se k>0:
288
-– Ch risale la propria catena statica di k passi e passa il puntatore così determinato
289
-![20260214_2026-02-24_15-32-13](assets/imgs/20260214_2026-02-24_15-32-13.png)
270
+L'implementazione dello scope statico divide il lavoro e introduce dei costi a run-time:
290 271
291
-> Nota: Se B chiamasse D non potrebbe farlo perche' non lo puo' vedere.
292
-
293
-Ripartizione dei compiti
294
-Compilatore:
295
-
296
-- associa l'informazione k ad ogni chiamata
297
-- associa ad ogni nome un indice h:
298
- - h=0: nome locale
299
- - h diverso da 0: nome non locale definito h blocchi sopra
300
-- sequenza chiamata/prologo
301
- - risale la catena statica
302
- - inizializza il puntatore di catena statica
303
-- Costi:
304
- - per ogni chiamata: k passi di catena statica
305
- - ad ogni accesso ad una variabile non locale:(h passi di catena statica in piu rispetto all'accesso ad un locale)
272
+- **Compilatore:** \* Associa la distanza di chiamata ($k$) ad ogni invocazione di funzione.
273
+ - Associa la distanza di annidamento ($h$) ad ogni accesso a variabile.
274
+- **Sequenza di chiamata / Prologo (Run-time):**
275
+ - Risale materialmente la catena statica e inizializza il puntatore per il nuovo RdA.
276
+- **Costi a Run-time:**
277
+ - **Costo di chiamata:** Per ogni chiamata a funzione, bisogna fare $k$ "salti" sui puntatori della catena statica.
278
+ - **Costo di accesso a variabile non locale:** Per ogni lettura/scrittura, bisogna fare $h$ "salti" nella catena statica (più costoso rispetto all'accesso di una variabile locale, che richiede 0 salti).Compilatore: