Articolo pubblicato sul n. 56 di MCmicrocomputer (Edizioni Technimedia Srl - Roma) nell'ottobre 1986 Linguaggi, istruzioni, parametri Dopo essere violentemente precipitati nei piu' infimi bassifondi di un calcolatore (sino al livello di microprogrammazione) questo mese risaliremo verso gli alti livelli dei moderni linguaggi di programmazione. Tratteremo circa i meccanismi di programmazione offerti da tali linguaggi, tra cui la strutturazione a blocchi, le dichiarazioni, le procedure e le funzioni. Cenni storici Come e' noto, un tempo esistevano solo le macchine nude e crude, e queste potevano essere istruite soltanto a colpi di "volgare" linguaggio macchine. Il primo sforzo per aiutare il povero programmatore a non innervosirsi troppo a furia di numeri esadecimali, fu di inventare l'assember e il macroassembler, col quale era possibile parlare al calcolatore con un linguaggio appena un po' piu' civile: era perlomeno fatto di parole mnemoniche, con la possibilita' di definirsi anche nuove istruzioni a partire da quelle giA' esistenti (le Macro). Subito dopo pero' si sent l'esigenza di mezzi piu' potenti per quel che riguarda le applicazioni scientifiche e in particolare i calcoli piu' complessi delle somme e moltiplicazioni disponibili a livello di CPU. Servivano nuovi strumenti per trattare facilmente le equazioni, i sistemi e le funzioni matematiche in generale: una sorta di programmone che traduceva un linguaggio da un liv1llo piu' alto ad uno piu' basso: nel caso del fortran, da fortran a codice eseguibile dalla CPU. Quasi parallelamente agli ingegneri che protendevano verso le soluzioni meccanizzate dei loro problemi matematici, gli "archivisti" parteggiavano per un linguaggio di programmazione piu' consono alla archiviazione e l'elaborazione automatica dei dati. Per loro nacque il Cobol: COmmon Businers Oriented Language. Siamo ovviamente ancora agli albori dell'informatica: nonostante gli sforzi compiuti, programmare sia in fortran che in cobol qualcosa di non specificatamente previsto dai due linguaggi risultava tanto difficile quanto poteva esserlo per i calcoli il linguaggio macchina. E da quel momento un po' tutti nel mondo si sbizzarrirono a fare linguaggi di programmazione. Nacquero linguaggi per trattare agevolmente le stringhe alfanumeriche (Snobol), liste o in generale oggetti non troppo numerici (LISP), processi e comportamenti di oggetti reali (SIMULA) e altro. L'occhio con cui si guardava la nascita di un nuovo linguaggio di programmazione era comunque la massima comprensibilitA' anche da chi non avesse scritto il programma. Niente meccanismi per fare trucchetti strani, ma solo strumenti tutti puliti per una programmazione semplice e ordinata. Spari' il concetto di sottoprogramma per fare posto alle procedure e alle funzioni: niente gosub e return ma invocazione tramite il nome della stessa e nient'altro. Dei goto manco a parlarne: sono brutti semanticamente e soprattutto un programma zeppo di goto puo' far disperare chi cerca il bug nel proprio elaborato. Grazie a nuovi costrutti di programmazione come l'IF-THEN-ELSE e il WHILE-DO e' stato dimostrato che se ne puo' fare comodamente a meno. Algol-like Il primo linguaggio di programmazione che sfrutto' nuovi costrutti anti-goto e' stato l'algol 60. Si badi bene che per i fissati, il goto era pur sempre disponibile: semplicemente ne era altamente sconsigliato l'uso, anche perche' poteva creare non pochi problemi il saltare da un punto all'altro dato che la programmazione algol e' strutturata. A partire da questo, nacquero in seguito altri linguaggi che si ispiravano all'algol 60: tutta la sua dinastia, comprendente algol 68, algol w, pascal, ada e altri, e' stata cosi' chiamata algol-like (tipo-algol). Algol sta per ALGOLritmic Language, e il suo nome sta a sottolineare il fatto che il modo di programmare corrisponde praticamente ad una definizione precisa dell'algoritmo che stiamo implementando sul computer. Un programma Algol-like e' strutturato a blocchi (vedremo meglio tra poco) ed ogni blocco e' diviso in due parti: la parte dichiarazioni e la parte comandi. Il programma stesso, per intero, e' un blocco: altri blocchi saranno in esso modificati (stile bambole russe) per descrivere l'algoritmo (o scrivere il progamma che e' la stessa cosa). Nella zona dichiaraioni bisogna indicare tutte le variabili usate nel blocco e per oguna di queste il tipo (intero, reale, stringa array o altro) e eventualmente i parametri che occorrono, ad esempio il numero di elementi se e' un array. Le dichiarazioni, oltre a servire per allocare a tempo di compilazione o a tempo di esecuzione lo spazio necessario alle variabili, permettono durante la stesura di un programma di avere sempre sottomano tutta la lista delle variabili giA' usate in modo da non usare in modi diversi lo stesso oggetto. Sempreche' questo e' cio' che desideriamo: infatti la strutturazione a blocchi, unita alla possibilitA' di fare le dichiarazioni in ogni blocco, permette anche il nome di variabile denta due punti del programma, lo stesso nome di variabile denota due oggetti diversi. E' arrivato il momento di fare qualche esempio. Dicevamo che un programma algol-like e' un blocco formato da due parti: dichiarazioni e comandi: Begin lista dichiarazioni lista comandi End Le due parole chiave begin e end delimitano l'inizio e la fine del blocco. Prendiamo ora l'istruzione IF-THEN: la sua sintassi e': IF (condizione) THEN (comando o blocco) Ecco un punto dove possiamo usare un blocco piu' interno del blocco principale. Quasi tutti i comandi sono fatti in questo modo: se c'e' da far fare qualcosa a piu' di una istruzione, basta racchiderle tra begin e end in modo da creare un nuovo blocco (si noti che per i blocchi piu' interni, se non si usano nuove variabili o nuove occorrenze di variabili gia' esistenti, non sono necessarie le dichiarazioni). L'if di cui sopra, se la condizione e' verificata, non ha effetti (come in basic). Ora vedremo la prima delle istruzioni anti goto. Il caso dovrebbe essere ovvio: a seconda di una condizione dobbiamo eseguire un insieme di comandi o un altro, come mostrto nel diagramma a blocchi di figure 1. In un linguaggio di programmazione vecchia maniera, cio' si realizza con almeno un salto, ad esempio in basic avremo: 10 IF A>0 THEN PRINT A: X=X+3: GOTO 30 20 B=A/2: A=A+1 30 ...... lo stesso programma in algol-like si scrive: IF A>0 THEN BEGIN PRINT A X:=X+3 END ELSE BEGIN B:=A/2 A:=A+l END appare evidente come nel secondo caso, una volta chiarita la convenzione che begin ed end delimitano un insieme di operazioni da compiere, il programmino algol-like non e' altro che la descrizione a parole (sebbene in inglese) del procedimento che volevamo descrivere (libera traduzione: se A e' maggiore di zero allora stampa A e ad X associagli il valore di X + 3, altrimenti...ecc. ecc.). Analogamente per il caso in cui dobbiamo eseguire un insieme di istruzioni finche' e' vera una condizione (figura 2). Continuiamo con gli esempi basic: 10 IF A<0 THEN 50 20 PRINT A 30 A=A-1 40 GOTO l0 50 ..... in algol-like scriveremmo un piu' pulito e piu' consono al vero significato: WHILE A>0 DO BEGIN PRINT A A:=A-1 END Esiste pero' anche il caso contrario in cui la condizione e' posta dopo le istruzioni e si desidera ripeterle fino a quando una condizione non si verifica (fig 3). In basic: 10 PRINT A 20 A=A+l 30 IF A<0 THEN 10
in algol-like diventa: REPEAT PRINT A A:=A+l UNTIL A>0 piu' pieno di significato di cosi' si muore. Infine, vorremmo mostrarvi come si implementa il caso in cui, a seconda del valore di una certa espressione bisogna eseguire un determinato pezzo di programma (fig 4). Ad esempio, in basic la situazione potrebbe essere: 20 IF A=3 THEN PRINT A: A=A-1: GOT050 30 IF A=5 THEN A=A-2: GOTO 50 40 IF A=2 THEN A=A+5 50 ......
scritto in un linguaggio algol-like diventa:
CASE A OF
0: PRINT "OK” 3: BEGIN PRINT A A:=A-1 END 5: A:=A-2 2: A:=A+5 Si noti he per il caso 3, dovendo eseguire due comandi e' stato necessario racchiuderli in un blocco begin-end. I blocchi Finora abbiamo visto e usato i blocchi solo per racchiudere piu' istruzioni da eseguire al verificarsi di evento. Dicevamo, pero', che un blocco e' formato anche da una opzionale parte dichiarazioni tramite la quale possiamo definirci nuove variabili locali a quel blocco. Cio' significa essenzialmente due cose: primo al termine del blocco (una volta cioe' incontraro il corrispondente end) tutte le variabili li' dentro dichiarate vengono dealloccate, secondo e' possibile creare una nuova istanza di una variabile che non ha nulla a che spartire (tranne il fatto di avere lo stesso nome) con la corrispondente creata in un blocco piu' esterno. Facciamo un esempio:
BEGIN All'inizio ci sono le due dichiarazioni per X e Y di tipo intero. Segue la loro inizializzazione rispettivamente a 0 e a 100. Incontriamo a questo punto un comando while che fa ciclare il blocco seguente fino a quando X e Y non diventano uguali. Nel blocco del while, dopo aver incrementayo di 1 la X e di egual misura decrementato la Y, se ha raggiunto il valore 10 si passa al blocco del THEN. Qui troviamo troviamo una dichiarazione di nuova istanza per X che viene inizializzata a 25. E' importante notare che dentro a tale blocco la X di fuori non e' accessibile mentre lo e' la Y che e' stata dichiarata nuovamente. La X esterna, che non e' scomparsa, e' solo disattivata, ritornerA' in vita (e col suo valore 10) una volta usciti dal blocco del THEN. Il resto del programma e' ovvio. A questo punto qualcuno si chiedera': "Serve tutto quanto?". Si', come era prevedibile. Noi abbiamo fatto l'esempio di una variable: se manipolavamo matrici di 10000 elementi la differenza sarebbe stata piu' sensibile. Immaginiamo che, per un qualsiasi motivo in un punto di un programma ci servono delle nuove matrici per effettuare delle operazioni locali ad un preciso momento dell'algoritmo. Ipotizziamo ancora che tale necessitA' non sempre si presenta, ma e' funzione dei dati di ingresso,. Dichiarare le matrici ausiliarie nel momento in cui verrA' restituito alla loro deallocazione automayica all'uscita del blocco. Procedure e funzioni Un altro dei meccanismi di programmazione offerto dai linguaggi algol-like e' la definizione delle procedure e delle funzioni. Sono assimilabili a meccanismi di estensione del linguaggio in quanto una procedura puo' essere vista come un nuovo comando cosi' come per le funzioni definibili. Sia l'une che l'altre, una volta definite, vengono usate come normali statemen e funzioni, come se queste fossero proprie del linguaggio. Se ad esempio abbiamo la necessita' di un comando, che presi due argomenti ne calcola la somma e stampa il risultato, possiamo definirci la seguente procedura: PROCEDURE PIPPO (X,Y:INTERO) BEGIN VAR SOMMA: INTERO SOMMA:=X+Y PRINT SOMMA END e da questo momento possiamo usare PIPPO a nostro piacimento, ad esempio PIPPO (4,9), (28*A, J/2) o similmente. X e Y della procedura sono detti parametri formali e effettivamente stanno li' pro forma. Nel senso che servono solo per associare i parametri di ingresso (detti attuali) a qualcosa (i nomi X e Y) che saranno usati all'interno della procedura. Quindi tanto questi, quanto la variabile SOMMA dichiarata all'interno della procedura, una volta terminata l'esecuzione di questa, non esisteranno piu'. Esistono cioe' solo nell'ambiente locale della procedura, che dal canto suo si comporta come un blocco essendo costituita di fatto da un blocco. Analogamente possiamo definirci una funzione che potremo comodamente usare nelle nostre espressioni, come se fosse una funzione offerta direttamente dal linguaggio. A differenza oelle procedure, le funzioni restituiscono un valore e quindi bisogna dichiarare oltre al tipo dei parametri anche il tipo del risultato. Facciamo un esempio: immaginiamo che il nostro linguaggio non dispone della funzione tangente di un angolo, ma solo delle funzioni uguale al seno diviso spesso la tangente non vogliamo ricorrere a scrivere ogni volta seno su coseno. Definiamo la nostra funzione cosi': FUNCTION TAN (X:REAL): REAL BEGIN TAN:=SIN(X)/COS(X) END e potremo usare TAN dove e come vogliamo, naturalmente nel giusto contesto: come espressione che restituice un valore: es. A:=TAN (30), A:= TAN (30) +SIN (45) e cosi' via.
Impaginato originale... Articolo pubblicato su www.digiTANTO.it - per ulteriori informazioni clicca qui |