Il y a un an, presque jour pour jour, naissait le projet UnderBasic (à deux jours près, zut ! )
Ce projet avait pour but de permettre de programmer en Basic de manière plus simple tout en ayant plus de fonctionnalités à disposition, telles que les fonctions, les blocs, les alias et les routines (vous pouvez regarder la doc pour voir ce qu'on pouvait faire avec ce langage). Cependant, il lui manquait une fonction cruciale, à savoir un type checker.
Show/Hide spoilerAfficher/Masquer le spoiler
Il s'agit d'un petit programme qui permet de savoir que 2 + cos(5 / "Hello") n'est pas valide mais que 2 + L1 / 2 * [A](0, 2] correspond à un nombre. Le compilateur utilisé pour UnderBasic n'était pas codé de manière à permettre une telle implémentation, et j'ai fini par jeter l'éponge.
Aujourd'hui, je vous annonce une nouvelle version de ce langage, bien plus robuste et puissante que la première version ! En plus de ce programme qui est - comme vous vous en doutez - implémenté, beaucoup de choses ont changé, des choses qui étaient problématiques et faisaient de l'UnderBasic un langage trop peu structuré pour être vraiment intéressant.
I - Présentation du langage
L'UnderBasic est un langage de programmation qui est converti en TI-Basic. En d'autres termes, vous créez un programme en UnderBasic, vous le collez dans l'éditeur, et un magnifique code TI-Basic apparaît !
Avant de commencer, voici un petit aperçu des fonctions qu'on peut créer en UnderBasic :
Show/Hide spoilerAfficher/Masquer le spoiler
- Code: Select all
function direBonjour(nom) {
afficher "Bonjour, " + nom + " !"
afficher "Comment ça va ?"
}
direBonjour "Michel"
direBonjour "Jean-Pierre"
saisir "Votre nom ?", nom
direBonjour nom
- Code: Select all
Disp "Bonjour, Michel !"
Disp "Comment ça va ?"
Disp "Bonjour, Michel !"
Disp "Comment ça va ?"
Disp "Bonjour, Jean-Pierre !"
Disp "Comment ça va ?"
Input "Votre nom ?", Str0
Disp "Bonjour, " + Str0 + " !"
Disp "Comment ça va ?"
L'intérêt de ce langage est de permettre de programmer des programmes qui fonctionnent sur les calculatrices TI-z80 (TI-82 Stats.fr, TI-83+, TI-83+.fr, TI-84+, TI-84+ SE, TI-83 Premium CE, TI-84 Premium CE et TI-84 CSE, plus quelques autres vieux modèles comme la TI-81 je pense), tout en créant des programmes plus simplement et de manière plus lisible, en utilisant des fonctionnalités dont ne disposent pas ces calculatrices.
Vous pourrez par exemple programmer en utilisant des fonctions intégralement traduites en français (afficher, saisir, effacer...) et une grande liberté de syntaxe (que nous verrons un peu après).
Si vous avez besoin d'effectuer une grosse série de calculs sur plusieurs valeurs à plusieurs endroits dans votre code, vous allez devoir recopier ce morceau de code à chaque fois, ce qui va prendre de la place. À chaque fois que vous voudrez modifier ces calculs, vous devrez modifier chaque partie du code, ce qui est contraignant. Ici, pas de problème !
Les fonctions
Les fonctions permettent d'exécuter un code de manière répétée. Dans notre exemple, cela donnerait ceci :
- Code: Select all
fonction grosCalculs(a, b, c) {
a * b / cos( tan( arcsin( 2 / stdDev(L1, L2) ) ) ) / sin( 2 * tan( a / L1[3] ) )
Ans + 2 * cos( Ans * a / c )
}
grosCalculs(2, 3, 5)
# beaucoup de code ici
grosCalculs(7, 2, 8)
En TI-Basic, vous auriez dû écrire :
- Code: Select all
2*3/cos(tan(arcsin(2/stdDev(L1,L2))))/sin(2*tan(2/L1[3]))
Ans+2*cos(Ans*2/5)
# Beaucoup de code ici
7*2/cos(tan(arcsin(2/stdDev(L1,L2))))/sin(2*tan(7/L1[3]))
Ans+2*cos(Ans*7/8)
Ça fait peur, hein ?
Les variables
Bon, on va pas se mentir, les variables ça sert. Un peu.
En TI-Basic on a accès à A, B, L1, [A], Z, PI, e, i, X...
Il n'est pas pratique du tout d'écrire avec ces noms-là sur un ordinateur.
D'autre part, l'UnderBasic est, à l'instar du TI-Basic, un langage dit typé, c'est-à-dire que vous ne pouvez pas mettre une chaîne de caractère dans une variable faite pour recevoir un nombre. Ainsi, "Hello"->A ne fonctionne pas en TI-Basic.
Pour pouvoir utiliser des variables, on va donc utiliser des noms. age correspondra à A, nom à Str1, etc.
Dans l'ancienne version d'UnderBasic, on faisait comme ça :
- Code: Select all
nom is Str1
- Code: Select all
#alias nom : Str1
Nom seulement ce n'était pas très pratique mais en plus il y avait plein de bugs, si vous écriviez ensuite print "Salut, mon nom est Michel !" votre ligne était transformée en print "Salut, mon Str1 est Michel !", ce qui est nettement moins sexy.
Voici comment on déclare des variables en UnderBasic :
- Code: Select all
Voilà. C'est simple non ? Si c'est allé trop vite pour vous, je vous le refais :
Censuré pour cause de répétition totalement inutile
En UnderBasic, on n'a pas besoin de déclarer les variables. Plus exactement, vous pouvez les déclarer, mais ce n'est pas obligatoire. Ainsi, on distingue trois types d'utilisation :
1 - Déclaration à la volée
- Code: Select all
# Pas de déclaration ici
saisir "Votre nom ?", nom
Comme le compilateur sait que la fonction "saisir" prend comme second argument une variable de chaîne de caractères (eh oui, j'ai dû recopier tout le catalogue de la TI à la main en ajoutant les types, ça fait beaucoup de fonctions), il va "deviner" que "nom" est une variable contenant une chaîne de caractères. Problème, elle n'est pas définie... Du coup, il va la créer !
Mais comme la TI n'a pas de variable nommée "nom", il va l'associer à une variable TI-Basic, et il choisira en premier lieu Str0, puis Str1, puis Str2...
Et quand il arrive à Str9... Il est bloqué, et une erreur survient. Comme la TI n'a que 10 variable pouvant contenir des chaînes, il ne peut pas en faire apparaître (malheureusement ).
2 - Déclaration implicite
- Code: Select all
let nom
saisir "Votre nom ?", nom
Cette forme de déclaration permet de déclarer votre variable avant de l'utiliser. Cela vous permet de savoir quelle variable vous utilisez dans votre code, sans vous retrouver à relire tout votre code de 800 lignes pour vous en souvenir...
Là, le compilateur sait que la variable "nom" existe, il n'a plus qu'à deviner son type.
3 - Déclaration explicite
Le problème des deux formes précédentes, c'est que l'on ne se souvient pas forcément de quelle variable contient quoi, et surtout vous pouvez vous retrouvez avec des illogicités dans votre code, par exemple un endroit ou vous y assigner un nombre et un autre où, en ayant oublié cela, vous assignez une chaîne de caractères. Pas bien grave, me direz-vous. C'est vrai, mais c'est toujours mieux de ne pas faire d'erreur .
Pour cela, on utilise des déclarations dites typées, c'est-à-dire que l'on indique quel est le type de la variable :
- Code: Select all
string nom
nom = "Michel"
Voilà, c'est tout bête. Les types disponibles sont "string" "number" "list" "matrix" "yvar" "picture" "gdb" (qui seront par la suit également disponibles en français), respectivement une chaîne de caractères, un nombre, une liste une matrice, une fonction (2X+1), une image (Pic1) et un groupe de données graphiques (GDB1).
II - Les fonctions et les blocs
Pour les fonctions et les blocs... Beh ça n'a pas changé en fait . C'est toujours comme dans la première version, à l'exception près que vous pouvez ou non exiger un type pour l'argument qui est passé en paramètre. C'est tout !
Les directives changeront également (#define, #alias, #ifdef...) mais j'en reparlerais, pour l'instant ce n'est même pas encore implémenté.
Allez, une dernière bonne petite fonction bien compliquée pour finir ? (je précise que les #ifdef, #match etc. ne sont pas des commentaires) :
- Code: Select all
function centrer(string str, number [y]) {
# ifdef y
# ifmatch str string~
:precalc number x = 8 - Math.round($scope.str.length / 2);
output y, ${x}, str
# elseif
output y, 8 - round(length(str) / 2), str
# endif
# elseif
# ifmatch str string~
:precalc string spaces = " ".repeat(Math.round(7 - $scope.str.length / 2))
print "${spaces | unquote}${str}"
# elseif
# error Impossible d'afficher la variable sans en connaître la ligne
# endif
}
- Code: Select all
# Exemples d'utilisation :
# Afficher sur la ligne suivante un magnifique "Bouquet" centré
center("Bouquet")
# Afficher Str0 au centre de la ligne 2
center(Str0, 2)
- Code: Select all
Disp " Michel"
Output(2,8-round(length(Str0)/2),Str0)
Si si c'est vraiment possible de faire ça en UnderBasic. J'ai dit qu'on pouvait faire beaucoup de choses, non ?
Bonne soirée à tous !
P.S. : Vous pouvez aussi consulter le dépôt GitHub.