Istruzioni strutturate

Le istruzioni strutturate sono poche: sequenza di istruzioni, selezione (IF o CASE), istruzioni ripetitive (WHILE, REPEAT, FOR). C’è un teorema (Bohm - Jacopini) che dimostra addirittura che sarebbero sufficienti la sola sequenza e il WHILE.

La caratteristica di ogni istruzione strutturata è di costituire un blocco con un solo ingresso e una sola uscita. In questo modo è possibile agganciare ad ogni istruzione una precisa proprietà logica come verrà evidenziato nel prossimo paragrafo.

Oltre alle istruzioni di controllo troviamo poi l’assegnazione, con tutte le regole sui tipi esposte precedentemente, e la possibilità di spezzare un programma in moduli attraverso la creazione di funzioni e procedure.

Una procedura è un sottoprogramma, un modulo, una subroutine.

Ogni procedura è in pratica un piccolo programma a se stante, che può avere le proprie sottoprocedure, le proprie variabili locali e che comunica con il programma principale attraverso parametri o variabili globali.

Questa strutturazione a scatole cinesi obbliga a definire le regole di visibilità tra i vari blocchi.

Vediamo con un esempio.

Var

a,b,c:integer; {variabili globali}

Procedure P1;

var i,j:integer; {variabili locali}

begin

a := 0; {zero nell’a globale}

end;

Procedure P2;

Var a,j:integer; {variabili locali}

Procedure P3; {procedura locale}

begin

end;

begin

a := 0; {zero nell’a locale}

end;

begin

i := 0; { ERRATO: variabile non visibile! }

a := "prova" { ERRATO: tipo non compatibile}

P3; { ERRATO: procedura non visibile}

end.

In questo spezzone vediamo come le variabili e le procedure siamo visibili solo nel blocco che le definisce e in quelli in questo contenuti. Se viene seguita una regola di questo tipo, è possibile spezzare il lavoro tra più programmatori senza che i nomi che ognuno sceglie possa "scontrarsi" con il lavoro degli altri.

Ricordiamo il vecchio linguaggio BASIC che non prevedeva questi meccanismi di protezione. Ogni subroutine condivideva le variabili con il programma principale. Se un programmatore faceva un ciclo utilizzando la variabile "I", unendo il lavoro con quello di un altro, se anche questo aveva usato la stessa variabile, capitava che due moduli precedentemente corretti non funzionavano più bene.

Un meccanismo fondamentale è il passaggio dei parametri, che permette di interfacciare moduli diversi. Nel passaggio dei parametri ci sono due metodi fondamentali: per valore e per indirizzo.

Nel primo caso il parametro è una variabile locale della procedura chiamata che viene inizializzata ad un particolare valore.

Nel secondo caso viene passato l’indirizzo a cui associare una variabile locale della procedura chiamata, in modo che questa possa modificare una variabile del programma chiamante.

Var i:integer;

Procedure P1(var a:integer);

begin

a:=0; {assegnazione alla variabile specificata dal programma chiamante}

end;

Procedure P2(a:integer);

begin

a:=0; {assegnazione alla variabile a locale}

end;

begin

i:=1; P1(i); {i ora vale 0, viene modificata da P1}

i:=1; P2(i); {i vale ancora 1, non viene modificata da P2}

end;

In questo esempio vediamo due procedure, scritte con la sintassi Pascal, la prima che ha un parametro passato per indirizzo, la seconda per valore.

Entrambe le procedure assegnano il valore zero al parametro. Nel caso della prima viene effettivamente modificato il valore della variabile globale "i", mentre nel secondo viene modificata solo la variabile locale.

Questo meccanismo permette di creare delle procedure che modificano valori globali senza creare un "interfacciamento" diretto con le variabili interessate.

Ricordiamo come nel capitolo precedente era stata segnalata come pericolosa la pratica di modificare i valori globali da un modulo separato. In effetti cambiando il nome del dato modificato bisogna riscrivere tutti i moduli che vi accedono. Con il meccanismo del passaggio per indirizzo si resta nelle interfacce "buone", pur mantenendo la possibilità di intervento sui dati globali.