Pascal ha origine dal travagliato cammino di progettazione dell’ ALGOL. Nel 1965, nel comitato per lo standard di ALGOL, si contrapposero due proposte, riconducibili a Wirth e a Wijngaarden rispettivamente. La proposta di Wirth, più pragmatica, fu implementata con nome ALGOL W nel 1966 su IBM 360. Wirth decise poi di proseguire nel disegno di un linguaggio generalizzato, “senza le pesanti restrizioni imposte dalla necessità di trovare un accordo fra due dozzine di esperti su ogni più piccolo dettaglio”[1]. Ciò fu possibile nel 1968 quando divenne professore a Zurigo presso l’ ETH. sul cui calcolatore, CDC 6000, erano disponibili Assembler, FORTRAN e un ALGOL “piuttosto poveramente disegnato”[2]. Ritenendo questi strumenti inadatti per l’insegnamento della programmazione, Wirth iniziò lo sviluppo di Pascal (tramite FORTRAN e successivamente in PASCAL stesso). Il nome è un omaggio a Blaise Pascal (Clermont 1623, Parigi 1662) filosofo e matematico che costruì la prima macchina addizionatrice meccanica.
In confronto ad ALGOL, PASCAL ha più tipi di dato e più strutture e in particolare offre al programmatore la possibilità di definire propri tipi e strutture.
Il primo compilatore e la definizione del linguaggio sono del 1970, ed essendo la prima versione non efficiente, fu realizzato un compilatore di un sottoinsieme del linguaggio, PASCAL-S, più adatto per gli scopi didattici e di cui fu distribuito anche il sorgente.
La richiesta di poter disporre di PASCAL da parte di università, spesso con calcolatori diversi da quelli su cui esso era disponibile, favorì la realizzazione nel 1973, di una versione migliorata di PASCAL e la generazione del programma in un codice intermedio detto P-CODE; ciò permise di eseguire programmi PASCAL su macchine senza compilatore, ma dotate di un P-interprete.
Nel 1975 K. Bowles dell’università della California a S. Diego (UCSD), sfruttando la facile portabilità del P-CODE, realizzò il compilatore per una serie di microcomputer (INTEL 8080, DEC LSI 11, Rockwell 6502), corredato di editor, debugger e file system; quest’ambiente di sviluppo è conosciuto col nome di PASCAL UCSD. Nel 1978 esistevano circa 80 implementazioni di PASCAL, dai microprocessori ai supercomputer quale Cray-1. Tale diffusione favorì la nascita di due comitati di standardizzazione, che naturalmente portarono a divergenze, in particolare circa gli array dinamici. Lo standard IEEE è del 1981, lo standard ANSI è del 1982 e quello ISO è del 1983. Il successo in ambito accademico deriva dalla natura del linguaggio, che guida il programmatore a progettare accuratamente il lavoro.
Furono sviluppate, inoltre, diverse varianti commerciali di PASCAL, fra cui Turbo Pascal e Delphi (Kylix in LINUX) l’evoluzione in ambiente grafico basata su Object Pascal.
PASCAL ha avuto una grande influenza sullo sviluppo di una serie di linguaggi che ad esso si richiamano, fra questi il Concurrent PASCAL (Brinch Hansen 1975) un sottoinsieme di PASCAL per trattare processi concorrenti, Pascal Plus (Welsh, Elder 1984) per la simulazione di eventi discreti, Mesa (Mitchell 1978), Euclid (London 1978), Modula-2 (Whirt 1982), Object Pascal (Tesler 1985).
I programmi PASCAL sono strutturati alquanto rigidamente, sia per l’ambizione di costruire compilatori con un solo passaggio, sia per ottenere una maggior correttezza intrinseca: deve essere presente il nome del programma o del modulo, seguono le parti o sezioni che individuano le risorse esterne al sorgente e le dichiarazioni di variabili, costanti, tipi e label utilizzate nel programma, infine la sezione delle istruzioni racchiusa fra begin ... end, con un uso variegato della punteggiatura.
PROGRAM nomeprogramma; |
Program ProvaPolare; |
Sezione importazioni |
uses polare; |
Sezione dichiarazioni |
Var C,X,Z : Complex; |
BEGIN |
begin |
Sezione istruzioni |
randomize; C := GenPolar(10 * random, 2 * pi * random); X := GenPolar(10 * random, 2 * pi * random); writeln('C: ', WritePolar(C),' X: ',
WritePolar(X)); Z :=
C + X; writeln('C + X = Z = ', WritePolar(Z)); writeln('Distanza fra C e 2Z: ', Distanza(C,2.0*Z):5:2); if C > X then writeln('C > X') else writeln('C non >
X'); |
END. |
end. |
Figura 20 Struttura di un programma PASCAL
Le librerie di PASCAL sono dette unit o module e sono strutturate in modo analogo ai programmi. Esistono numerose librerie che coprono varie esigenze. L’utilizzo delle librerie avviene tramite la clausola uses nella sezione importazioni.
|
{gpc version 20001101, based on 2.95.2 19991024 (release)} |
UNIT nomeprogramma; |
unit polare; |
INTERFACE |
interface |
Sezione importazioni |
|
Sezione interfaccie |
type polar = record ro : real; fi : real; end; var Zeropolar : polar; function Genpolar(x, y : real) : polar; function Distanza(w, z : polar) : real; function Writepolar(c : polar) : string; operator + (w, z : polar) c : polar; operator * (z1, z2 : polar) c : polar; operator * (z: polar; re : real) c : polar; operator * (re : real; z: polar) c : polar; operator > (z1, z2 : polar) c : boolean; |
IMPLEMENTATION |
Implementation |
Sezione
implementazioni |
function Genpolar(x, y : real) : polar; var C:polar; begin C.ro := x; C.fi := y; Genpolar := C; end; function Distanza(w, z : polar) re: real; var X,Y: real; begin X := w.ro*cos(w.fi) - z.ro*cos(z.fi); Y := w.ro*sin(z.fi) -
z.ro*sin(z.fi); re :=
sqrt(X**2 + Y**2); end; function Writepolar(c : polar) : string; var s: string[18]; begin Writestr(s,'(', c.ro:7:3,
(c.fi*180/pi):4:0, "\370)"); Writepolar := s; end; operator + (w, z : polar) c : polar; var X,Y: real; begin X := w.ro*cos(w.fi) +
z.ro*cos(z.fi); Y := w.ro*sin(w.fi) +
z.ro*sin(z.fi); c.ro
:= sqrt(X**2 + Y**2); c.fi := pi/2; if X <> 0 then c.fi :=
ArcTan(Y/X); else if Y < 0 then c.fi
:= -pi/2; end; operator * (z1, z2 : polar) c : polar; begin c.ro := z1.ro*z2.ro; c.fi := z1.fi + z2.fi; end; operator * (re : real; z: polar) c : polar; begin c.ro := z.ro*re; c.fi := z.fi; end; operator > (z1, z2 : polar) c : boolean; begin if z1.ro > z2.ro then return true else return false; end; |
Sezione inizializzazioni |
begin Zeropolar := Genpolar(0,0); end. |
C:\fsf\pascal>prpolare C: ( 8.138 67°) X: (
1.049 351°) C + X = Z = (
8.458 60°) Distanza
fra C e 2Z: 9.25 C
> X C:\fsf\pascal>prpolare C: ( 4.752
202°) X: ( 5.041 127°) C + X = Z = (
7.761 -17°) Distanza
fra C e 2Z: 19.51 C non > X |
Figura 21 Struttura di una unit PASCAL
Nei sorgenti di Figura 20 e di Figura 21, si ha un esempio di dichiarazioni del tipo utente polar
“coordinate polari”, con alcune operazioni definite su questo tipo di dato, in particolare gli operatori
+ e * di somma e prodotto sono stati sovraccaricati (operator overloading) per utilizzare il tipo
polar nelle usuali operazioni algebriche. Si noti che l’operatore prodotto è stato sovraccaricato
due volte per permettere il prodotto fra due numeri polar e fra un numero reale ed uno polar
(ma non fra un numero polar ed uno reale). Qui di fianco c’è un esempio di esecuzione del programma.
I tipi di dato di PASCAL
comprendono vari tipi numerici, stringhe, enumerazioni, matrici, records,
pointers, insiemi, e combinazioni di essi anche piuttosto evolute, ad
esempio è possibile definire dei record
con parti una parte variabile.
{gpc version 20001101, based on 2.95.2
19991024 (release)} program VarRecord; Type Lang = record nome: string[30]; anno: integer; case disponibile: boolean
of true: (OS: string[10]); end; var Langx: array[1..3] of Lang; n: integer; Procedure Stampa (langage: Lang); begin write(langage.anno,' '
,langage.nome); if langage.disponibile then
write(' ',langage.OS); writeln(''); end; begin with Langx[1] do begin nome := 'PROLOG'; anno := 1970; disponibile := true; OS := 'WINDOWS' end; Langx[2].nome := 'ALGOL'; Langx[2].anno := 1960; Langx[2].disponibile := false; Langx[3].nome := 'PASCAL'; Langx[3].anno := 1970; Langx[3].OS := 'DOS'; Langx[3].disponibile := true; for n := 1 to 3 do
Stampa(Langx[n]); end. |
Output del programma 1970 PROLOG WINDOWS 1960 ALGOL 1970 PASCAL DOS |
Figura 22
Il listato che segue è un programma generato da RIGAL (v. par. 1.6.7), utilizzato per compilare un frammento di FLOW-MATIC (v. par. 2.22).
{Turbo Pascal - Version
5.5 Copyright (c) 1983, 1989 by
Borland International, Inc.} Program FLOWMATIC; type rec=record key: array[1..4] of char; Cust_code_no: array[1..12] of
char; crlf: array[1..2] of char; end; function iff(str1, str2: string): longint; begin iff := -1; if str1 = str2 then iff:=0; if str1 > str2 then
iff:=1; end; var NumRec : integer; {NumRec = 0 e' fine file} Ris : longint; {Ris = -1, 0, +1 risultato confronto} A : Rec; FlA : File; B : Rec; FlB : File; C : Rec; FlC : File; D : Rec; FlD : File; Label Lab2, Lab5, Lab8, Lab10,
Lab13, Lab1; Begin {INPUT} Assign (FlA, 'FILE_A'); Reset (flA, SizeOf(A)); Assign (FlB, 'FILE_B'); Reset (flB, SizeOf(B)); Assign (FlC, 'FILE_C'); Reset (flC, SizeOf(C)); Assign (FlD, 'FILE_D'); Rewrite (flD, SizeOf(D)); blockread (flA, A, 1,
NumRec); blockread (flB, B, 1,
NumRec); blockread (flC, C, 1,
NumRec); Lab1: {SELECT_LEAST} if A.key <= B.key then if
A.key <= C.key then Goto Lab2; if B.key <= A.key then if
B.key <= C.key then Goto Lab5; if C.key <= A.key then if
C.key <= B.key then Goto Lab8; Lab2: {TRANSFR_ITEM} D := A; {READ_ITEM} blockread (flA, A, 1,
NumRec); if NumRec = 0 then begin FillChar(A, SizeOf(A),
'Z'); Goto Lab10; end; {JUMP} Goto Lab10; Lab5: {TRANSFR_ITEM} D := B; {READ_ITEM} blockread (flB, B, 1,
NumRec); if NumRec = 0 then begin FillChar(B, SizeOf(B),
'Z'); Goto Lab10; end; {JUMP} Goto Lab10; Lab8: {TRANSFR_ITEM} D := C; {READ_ITEM} blockread (flC, C, 1,
NumRec); if NumRec = 0 then begin FillChar(C, SizeOf(C),
'Z'); Goto Lab10; end; Lab10: {TEST} ris := iff(D.CUST_CODE_NO,
'ZZZZZZZZZZZZ'); if ris = 0 then Goto Lab13; {WRITE_ITEM} blockwrite (flD, D, 1); {JUMP} Goto Lab1; Lab13: {CLOSE_OUT} close (flD); {STOP} exit; End. |
Figura 23