1.1        SIMULA

Linguaggio generale e di simulazione

SIMULA (SIMUlation LAnguage) ha origine in Norvegia nel 1962 al Norwegian Computing Centre in Oslo, ad opera di Kristen Nygaard, esperto di Ricerca Operativa e di Ole-John Dahal un programmatore con esperienza nella costruzione di compilatori.

1.1.1             SIMULA I

Nel 1957 il Norwegian Computing Centre acquisì un calcolatrore Ferranti MERCURY, sul quale Kristen Nygaard iniziò l’implementazione di un programma di simulazione (Monte Carlo compiler); questa attività indirizzò la sua ricerca verso la formalizzazione della descrizione di sistemi complessi con l’obiettivo di poterli simulare con un computer. 

SIMULA I doveva essere un linguaggio per descrivere dei sistemi (servizi, aeroporti, impianti industriali, …) e per effettuare simulazione, ma durante l’implementazione risultò evidente che esso doveva avere anche le capacità di un linguaggio, ciò portò al coinvolgimento nell’attività di sviluppo di Ole-John Dahal. Nell’agosto del 1962, in occasione della seconda conferenza internazionale sull’Information Processing in Germania a Monaco, SIMULA fu presentato come “un’estensione di ALGOL per la descrizione di reti di eventi discreti”. Il progetto di SIMULA poté svilupparsi grazie ad un accordo con la UNIVAC, interessata a rafforzare l’offerta di ALGOL in alternativa al FORTRAN dell’IBM.

L’idea iniziale era di creare un pecompilatore per ALGOL (1963) per descrivere una rete di servizi attivi (station) attraverso la quale fluiscono dei clienti (customer); ma gli sviluppatori si resero conto che la struttura di ALGOL, in particolare lo stack, non era sufficiente per gli aspetti di simulazione, per cui decisero di modificare un compilatore ALGOL (1964) per adattarlo ai loro scopi.

Il linguaggio, sviluppato su UNIVAC 1107, incontrò un certo successo e fu portato su Borroughs B5500 (1968) e sul sovietico URAL 16 (1967).

SIMULA I ha l’aspetto formale di un programma specializzato, con tipi di dato ed istruzioni ad hoc:

·     customer una lista di clienti con i loro attributi,

I blocchi di programma di SIMULA I, mutuati da ALGOL, sono visti esternamente come operazioni e, se dichiarati come procedure con dati locali accessibili dall’esterno, hanno di fatto alcune caratteristiche degli oggetti.

1.1.2             SIMULA 67

SIMULA I fu utilizzato anche al di fuori dei progetti di simulazione, ciò rese ancor più evidente che la sua evoluzione doveva renderlo un linguaggio di programmazione completo ed in particolare acquisire la capacità di trattare stringhe di caratteri e poter accedere ai file.

Fu deciso di mantenere un’alta compatibilità con AlGOL 60 e nel 1967 iniziò la fase di progettazione e di implementazione con la disponibilità del linguaggio fra 1969 ed il 1972 su CONTROL DATA 3000, UNIVAC 100 e IBM 370.

A differenza di altri linguaggi che hanno avuto una diffusione analoga, SIMULA 67 è rimasto sostanzialmente invariato nel tempo. 

 

numeri e caratteri

booleani

testi

REF

assegnazione

:=

:=

:=

:-

uguale

=

EQV

=

==

diverso

<>

NOT variab EQV

<>

=/=

I tipi di dato sono numeri interi e reali, boolean, caratteri e referenze. Quest’ultime sono di fatto l’indirizzo di un oggetto. SIMULA è bizzarramente semiortogonale per quanto riguarda alcuni operatori sui diversi tipi di dato, come si può notare nella figura a lato.

La struttura dei programmi è a blocchi begin ... end con i dati dichiarati all’interno del blocco non visibili all’esterno del blocco:

begin

  comment starting declarations;

  text array T(1:100);       ! array declarations;

  Integer I;           

  Integer LL = 100;          comment constant declarations;

  ref (InFile) Inf;          ! declaration of file reference;

  ! starting instructions; 

  Inf :- new InFile("IN.TXT");    

  inspect inf do              ! per evitare inf.open, ...;

    begin

      Open(Blanks(LL));      ! open file;

      while not endfile do       

        begin

          I := I + 1;

          InImage;           ! read line in buffer;

          T(I) :- Inf.Image; ! put line in array;

          OutText(T(I));    

        end;

      Close;

    end of inspect;

end of program

Figura 2-24

Si notino le differenti sintassi dei commenti, ! ... ; o comment ...;, obbligatoriamente terminati da ;, ma anche la possibilità di inserire commenti dopo la parola riservata end.

Si possono utilizzare matrici di tutti i tipi di dato, in esse le dimensioni sono implicitamente date indicando il primo e l’ultimo elemento (in realtà sono liste i cui elementi sono accessibili con chiave numerica),  e poiché lo spazio per le variabili è allocato ogni volta che il blocco è attivato, si possono indicare matrici i cui limiti dipendono da variabili esterne al blocco e dunque ottenere una certa dinamicità.

L’istruzione condizionale è l’usuale if espressione then ... else, in cui espressione può contenere gli operatori logici not, and, or, impl e eqv, e anche and then e or else il cui effetto è di evitare la valutazione di entrambe le espressioni in and o or, quando non è necessario (short circuit).

Interessante è l’utilizzo delle espressioni condizionali nell’assegnazione: 

i:= inint; ! chiede un numero;

outtext(if mod(i, 2) = 0 then "pari" else "dispari");

Esiste il while condizione do ... ed il for variabile := espressione step ... until ... do ..., questo ha un’utile variante per eseguire le iterazioni per insieme di valori, ad esempio:

for pcard := "nord","sud","est","ovest" do outtext(pcard);

E’ presente anche una sorta di struttura case, il comando inspect oggetto do ... limitato agli oggetti con scopo principale di omettere il qualificatore oggetto all’interno del blocco (vedi esempio in Figura 2-24 ) e in cui opzionalmente sono accettate clausole when e otherwise.

Funzioni, procedure e class, gli oggetti nella terminologia di SIMULA, sono blocchi con un nome e con l’indicazione dei parametri, le funzioni si differenziano dalle procedure, in quanto sono prefissate col tipo di dati che restituiscono ed il nome della funzione è il nome della variabile contenente il valore calcolato. Le variabili sono passate per valore (VALUE) riferimento (REF) o nome (NAME), quest’ultima forma permette alle variabili di essere modificate dalla procedura.

Le procedure di ALGOL furono lo strumento per trasformare le activity di SIMULA I in classi di oggetti, questo salto concettuale fu favorito dall’osservazione che esistono processi che hanno delle proprietà comuni e, se realizzati come oggetti, possono essere usati per costruire degli oggetti derivati (ereditarietà), l’ereditarieà si ottiene prefissando il nome della classe con la classe da cui si vuole ereditare.

Una delle conseguenze formali dell’introduzione degli oggetti è che stringhe, input/output e liste sono implementati come oggetti. La sintassi per creare un’istanza di un oggetto, class è ridondante, si veda l’esempio di Figura 2-24 applicata ad un file in lettura in cui è necessario:

·         dichiarare una variabile per il riferimento ad un oggetto della classe InFile,

·         creare un oggetto InFile,

·         utilizzare del file.

La gestione dei file è comunque macchinosa: in input occorre alimentare il buffer tramite InImage, prima di poter assegnarne il contenuto ad una variabile testo; in output si hanno procedure per scrivere testi (OutText), numeri (OutInt e OutFix), caratteri (OutChar)e ritorno a capo (OutImage).

Le stringhe, devono essere allocate tramite le procedure copy(testo) o blanks(quantità), ed hanno proprietà quali variab.length, variab.pos (pointer per accedere all’interno della stringa) e metodi o funzioni fra cui variab.setpos, variab.getchar, variab.putchar(char) e variab.sub(da, lungo).

Una innovazione di SIMULA fu il parallelismo di esecuzione delle procedure, in realtà uno pseudo parallelismo controllato dalle istruzioni detach e resume che trasformano una procedura in una coroutine, i cui punti di uscita (e il successivo rientro) sono detach e resume. Il programma sottostante è un gioco in cui i due giocatori cercano di occupare porzioni di un’area o di liberarle dall’avversario, in particolare le istruzioni players(n) :- NEW play(n); creano un’istanza della coroutine che viene eseguita fino all’istruzione detach permettendo l’inizializzazione della situazione del giocatore n-esimo, RESUME(players(1)); fa inizia il il gioco). .

! cim-3.33-i586-pc-cygwin ;

!     gioco occupa e distruggi ;

begin

  text digit,Area;                 ! Area da occupare;

  integer seed;                    ! per numeri random;

  REF(play) ARRAY players(1:2);    

  CLASS play(who); Integer who;

  begin

  character Procedure convert(n); integer n;   

    begin

      digit.SetPos(n+1);

      convert := digit.GetChar;          ! converte digit in carattere;

    end; 

  Procedure HoldDestroy (n,flag,occupa);    

    integer n,flag; boolean occupa;

    comment Occupa o distrugge postazione;   

    begin

      Area.SetPos(n);        ! posiziono sul byte n ;

      if occupa and Area.Sub(n,1) = " " then

          Area.PutChar(convert(flag))

        else

          begin

            if not occupa then Area.PutChar(' ') end; 

  end++of++HoldDestroy;

  begin       

      integer I,J;

      Integer ARRAY player(1:100);

      boolean occupa;        ! variabile occupare/distruggere;

      ! riempe Matrice con gli n numeri da 1 ad n in ordine casuale; 

      For I := 1 step 1 until 100 do

        begin

          J := RandINT(1,100,seed);

          while player(J) <> 0 do J:= RandINt(1,100,seed);

          player(J) := I;        

        end;  

      DETACH;                ! serve ad inizializzare;

      FOR I := 1 step 1 until 100 do

        begin

          occupa := Draw(1-I/100,seed);

          HoldDestroy(player(I),who,occupa);

          RESUME(players(MOD(who,2)+1)); ! tocca a te;

        end;

   end;    

 end++of++class;

   begin

     Integer I,J,N;     

     digit :- COPY("0123456789");

     seed := clocktime;

     Area :- Blanks(100);    ! Campo di battaglia ;     

     players(1) :- NEW play(1);

     players(2) :- NEW play(2);

     RESUME(players(1));     ! fa ripartire il gioco;

     outtext(Area); Outimage;

     For I := 1 step 1 until Area.length do

       begin

         if Area.Sub(I,1) = "1" then J := J + 1;

         if Area.Sub(I,1) = "2" then N := N + 1;

       end;

    outtext("Giocatore 1: "); Outint(J,2); Outimage;

    outtext("Giocatore 2: "); Outint(N,2); Outimage;

  end;   

end

Figura 2-25

L’esecuzione del gioco è riportata in Figura 2-26 .

    211     12    1     2 1         2    1  1  1  21   22  21  111 2 21 2 2

  2   112 1 1   2  2

Giocatore 1: 18

Giocatore 2: 16

Figura 2-26

SIMULA 67 è ritenuto, riduttivamente, un linguaggio di simulazione; in realtà è un linguaggio generale che tramite delle funzioni native per generare numeri a caso, con diverse distribuzioni di probabilità, e le istruzioni detach e resume per gestire coroutines, permette di fare della simulazione; tuttavia la creazione di simulazioni diventa un’attività molto semplice ed elegante se si utilizzano le due classi predefinite SIMSET e SIMULATION. La prima fornisce proprietà e metodi per gestire delle liste, la seconda è una sottoclasse di SIMSET, che ha proprietà, metodi e sottoclassi che, senza svincolare del tutto la realizzazione di una simulazione dal come implementarla, permetteno di concentrarsi su cosa si vuol ottenere. SIMULATION gestisce la coda degli eventi ordinata su base temporale tramite l’utilizzo di detach e resume,  la funzione time fornisce l’ora dell’evento.

Gli elementi che entrano in causa in una simulazione sono realizzati come classi che ereditano dalla classe process di SIMULATION una serie di attributi e metodi, in particolare i metodi activate per attivare un processo, hold(durata), per simulare una durata e rischedulare il processo al tempo opportuno.

Nel listato sottostante è riportata la simulazione di uno sportello che eroga servizi, con attivazione e disattivazione di un secondo sportello per gestire le punte di servizio). .

! cim-3.33-i586-pc-cygwin ;

! queue simulation;

Simulation begin

  Integer U;                 ! seed for random generators;

  REF(head) Q;               ! queue;

  Integer LevelHigh = 20,LevelLow = 10;  ! for second server;

  procedure signal(What); NAME What; boolean What;

    begin

      OutText(if What then "deactivate" else "activate");

      OutText(" second server at "); outint(time, -6);

      OutText("whit ");OutInt(Q.cardinal,3);OutText(" clients");

      outimage;

      What := not What;   

    end;

  process class client;

    begin

      REF(client) customer;

      while true do begin

        customer :- new client;                              

        customer.into(Q);

        HOLD(negexp(1/5, U)) ! negative exponential distribution;

      end;        

    end; 

  process class server;

    begin

      while true do begin

        if not Q.empty then begin

          Q.first.out;

          hold(uniform(1,10, U));  ! uniform distribution;

        end;

        hold(1);

      end; 

    end;    

  process class wizard();

    begin boolean secondserver;    ! boolean are initialized at false;

      REF(server) secondsrv;

      while TRUE do begin

        if Q.cardinal > LevelHigh and then not secondserver then begin

          secondsrv :- new server;

          activate secondsrv;

          signal(secondserver);  

        end;   

        if Q.cardinal < LevelLow and then secondserver then begin

          cancel(secondsrv);

          signal(secondserver);           

        end;

        hold(1);

      end;

    end;

   Q :- new head;

   outtext("Simulation start..."); outimage;

   U := clocktime;           ! for random seed;

   activate new client;  

   activate new wizard;

   activate new server;

   hold(2000);          ! simulation running time;

   outtext("Simulation end");

end

Segue il risultato della simulazione.

C:\Simula\bin>coda

Simulation start...

activate second server at 225   whit  21 clients

deactivate second server at 320   whit   9 clients

activate second server at 448   whit  20 clients

deactivate second server at 506   whit   9 clients

activate second server at 1130  whit  20 clients

deactivate second server at 1211  whit   9 clients

activate second server at 1511  whit  20 clients

deactivate second server at 1674  whit   9 clients

activate second server at 1881  whit  20 clients

deactivate second server at 1971  whit   9 clients

Simulation end

Figura 2 -27