1.1        REBOL

Linguaggio di scripting

REBOL (Relative Expression-Based Object Language) nasce nel 1997 ad opera di Carl Sassenrath, attivo nel campo dei sistemi operativi (Amiga Multitasking Operating System) e dello sviluppo dei linguaggi.

Secondo la definizione dell’autore, REBOL si basa sul passaggio di messaggi e sulla possibilità di creare dei “dialetti” per scopi particolari.

Il linguaggio è interpretato ed è disponibile su un’ampia piattaforma di Sistemi Operativi. REBOL possiede un’enormità di tipi di dato (45), ciò gli da una ampia flessibilità per interagire con INTERNET, il suo utilizzo principale. Oltre a stringhe di caratteri, numeri, date, importi, sono presenti tipi quali indirizzi e-mail, URL e TAG HTML ed  inoltre i nomi di file, individuati dal prefisso %, le tuple, sequenze di numeri interi da 0 a 255, separati da . (127.0.0.1), le coppie, due numeri interi separati da x (1024x800).

La struttura principale di REBOL sono le serie, appartengono alle serie anche alcuni tipi di dato, quali stringhe ed indirizzi e-mail. Un particolare tipo di serie sono i blocks, questi sono delimitati da [] e possono contenere qualsiasi tipo di dato o variabile, ma anche parole, che non sono né variabili né costanti, e programmi; le parole assumono in pratica la funzione di identificatori dei valori che le seguono. I blocchi di istruzioni sono eseguibili tramite i comandi do o reduce, nell’esempio seguente il blocco p contiene la dichiarazione di una funzione e le istruzioni: :

p: [fatt: func [i] [either i = 1 [1] [i * fatt (i - 1)]]

    prin "immettere numero "

    n: to-integer input

    fatt n]

>> do p

immettere numero 10

== 3628800

>> è il prompt della console dell’interprete REBOL; come si può notare dall’esempio l’assegnazione ha la forma variabile: espressione, func precede il blocco dei parametri ed il blocco con il corpo della funzione (ricorsiva).

Le serie, sono manipolabili con un insieme, pletorico, di funzioni: per modificare (insert, append, remove, ...), estrarre (pick, /n, copy/part, first, second, third, fourth, fifth, last), trattarle come insiemi (unique, intersect, union, intersect, difference), ordinarle e percorrerle (next, skip, foreach,...). Una caratteristica interessante dei blocchi è l’individuazione dei dati contenuti tramite cammini o path, utile per costruire delle semplice banche dati:

ind: [ email 

         [ bellecombe ross@libero.it

           anna anna@condor.bmp ]

       sito

         [ repubblica www.repubblica.it

           libero www.libero.it

           bellecombe http://bellecombe.t ]

      ]    

>> print ind/siti/repubblica

www.repubblica.it

>> print ind/email/anna

anna@condor.bmp

>>

I blocchi naturalmente sono utilizzabili come array, ma nonostante la varietà di funzioni, è macchinoso modificare un elemento che dipende da una variabile:

poke qs i (pick qs i) + 1      ; incrementa

mentre accedere ad una posizione fissa è semplicemente: qs/2: qs/2 + 1

n: to-integer input

p: [print "ora errata"]

if (n < 0) or (n > 23) p

if any [n < 0 n > 23] p

REBOL è uno dei pochi linguaggi che sintatticamente differenzia le espressioni condizionali: if condizione [istruzioni] e either condizione [istruzioni] [istruzioni], la condizione può essere formata da più condizioni connesse con operatori logici, inoltre l’or o l’and di condizioni può essere abbreviato rispettivamente da any ed all. if ed either sono funzioni, che ritornano il risultato dell’esecuzione del programma contenuto nel blocco.

REBOL non ha parole riservate, ciò rende possibile ridefinire anche i comandi, ed ha una semplice struttura sintattica: nelle espressioni non ci sono precedenze fra gli operatori che devono essere spaziati dagli operandi. Molte istruzioni ammettono dei parametri sotto forma di refinements, separati dal comando tramite il carattere /, ad esempio read/binary %nomefile, write/append %nomefile dati.

REBOL gestisce in maniera semplice gli oggetti, non esistono classi ma solo oggetti creati e cloni di questi. La sintassi è semplice:

nomeoggetto: make object! [dati e codice]

nomeoggetto: make oggettoesistente [eventuali dati e codice]

Vi sono diverse istruzioni di controllo dei cicli: loop n, repeat variabile n e for variabile inizio fine passo, e di scorrimento di serie: foreach (foerach variabile nomeblocco [istruzioni]), forall, forever.

Fra while ed until vi è una piccola incongruenza, mentre in while il blocco con la condizione controlla il successivo blocco di istruzioni, in until il blocco di istruzioni è eseguito almeno una volta ed è rieseguito se l’ultima istruzione contenuta è una condizione soddisfatta.

REBOL consente l’utilizzo di librerie esterne, tuttavia le sue estensioni, GUI, protocolli INTERNET, parsificazione, ecc. sono funzioni ed oggetti di REBOL detti, nella sua terminologia, dialetti. Un esempio significativo sono le interfacce grafiche e la gestione degli eventi ad esse collegati: le funzioni view e layout, gestiscono la presentazione ed a molti oggetti è immediatamente associabile un gestore dell’evento principale. Gli oggetti possono essere disposti automaticamente, o posizionati tramite una serie di modificatori (return, below, across, pad, offset, origin,…); anche l’aspetto degli oggetti è controllato da svariati attributi ed il dialetto draw permette di aggiungere elementi grafici alle finestre. Una gestione più sofisticata degli eventi si ottiene tramite le funzioni redraw, over, engage e detect.

L’esempio sottostante è una simulazione di traffico di un semaforo a due vie .

Copyright 2000-2001 REBOL Technologies.  All rights reserved.

REBOL is a trademark of REBOL Technologies. WWW.REBOL.COM

REBOL [Title: "Junction Traffic Simulation"  Date: 8-jul-2004

       Author: "El Condor" eMail: rossati@libero.it

       Web: http://digilander.libero.it/bellecombe/]

DEC: :to-decimal        ; function synonim

Simulation: func [RunTime t1 t2] [

statistics: func []

  [print ["Last arrived at " lastcar]

   print ["Last departed at:" Timer - 1]

   print ["Stret1 cars: " cs1] print ["Stret2 cars: " cs2]

   print ["End Simulation"]]

VerifySem: func[res qgreen qred]   ; for semaphor handling

  [if res = 0 [return True]

   if opt/data               ; optimasing

      [if (qgreen = 0) and   ; no cars on green street

          (qred > 0) and           ; cars waiting

          (res < 10) [print ["Change semaphore in advance of" Res]

          return true]]]          

e: power 10 (1 / Log-e 10 )  ; base for natural logarithms

Poisson: func [t]       ; t is means time from cars arrival

   [lambda: 0 - (1 / t)

    p: (power e lambda) * (0 - lambda)               ; probab. 1 event

    p: p + ((power e lambda) * lambda * lambda / 2)  ; probab. 2 event

    if (to-integer (100 *  p)) >= (random 100) [return true]]

STG: copy []                 ; block of green time Streets

STG: append STG (DEC sm1/text)

STG: append STG (DEC sm2/text)

qs: copy [0 0]               ; queue counters

cs1: cs2: lastcar: 0         ; some others counters

CountSem: 0                  ; downcounter of green semaphore

Sem: 1                       ; number of green Semaphore

random/seed 0                ; impose same sample

twait: DEC st/text           ; speed of simulation 1 = real time

Timer: 0

forever

     [graphStreet qs         ; graphical image of strets

      if ((qs/1 + qs/2) = 0) and (Timer > RunTime) [statistics break]

      counter/text: Timer show counter

      if VerifySem CountSem pick qs (sem + 1) pick qs ((sem xor 1) + 1)

         [Sem: Sem xor 1           ; Sw semaphore

          graphSem Sem             ; graphical change semaphore

          CountSem: pick STG (Sem + 1)]

      if Timer <= RunTime [

      ; to see if car is arriving now

      if (Poisson t1) [qs/1: qs/1 + 1

                       cs1: cs1 + 1

                       lastcar: Timer] ; a car a car

        if (Poisson t2) [qs/2: qs/2 + 1

                         cs2: cs2 + 1

                         lastcar: Timer]] ; a car a car

      graphStreet qs         ; graphical image of strets                         

      if (pick qs (sem + 1)) > 0

        [poke qs (sem + 1) (pick qs (sem + 1)) - 1] ; remove from green queue        

      wait twait

      CountSem: CountSem  - 1

      Timer: Timer + 1]

]

graphSem: func [Sem]         ; graphic

          [either (Sem = 0) [Street1/color: green Street2/color: red]

                              [Street2/color: green Street1/color: red]

            Street1/text: copy "" show Street1

            Street2/text: copy "" show Street2]

graphStreet: func [qs]       ; graphic on the street

             [Street1/text: gencars qs/1

              Street2/text: gencars qs/2

              show Street1 show Street2]

gencars: function [q] [q1]

             [q1: copy ""

              for i 1 q 1 [q1: join q1 "O"]

              return q1]             

view layout [

    style lab label 200 right      ; style for labels

    backdrop silver                ; background color

    across origin 5x5

    text black bold "Go" #"^g"           ; it's easy make a menu

         [simulation DEC RunTime/text DEC t1/text DEC t2/text]

    text black bold "Info" #"^e"

         [view/new layout

               [label "For the cars arrival I adopted the probability" below

                label "under Poisson distribution e.g. the probability" below

                label "of one arrival plus the probability of two arrivals." below

                label "I apologize if this is not correct."]]

    text black bold "End" #"^e"

         [view layout [label "see you later"] exit]                

    counter: h3 red 40x20 right "0" ; counter

    below h2 "All time in seconds " center olive font-size 16

    across

    lab "Running Time:" RunTime: field "100" 100 return

    lab "Street 1 green Semaphore time:" sm1: field "20" 100 return

    lab "Street 1 average car arival time:" t1: field "3" 100 return

    lab "Street 2 green Semaphore time:" sm2: field "30" 100 return

    lab "Street 2 average car arival time:" t2: field "2" 100 return

    lab "Speedy simulation time:" st: field "0.15" 100 return

    lab "Optimisation RunTime:" opt: check return

    pad 30    Street1: box green 250x20 right font-name "courier new"

    pad -6x20 Street2: box red 20x250 top font-name "courier new"]

Nella Figura 2-22 un esempio di esecuzione dello script precedente.

Last arrived at  98

Last departed at: 107

Stret1 cars:  29

Stret2 cars:  41

End Simulation

Figura 2 - 22