PASCAL

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

 



[1] Intervento di Niklaus Wirth in [BJ] pag.98.

[2] ibidem pag. 98.