# Le langage d'Aseba

Cet aide est aussi disponible dans Aseba Studio dans le menu `Aide -> Langage`. Lorsque nous utilisons des mots techniques, nous les lions vers l'article Wikipedia correspondant. De plus, la page concepts explique quelques concepts importants liés à Aseba. Cette page présente le langage de la version 1.2 d'Aseba, pour des versions précédentes, veuillez lire cette page.

Le langage de programmation d'Aseba permet de programmer le comportement des nœuds Aseba. Syntaxiquement, ce langage ressemble à Matlab (un langage de programmation scientifique commun) : cette ressemblance permet aux développeurs ayant des connaissances préalables sur les langages de scripts de se sentir à l'aise et d'apprendre rapidement. Sémantiquement, c'est un langage de programmation impératif avec un seul type simple (nombres entiers signés sur 16 bits) et des tableaux. Cette simplicité permet aux développeurs sans connaissances préalables d'un système de type de programmer des comportement ; les nombres entiers étant le type de variable le plus naturel. De plus, les nombres entiers sont particulièrement adaptés aux robots à micro-contrôleurs.

# Commentaires

Les commentaires permettent d'ajouter des informations qui seront ignorées par le compilateur. Les commentaires sont très utiles pour annoter votre code avec des informations compréhensibles par un humain ou pour désactiver certaines parties du code. Les commentaires commencent avec un # et finissent à la fin de la ligne.

Exemple :

    # ceci est un commentaire
    var b    # un autre commentaire

Les commentaires sur plusieurs lignes sont également possibles. Ils commencent par #* et finissent par *#.

Exemple :

    #*
    ceci est un commentaire
    sur plusieurs lignes
    *#
    var b    # commentaire simple

# Scalaires

Les valeurs scalaires sont utilisées dans Aseba pour représenter des nombres. Elles peuvent être utilisées dans n'importe quelle expression, telle que l'initialisation d'une variable, dans une expression mathématique, ou dans une condition logique.

## Notation

Les scalaires peuvent être écrit en utilisant plusieurs bases différentes. La façon la plus naturelle correspond au système décimal, en utilisant les chiffres de 0 à 9. Les nombres négatifs sont déclarés en utilisant un signe `-` (moins) devant le nombre.

    i = 42
    i = 31415
    i = -7

Les nombres binaires et hexadécimales peuvent également être utilisés. Les nombres binaires sont préfixés par `0b`, alors que les nombres hexadécimales sont préfixés par `0x`.

    # notation binaire
    i = 0b110         # i = 6
    i = 0b11111111    # i = 255

    # notation hexadécimale
    i = 0x10    # i = 16
    i = 0xff    # i = 255

# Variables

Les variables font référence soit à des valeurs scalaires, soit à des tableaux de valeurs scalaires. Les valeurs sont comprises entre -32768 et 32767, ce qui correspond à la plage des nombres entiers signés sur 16 bits. Les variables utilisateurs doivent être déclarées au début du script Aseba, en utilisant le mot clé `var`, avant tout autre opération.

Le nom d'une variable doit suivre un certain nombre de règles :

- Le nom fait la différence entre majuscules et minuscules : une variable appelée "foo" est différente d'une autre appelée "Foo"
- Le nom doit commencer par un caractère alphabétique valide, ou '_'
- Le nom ne peut contenir que des caractères alphabétiques, '_' ou '.'
- Le nom ne peut pas être identique à un des mots clés d'Aseba (voir mots clés réservés)

Les variables peuvent être initialisées durant la déclaration, en utilisant le symbole d'assignation combiné à n'importe quelle expression mathématique. Une variable qui n'a pas été initialisée au préalable aura une valeur aléatoire, rien ne garantit qu'elle sera égale à zéro.

Exemple :

    var a
    var b = 0
    var c = 2*a + b # attention: 'a' n'est pas initialisée

## Mot clés réservés

Les mots clés suivants ne peuvent pas être utilisés pour nommer des variables, car ils sont déjà utilisés par la langage Aseba.

Mots clés
abs | call | callsub | do
else | elseif | emit | end
for | if | in | onevent
return | step | sub | then
var | when | while |

## Constantes

Des constantes peuvent être définies dans Aseba Studio, en utilisant le panneau "Constantes", car elles ne peuvent pas être définies directement dans le code. Tout comme une variable normale, une constante contient une valeur numérique, qui peut être utilisée plusieurs fois dans le programme. Mais contrairement aux variables, une constante ne peut pas être modifiée durant l'exécution. Les constantes sont utiles quand on veut facilement changer le comportement d'un programme d'une exécution à l'autre, comme le changement d'une valeur de seuil. Une constante a une portée couvrant l'ensemble des noeuds Aseba. Une constante ne peut pas avoir le même nom qu'une variable, une erreur est produite dans le cas contraire. Les constantes se comportent exactement comme des valeurs numériques.

    # en supposant une constante appelée SEUIL
    var i = 600

    if i > SEUIL then
        i = SEUIL - 1
    end

## Tableaux

Un tableau représente une zone contiguë de mémoire, manipulée comme une seule entité logique. La taille d'une tableau est fixe, et elle doit être définie au moment de la déclaration. On peut déclarer des tableaux en utilisant l'opérateur crochet habituel `[]`. Le nombre entre les crochets déclare le nombre d'éléments attribués au tableau, c'est-à-dire la taille du tableau. Il peut s'agir de n'importe quelle expression constante, incluant des opérations mathématiques portants sur des scalaires et des constantes. Une initialisation optionnelle peut avoir lieu, en utilisant le constructeur de tableau (voir ci-dessous). Dans le cas où une initialisation est effectuée, la taille du tableau peut être omise.

Exemple:

    var a[10]                   # tableau de 10 éléments
    var b[3] = [2, 3, 4]        # initialisation
    var c[] = [3, 1, 4, 1, 5]   # taille implicite de 5 éléments
    var d[3*FOO-1]              # taille déclarée en utilisant une expression constante (FOO déclarée en tant que constante)

Les tableaux peuvent être accédés selon plusieurs syntaxes :

- On accède à un seul élément en utilisant l'opérateur crochet encadrant une seule valeur. Les indexes d'un tableau commencent à zéro. N'importe quelle expression peut être utilisée comme index, incluant des expressions mathématiques impliquant d'autres variables.
- Une plage de valeurs peut être accédée en utilisant l'opérateur crochet encadrant deux expressions constantes séparées par deux-points ':'.
- En l'absence de l'opérateur crochet, le tableau est accédé dans son ensemble.

Exemple :

    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]        # copie le 1er élément depuis 'foo' vers 'a'
    a = foo[2*i-2]    # identique
    b = foo[1:3]      # prends le 2ème, 3ème et 4ème éléments de 'foo', copie vers 'b'
    b = foo[1:2*2-1]  # identique
    c = foo           # copie les 5 éléments de 'foo' vers 'c'
    d = c * foo       # multiplie élément par élément les tableaux 'c' et 'foo', copie vers 'd'

## Constructeur de tableau

Un constructeur de tableau permet de construire un tableau à partir de variables, d'autres tableaux, de scalaires, ou même n'importe quelle expression. Ils sont utiles dans plusieurs cas, par exemple lors de l'initialisation d'un autre tableau, ou comme opérande dans des expressions, fonctions ou événements. Un constructeur de tableau est déclaré en utilisant des crochets entourant plusieurs expressions séparées par une `,` (virgule). La taille d'un constructeur de tableau est la somme de la taille des éléments le constituant, et elle doit correspondre à la taille du tableau servant à stocker le résultat.

Exemple :

    var a[5] = [1,2,3,4,5]    # constructeur de tableau pour initialiser un tableau
    var b[3] = [a[1:2],0]    # contenu du tableau 'b' : [2,3,0]
    a = a + [1,1,1,1,1]    # ajoute 1 à chaque élément du tableau 'a'
    a = [b[1]+2,a[0:3]]    # le résultat est [3,2,3,4,5]

# Expressions et assignations

Les expressions permettent les calculs mathématiques et sont écrites en syntaxe mathématique infixée commune. L'assignation utilise le mot clé `=` et affecte le résultat du calcul d'une expression à une variable scalaire, à l'élément d'un tableau, ou dans tout ou partie d'un tableau. Aseba fournit plusieurs opérateurs. Le tableau ci-dessous fournit une brève description, ainsi que la préséance de chaque opérateur. Pour évaluer une expression dans un ordre différent, nous pouvons utiliser une paire de parenthèses afin de grouper une sous-expression.

Préséance | Opérateur | Description | Associativité | Arité
--- | --- | --- | --- | ---
1 | () | Groupe une sous-expression |  | Unaire
2 | * / | Multiplication, division |  | Binaire
| % | Modulo |  | Binaire
3 | + - | Addition, soustraction |  | Binaire
4 | << >> | Décalage à gauche, à droite |  | Binaire
5 | | | OU binaire | Associatif à gauche | Binaire
6 | ^ | OU exclusif binaire | Associatif à gauche | Binaire
7 | & | ET binaire | Associatif à gauche | Binaire
8 | - | Moins unaire |  | Unaire
9 | ~ | NON binaire |  | Unaire
10 | abs | Valeur absolue |  | Unaire
11 | = | Assignation |  | Binaire
| |= ^= &= | Assignation avec un OU, OU exclusif, ET binaire |  | Binaire
| *= /= | Assignation avec un produit ou quotient |  | Binaire
| %= | Assignation avec un modulo |  | Binaire
| += -= | Assignation avec une somme ou différence |  | Binaire
| <<= >>= | Assignation avec un décalage à gauche / droite |  | Binaire
| ++ -- | Incrément, décrément unaire |  | Unaire

La version assignation avec des opérateurs binaires consiste à appliquer l'opérateur à une variable et à stocker le résultat dans cette même variable. Par exemple `A *= 2` est équivalent à `A = A * 2`. Ces raccourcis ont pour but de rendre le code plus lisible.

Exemple :

    a = 1 + 1
    # Résultat : a = 2
    a *= 3
    # Résultat : a = 6
    a++
    # Résultat : a = 7

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

## Utilisation

Les expressions mathématiques sont un outil qui peut être appliqué dans une grande variété de situations. Voici quelques utilisations :

- Du côté droit d'une affectation
- Comme index lors de l'accès à un tableau
- A l'intérieur d'appels de fonctions
- Comme argument lors de l'émission d'un évènement

# Contrôle de flux

## Conditions

Aseba fournit deux types de conditions : `if` et `when`. Elles consistent en un test de conditions et des blocs de code. Le test consiste en des comparaisons éventuellement groupées en utilisant les opérateurs `and` (conjonction logique), `or` (disjonction logique), `not` (négation logique) et les parenthèses. Une comparaison consiste en un opérateur et deux opérandes, et peut être soit vraie soit fausse. L’opérande peut être une expression quelconque. La table suivante liste les opérateurs de comparaison.

Opérateur | Valeur de vérité
--- | ---
== | vrai si les opérandes sont égaux
!= | vrai si les opérandes sont différents
> | vrai si le premier opérande est strictement plus grand que le second
>= | vrai si le premier opérande est plus grand ou égal au second
< | vrai si le premier opérande est strictement plus petit que le second
<= | vrai si le premier opérande est plus petit ou égal au second

Tant `if` que `when` exécutent un bloc de code différent selon qu'une condition est vraie ou fausse ; mais `when` exécute le bloc correspondant à vrai seulement si la dernière évaluation de la condition était fausse et que l'évaluation courante est vraie. Cette différentiation permet l'exécution de code seulement quand quelque chose change. Le `if` exécute un premier bloc de code si la condition est vrai, un second bloc à exécuter si la condition est fausse peut être ajouté par le mot-clé `else`. De plus, d'autres conditions peuvent être chaînées grâce au mot-clé `elseif`.

Exemple :

    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

Ici le bloc `when` s'exécute seulement quand `a` devient plus grand que `b`.

## Boucles

Deux constructions permettent la création de boucles : `while` et `for`.

Une boucle `while` exécute un bloc de code plusieurs fois tant qu'une condition est vraie. La condition est de même type que celle utilisée par `if`.

Exemple:

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

Une boucle `for` fait itérer une variable sur un intervalle d'entiers, avec en option une taille de pas.

Exemple:

    for i in 1:10 do
        v = v + i * i
    end
    for i in 30:1 step -3 do
        v = v - i * i
    end

# Blocs

## Sous-routines

Lorsque vous effectuez une même suite d'opérations à plusieurs endroits dans le code, il est bon de mettre le code commun une seule fois dans une sous-routine, puis d'appeler cette dernière depuis les divers endroits. Vous pouvez définir une sous-routine en utilisant le mot-clé `sub` suivi du nom de la sous-routine. Vous pouvez appeler la sous-routine en utilisant le mot-clé `callsub` suivi du nom de la sous-routine. Les sous-routines doivent être définies avant leur utilisation. Les sous-routines ne peuvent pas avoir d'arguments, ni être récursives, que ce soit directement ou indirectement. Les sous-routines peuvent accéder à toutes les variables.

Exemple:

    var v = 0

    sub toto
    v = 1

    onevent test
    callsub toto

## Événements

Aseba a une architecture par programmation événementielle, ce qui signifie que des événements peuvent déclencher l'exécution de code de façon asynchrone. Les événements peuvent être externes, par exemple un événement défini par l'utilisateur venant d'un autre nœud Aseba, ou internes, par exemple émis par un capteur qui possède un valeur nouvellement acquise. La réception d'un événement exécute, si défini, le bloc de code commençant par le mot clé `onevent` suivi du nom de l'événement. Le code au début du script est exécuté quand ce dernier est chargé ou au reset. Un script peut aussi envoyer des événements en utilisant le mot clé `emit`, suivi par le nom de l'événement ainsi que du nom de la variable à envoyer, s'il y a lieu. Si une variable est fournie, la taille de l'événement doit correspondre à celle de l'argument à envoyer. En lieu et place d'une variable, des constructeurs de tableau et des expressions mathématiques peuvent aussi être utilisées pour les situations plus complexes. Les événements permettent ainsi à un script de déclencher l'exécution de code sur un autre nœud ou de communiquer avec un programme externe.

Afin de permettre l'exécution du code lors de la réception d'un nouvel événement, le script ne doit pas bloquer et donc ne pas contenir de boucle infinie. Par exemple dans le contexte de la robotique, où un programme de contrôle de robot traditionnel travaillerait à l'intérieur d'une boucle infinie, un script Aseba ferait simplement le travail lors d'un événement lié aux capteurs.

Exemple :

    var run = 0

    onevent start
    run = 1

    onevent stop
    run = 0

    onevent ir_sensors
    if run == 1 then
        emit valeurs_des_capteurs valeurs_des_capteurs_de_proximite
    end

## Instruction return

Il est possible de sortir prématurément d'une sous-routine et de stopper l'exécution d'un événement en utilisant le mot clé `return`.

Exemple :

    var v = 0

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

    onevent test
    callsub toto
    return
    v = 2

# Fonctions natives

Nous avons conçu le langage de script d'Aseba simple afin de permettre une compréhension aisée par des développeurs novices et pour implémenter la machine virtuelle efficacement. Pour implémenter des calculs complexes ou lourds, nous fournissons des fonctions natives implémentées en code natif pour une exécution rapide. Par exemple, une fonction native est la solution de choix pour effectuer un calcul de produit scalaire.

Les fonctions natives sont sûrs, dans le sens qu'elles spécifient et vérifient les tailles de leurs arguments, qui peuvent être des constantes, des variables, des accès à des tableaux, des constructeurs de tableau et des expressions. Dans le cas d'un tableau, nous pouvons accéder à tout le tableau, à un élément discret ou à un sous-intervalle du tableau. Les fonctions natives prennent leurs arguments par référence et peuvent modifier leurs contenus, mais ne retournent aucune valeur. Les fonctions natives sont appelées par le mot-clé `call`.

Exemple:

    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)

# Que lire ensuite ?

La page suivante peut vous intéresser :

- Description de la bibliothèque standard de fonctions natives