# Linguaggio Aseba

Questa documentazione è anche disponibile in Aseba Studio nell'item di menu `Help->Language`. Quando si utilizzano parole tecniche, queste sono collegate ai corrispondenti articoli di Wikipedia, in Italiano dove disponibili, oppure in Inglese. Si consiglia di leggere prima la pagina relativa ai concetti di base di Aseba. Questa documentazione presenta il linguaggio com'è a partire dalla versione 1.2 di Aseba. Per versioni più vecchie leggere questa pagina.

Il linguaggio di Aseba assomiglia a quello di Matlab (un linguaggio comune di programmazione scientifica); questa somiglianza consente agli sviluppatori con una conoscenza precedente di qualche linguaggio di scripting di trovarsi velocemente a proprio agio con Aseba e quindi abbassare la curva di apprendimento. Semanticamente, è un semplice linguaggio di programmazione imperativo con un singolo tipo di dato (intero a 16 bit con segno ) e arrays. Questa semplicità consente agli sviluppatori di programmare comportamenti senza una precedente conoscenza di un sistema dei tipi, essendo gli interi il più naturale tipo di variabile e molto indicato per programmare robot basati su microcontrollori.

# Commenti

I commenti consento di aggiungere nel codice delle informazioni testuali che vengono ignorate dal compilatore. I commenti sono molto utili per annotare il codice con informazioni comprensibili dall'essere umano o per disabilitare temporaneamente dei pezzi di codice.I commenti iniziano con # e termiano alla fine della linea.

Esempio

    # Questo è un commento
    var b # un altro commento

Sono anche possibili commenti su più linee. Essi iniziano con #* e terminano con *#.

Esempio:

    #*
    Questo è un commento
    su più linee
    *#
    var b # semplice commento

# Scalari

I valori scalari sono utilizzati in Aseba per rappresentare in umeri. Essi possono essere utilizzati in qualsiasi espressione, come l'inizializzazione di variabili, espressioni matematiche o condizioni logiche.

## Notazione

Gli scalari possono essere rappresentati utilizzando varie basi. Il modo più naturale è il sistema numerico decimale, usando cifre da 0 a 9. I numeri negativi sono dichiarati utilizzando il segno meno `-` di fronte al numero.

Esempio:

    i = 42
    i = 31415
    i = -7

Possono essere anche utilizzati numeri binari e esadecimali. I numeri binari sono prefissati da `0b`, mentre i numeri esadecimali sono prefissati da `0x`.

Esempio

    # notazione binaria
    i = 0b110         # i = 6
    i = 0b11111111    # i = 255

    # notazione esadecimale
    i = 0x10    # i = 16
    i = 0xff    # i = 255

# Variabili

Le variabili si riferiscono sia singoli valori scalari o array di valori scalari. I valori sono compresi tra -32768 e 32767, che è l'intervallo di validità per gli interi a 16 bit con segno. E' necessario dichiarare tutte le variabili definite dall'utente, utilizzando la parola chiave `var` all'inizio di uno script Aseba, prima di fare qualsiasi elaborazione.

Il nome delle variabili è definito secondo queste semplici regole:

- Il nome può solo contenere caratteri alfabetici maiuscoli o minuscoli ed i caratteri '_' o '.'
- Il nome deve iniziare con un carattere alfabetico valido, oppure con '_'
- Il nome è sensibile alle maiuscole o minuscole: una variabile con nome "foo" è differente da un'altra chiamata "Foo"
- Il nome non può coincidere con una parola chiave Aseba (vedere l'elenco delle parole chiave riservate)

Le Variabili possono essere inizializzate nella dichiarazioni, utilizzando il simbolo di assegnazione in combinazione con qualsiasi espressione matematica valida.
Una variabile non precedentemente inizializzata può contenere qualsiasi valore. Non si deve mai assumere che una variabile non inizializzata abbia valore zero.

Esempio:

    var a
    var b = 0
    var c = 2*a + b        # attenzione: 'a' non viene inizializzata

## Parole chiave riservate

Le seguenti parole chiave non possono essere utilizzate come nomi validi per variabili, perchè sono già utilizzate dal linguaggio Aseba.

Parole chiave
abs | call | callsub | do
else | elseif | emit | end
for | if | in | onevent
return | step | sub | then
var | when | while |

## Costanti

In Aseba Studio si possono definire delle costanti utilizzando il pannello "Constants" ma non possono essere definite direttamente nel codice. Una costante rappresenta un valore numerico che può essere utilizzato in tutti i punti del codice dove si può utilizzare un numero.
Diversamente da una variabile, una costante non può essere modificata durante l'esecuzione. Le costanti sono utili quando si vuole facilmente cambiare il comportamento tra differenti esecuzioni, come ad esempio quando si vuole adattare un valore di soglia condiviso da diversi nodi Aseba. Una costante non può avere lo stesso nome di una variabile, altrimenti viene rilevato un errore dal compilatore.

Esempio:

    # assumiamo l'esistenza di una costante di nome THRESHOLD
    var i = 600

    if i > THRESHOLD then
        i = THRESHOLD - 1
    end

## Array

Gli Array rappresentano aree contigue di memoria, indirizzate da una singola unità logica. La dimensione di un array è fissa e deve essere specificata nella dichiarazione. Gli array possono essere dichiarati usando le solite parentesi quadre `[]`. Il numero tra parentesi quadre specifica il numero di elementi che devono essere assegnati all'array e che ne rappresenta la dimensione. Può essere una espressione costante, comprese operazioni matematiche tra scalari e costanti. Utilizzando il costruttore dell'array (vedi sotto) è possibile definire una assegnazione opzionale dei valori dell'array. Se si fa in questo modo, non è necessario definire la dimensione dell'array.

Esempio:

    var a[10]                   # array di 10 elementi
    var b[3] = [2, 3, 4]        # inizializzazione
    var c[] = [3, 1, 4, 1, 5]   # dimensione implicita di 5 elementi
    var d[3*FOO-1]              # dimensione definita utilizzando una espressione costante (FOO è dichiarata come costante)

Gli arrays possono essere acceduti in vari modi:

- Un singolo elemento è acceduto utilizzando le parentesi quadre con un singolo valore. L'indice di un array parte da zero e arriva fino alla dimensione meno uno. Qualsiasi espressione può essere utilizzata come indice comprese espressioni matematiche che includono altre variabili.
- un sottoinsieme di elmenti può essere acceduto specificando le parentesi quadre e due espressioni cstanti separate da due punti ':'.
- Se le parentesi quadre sono omesse, l'intero array è acceduto.

Esempio:

    var foo[5] = [1,2,3,4,5]
    var i = 1
    var a
    var b[3]
    var c[5]
    var d[5]

    a = foo[0]       # copia il primo elemento di  'foo' in 'a'
    a = foo[2*i-2]       # idem
    b = foo[1:3]       # prendi il secondo, terzo e quarto elemento  di 'foo' e copiali in 'b'
    b = foo[1:2*2-1]   # idem
    c = foo           # copia i 5 elementi dall'array 'foo' nell'array 'c'
    d = c * foo       # moltiplica gli elementi degli arrays 'foo' e 'c' elemento per  elemento e copia il risultato in 'd'

## Costruttori di Array

I costruttori di array sono un modo per costruire array partendo da variabili, altri array, scalari, o anche espressioni complesse. Sono utili in molti casi, per esempio quando si inizializzano altri array, o come operandi in espressioni, funzioni ed eventi. Un costruttore di un array è fatto utilizzando le parentesi quadre che racchiudono diverse espressioni separate da `,` (virgola). la dimensione di un costruttore di un array è pari alla somma delle dimensioni dei singoli elementi, e deve coincidere con la dimensione dell'array in cui il risultato è memorizzato.

Esempio:

    var a[5] = [1,2,3,4,5]    # costruttore per inizializzare un array
    var b[3] = [a[1:2],0]    # l'array b viene inizializzato a [2,3,0]
    a = a + [1,1,1,1,1]    # aggiungi 1 a ciascun elemento dell'array a
    a = [b[1]+2,a[0:3]]    # l'array a conterrà [5,2,3,4,5]

# Espressioni e assegnazioni

Le espressioni consentono di effettuare calcoli matematici e sono scritte usando la normale notazione matematica infissa. Le assegnazioni utilizzano la parola chiave `=` e assegnano il risultato del calcolo di una espressione ad una variabilie scalare, un elemento di un array o un intero array, a seconda della dimensione dell'operando. Aseba fornisce vari operatori. Fare riferimento alla tabella seguente per una breve descrizione e per conoscere la precedenza di ciascun operatore. Per eseguire le espressioni in un ordine diverso da quello stabilito dalla precedenza degli operatori si possono usare le parentesi.

Precedenza | Operatore | Descrizione | Associatività | Numero argomenti
--- | --- | --- | --- | ---
1 | () | raggruppa in sottoespressioni |  | unaria
2 | * / | moltiplicazione e divisione |  | binaria
| % | Modulo |  | binaria
3 | + - | Addizione, sottrazione |  | binaria
4 | << >> | scorrimento a destra, scorrimento a sinistra |  | binaria
5 | | | Or binaria | associativa a sinistra | binaria
6 | ^ | or esclusiva binaria (xor) | associativa a sinistra | binaria
7 | & | AND binaria | associativa a sinstra | binaria
8 | - | meno unario |  | unaria
9 | ~ | NOT binario |  | unaria
10 | abs | valore assoluto |  | unaria
11 | = | Assegnazione |  | binaria
| |= ^= &= | Assegnazione con or, xor, and |  | binaria
| *= /= | Assegnazione con prodotto e quoziente |  | binaria
| %= | Assegnazione con modulo |  | binaria
| += -= | Assegnazione con somma e differenza |  | binaria
| <<= >>= | Assegnazione by left / right shift |  | binaria
| ++ -- | incremento e decremento |  | unaria

La versione con assegnazione dell'operatore binario funziona applicando l'operatore ad una variabile e memorizzando il risultato nella variabile stessa. Per esempio `A *= 2` è equivalente a scrivere `A = A * 2`. Queste forme abbreviate hanno lo scopo di rendere il codice più leggibile.

Esempio:

    a = 1 + 1
    # Risultato: a = 2
    a *= 3
    # Risultato: a = 6
    a++
    # Risultato: a = 7

    b = b + d[0]
    b = (a - 7) % 5
    c[a] = d[a]
    c[0:1] = d[2:3] * [3,2]

## Uso

Le espressioni matematiche sono strumenti di tipo generale. Come tali possono essere usate in una grande varietà di situazioni. Eccone alcune:

- Sulla parte destra di una assegnazione
- Come indice quando si accede ad un elemento di un array
- All'interno di chiamate di funzioni
- Come argomenti quando si emette un evento

# Controllo di flusso

## Condizioni

Aseba fornisce due tipi di condizionali: `if` e `when`. Questi consistono nella verifica di una condizione e in un blocco di codice. Il test consiste in un confronti opzionalmente raggruppati usando `and` (congiunzione logica), `or` (disgiunzione logica), e `not` (negazione logica) operatori e parentesi.
Un confronto è fatto da un operatore e due operandi, e può essere vero o falso. Gli operandi possono essere espressioni arbitrarie. La seguente tabella elenca gli operatori di confronto.

Operatore | Funzione di verità
--- | ---
`==` | vero se i due operandi sono uguali
`!=` | vero se i due operandi sono differenti
`>` | vero se il priomo operando è strettamente maggiore del secondo
`>=` | vero se il primo operando è maggiore o uguale al secondo
`<` | vero se il primo operando è strettamente minore del secondo
`<=` | vero se il primo operando è minore o uguale al secondo

Sia `if` che `when` eseguono differenti blocchi di codice a seconda se la condizione è vera o falsa; ma `when` esegue il blocco corrispondente a vero solo se l'ultima valutazione del codice era falsa e quella corrente è vera. Questo consente l'esecuzione del codice solo quando qualcosa cambia. Il condizionale `if` esegue un primo blocco di codice se la condizione è vera. Si può aggiungere un secondo blocco di codice da eseguire quando la condizione è falsa tramite la parola chiave `else`. E' possibile concatenare ulterioni condizionali `if` usando la parola chiave `elseif`.

Esempio:

    if a - b > c[0] then
        c[0] = a
    elseif a > 0 then
        b = a
    else
        b = 0
    end

    if a < 2 and a > 2 then
        b = 1
    else
        b = 0
    end

    when a > b do
        leds[0] = 1
    end

Il blocco `when` viene eseguito solo quando `a` diventa maggiore di `b`.

## Loop

Due costrutti consentono la creazione di iterazioni ad anello (loop) `while` e `for`.

Una iterazione ad anello con `while` esegue ripetutamente un blocco di codice fintanto che la condizione specificata sia vera. La condizione è della stessa forma di quella usata da `if`.

Esempio:

    while i < 10 do
        v = v + i * i
        i = i + 1
    end

Una iterazione ad anello con `for` consente ad una variabile di iterare su un intervallo di interi, con una dimensione del passo di incremento specificabile. Il passo di incremento può anche essere negativo. In questo caso la variabile si decrementa della quantità specificata andando dal valore maggiore al valore minore indicato dopo la parola chiave `in`.

Esempio:

    for i in 1:10 do
        v = v + i * i
    end
    # ad ogni iterazione la variabile i viene incrementata di 1 e si andrà da 1 a 10
    for i in 30:1 step -3 do
        v = v - i * i
    end
    # ad ogni iterazione la variabile i viene decrementata di 3 e si andrà da 30 a 1

# Blocchi

## Subroutine

Quando volete eseguire la stessa sequenza di codice in due o tre posti nel programma, è possibile scrivere il codice in comune in un sottoprogramma e quindi richiamare questo sottoprogramma da posti diversi. E' possibile definire un sottoprogramma usando la parola chiave `sub` seguita dal nome del sottoprogramma. Potete chiamare il sottoprogramma usando la parola chiave `callsub`, seguita dal nome del sottoprogramma. I sottoprogrammi devono essere definiti prima di essere chiamati. I sottoprogrammi non possono avere argomenti né essere recursivi recursive, cioè non possono richiamare se stessi né direttamente, nè indirettamente .
I sottoprogrammi possono accedere a qualsiasi variabile (in Aseba tutte le variabili sono globali).

Esempio:

    var v = 0

    sub toto
    v = 1

    onevent test
    callsub toto

## Eventi

Aseba ha una architettura basata su eventi, cioè gli eventi possono scatenare l'esecuzione di codice in maniera asincrona.

Gli eventi possono essere esterni, per esempio eventi definiti dall'utente in arrivo da altrun altro nodo Aseba, o interni, per esempio emessi da un sensore che fornisca un dato aggiornato.
Il ricevimento di una notifica di un evento fa eseguire, se definito, il blocco di codice che inizia con la parola chiave `onevent` seguita dal nome dell'evento.Il codice in cima al programma è eseguito quando il programma è avviato o riavviato.
Il programma può anche emettere un evento utilizzando la parola chiave `emit`, seguita dal nome dell'evento e dagli argomenti dell'evento stesso (se previsti). Se viene fornita una variabile questa deve avere una dimensione corrispondente a quella specificata negli argomenti dell'evento che deve essere emesso. Invece di una variabile, in situazioni più complesse è anche possibile utilizzare come argomenti di un evento costruttori di array ed espressioni matematiche. Gli eventi consentono al programma di causare l'esecuzione di codice su un altro nodo o di comunicare con un programma esterno.

Per consentire l'esecuzione del codice relativo ad un nuovo evento gli script non devono bloccarsi e non devono contenere iterazioni ad anello infinite. Per esempio nel contesto della robotica spesso si ricorre ad una iterazione ad anello infinita all'interno della quale vengono eseguite tutte le elaborazioni legate ai valori dei sensori. Nel linguaggio Aseba invece il codice viene eseguito se specificato per un dato evento. Se l'evento si realizza allora verrà richiamato il sottoprogramma relativo.

Esempio:

    var run = 0

    onevent start
    run = 1

    onevent stop
    run = 0

    onevent ir_sensors
    if run == 1 then
        emit sensors_values proximity_sensors_values
    end

## Direttiva Return

E' possibile uscire da una subroutine e sospendere l'esecuzione di uno script attivato da un evento con la direttiva `return`.

Esempio:

    var v = 0

    sub toto
    if v == 0 then
        return
    end
    v = 1

    onevent test
    callsub toto
    return
    v = 2

# Funzioni native

Il linguaggio di script Aseba è stato progettato per essere semplice e consentire una rapida comprensione anche per sviluppatori inesperti e per realizzare la macchina virtuale efficientemente su un micro-controller. Per eseguire calcoli complessi o che fanno uso intenso di risorse, forniamo funzioni native realizzate in codice nativo per maggior efficienza.
Per esempio una funzione nativa è il modo naturale di realizzare un prodotto scalare.

Le funzioni native sono sicure poiché specificano e verificano la dimensione dei loro argomenti, che possono essere costanti, variabili, celle di array, costruttori di array ed espressioni. Nel caso di array, potete accedere all'intero array, un singolo elemento, o un sotto-insieme dell'array. Le funzioni native accettano i loro argomenti per reference e possono modificare il loro contenuto, ma non restituiscono alcun valore. Si possono richiamare le funzioni native per mezzo della parola chiave `call`.

Esempio:

    var a[3] = 1, 2, 3
    var b[3] = 2, 3, 4
    var c[5] = 5, 10, 15
    var d
    call math.dot(d, a, b, 3)
    call math.dot(d, a, c[0:2], 3)
    call math.dot(a[0], c[0:2], 3)

# Cosa leggere ora?

Potreste essere interessati a leggere:

- Descrizione della libreria standard delle funzioni native