Page 1 of 2

UnderBasic 2

Unread postPosted: 17 Sep 2016, 21:20
by Clément.7
Bonjour à tous !
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 :o !

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 :troll: ?

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
ou bien encore
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 :p).

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 :p. 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)


:o :p
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.

Re: UnderBasic 2

Unread postPosted: 17 Sep 2016, 22:42
by Adriweb
J'avais vu le repo GitHub, mais franchement en voyant tes exemples et explications ici, c'est nettement plus impressionnant que ce que je l'imaginais. Très sympa, cette v2 :)
Mes félicitations, et bonne chance pour la suite.

Je te conseille de faire une page de doc avec le maximum d'exemples, du plus simple au plus complexe, histoire d'augmenter la popularité de ton langage, il n'y a rien de mieux que d'apprendre par l'exemple je trouve :P Et puis ça complètera la doc existante (et bien fournie), c'est bien.
J'imagine que le must serait de montrer un vrai projet genre un jeu ?

Je vais voir si je peux rapidement m'occuper des bindings JS pour tivars_lib_cpp histoire de pouvoir (pour de bon) faire exporter le code TI-Basic généré en 8xp, ca te sera, je pense, utile...
(Ca tombe bien, j'étais en train de bosser dessus aujourd'hui pour améliorer des choses)

Re: UnderBasic 2

Unread postPosted: 17 Sep 2016, 23:13
by Wistaro
Excellent travail.
Et en js en plus, je savais même pas que c'était possible de faire ce genre de truc.
C'est vrai que c'est plus intéressants de faire travailler le client plutôt que le serveur comme je peux le faire en php. Tu me donnes envie de me remettre au JS (enfin plutôt me mettre, mes connaissances dans ce langage sont très limitée voire inexistantes. Je n'accordais que très peu d'attention à ce langage qui, pour moi, servait simplement à afficher des pop-up et des trucs épileptiques sur les vieux site des années 2000.
Trêve de blabla.

Ça va être utile ton programme. Même si..
Je ne vois pas vraiment l'intérêt de passer d'une syntaxe simple à une.syntaxe plus complexe pour finalement obtenir le même résultat. Mais bon.

Re: UnderBasic 2

Unread postPosted: 18 Sep 2016, 08:37
by Lionel Debroux
En effet, ça semble être du bon travail, Clément.7 :)
Ce genre de projets est très formateur, et je t'encourage donc à les poursuivre si tu souhaites devenir développeur professionnel, comme un certain nombre de membres anciens et actuels de la communauté.
Et Adriweb a raison, il faut un maximum d'exemples et une bonne doc.

Wistaro: on peut en effet faire beaucoup mieux que ce que tu cites avec le JS, que ce soit côté client ou côté serveur (Node.js) :)
Mais ne faisons pas dérailler le sujet.

Re: UnderBasic 2

Unread postPosted: 18 Sep 2016, 08:50
by Clément.7
@Wistaro : La syntaxe est de prime d'abord plus complexe, mais au final c'est plus simple de coder en UnderBasic qu'en TI-Basic. On a accès à des noms de variables à plusieurs caractères, là où sur TI on se limite à A, B, Str0... On peut utiliser des fonctions pour répéter du code, utiliser les blocs et les routines dont je parlerais plus tard pour utiliser de gros codes dans les jeux.

@Adriweb : J'ai créé l'UnderBasic à la base pour créer des jeux en fait. Donc oui, ça sera tout à fait possible. J'avais même commencé à développer des structures de jeux, une fois que le compilateur sera terminé il sera possible de faire ce que je n'arrivais pas à faire en TI-Basic : Un RPG avec plusieurs maps, complètes, des combats, et surtout réaliser - enfin - mon projet RPG Maker que j'avais abandonné à cause de sa trop grande complexité. Un moteur qui permettrait de coder des RPG sur TI directement, sans passer par un PC, tout en customisant les personnages, les monstres, les dialogues, avec des sortes de mini cut-scenes, des événements sur la map, etc.
Bref, une fois que j'aurais terminé le compilateur je mettrais en ligne une doc' complète avec des exemples, pourquoi pas si j'en ai le courage un tuto sur OpenClassrooms (mais j'en doute).
Il y aura de toutes manières des exemples de code fournis avec le compilateur, les premiers affichant un simple texte ou calculant les premiers termes de la suite de Fibonacci, les derniers pour montrer l'utilisation des directives conditionnelles qui permettent, comme je l'ai montré dans mon premier post, de réaliser des fonctions qui ne généreront pas le même code suivant les paramètres qu'on leur donne.

Merci à tous pour votre soutien :D

Re: UnderBasic 2

Unread postPosted: 01 Oct 2016, 11:07
by Clément.7
Il y avait plein de bugs dans le support des expressions écrites dans le compilateur, par exemple :

Code: Select all
sub("0123456789", iPart(10 * fPart(nbr * 10 ^ ( -x ))) + 1, 1) + answer


Ne fonctionnait pas. J'ai ajouté tout à l'heure un nouveau parser après deux semaines de développement (c'est pour ça que le projet semblait "arrêté" sur GitHub, pour ceux qui suivraient le dépôt). Maintenant tout fonctionne, il ne me reste plus que quelques petites choses à régler et le compilateur sera totalement utilisable ;)

La liste des choses à faire :

  • Renommer les fonctions (il y a des fonctions dont le nom les rend inutilisables, par exemple la fonction ShadeX² lèvera une erreur de syntaxe) quasiment terminé
  • Faire un fichier de traduction française (pour les messages d'erreur du compilateur, et pour les noms de fonction, "print" deviendra "afficher", etc.) avancé à 75 %
  • Ajouter des bibliothèques d'utilitaires (par exemple la fonction "replaceChar" permet de remplacer un caractère dans une chaîne) avancé à 75 %
  • Créer la bibliothèque RPG (pour... bah... créer des RPG :p) avancé à 50 %
  • Rédiger un tutoriel avancé à 25 %
  • Ajouter le support de fonctions écrites par l'utilisateur (à faire)
  • Ajouter le support des directives (à faire)

Re: UnderBasic 2

Unread postPosted: 08 Oct 2016, 15:29
by Ti64CLi++
Bonne chance,
Et si tu as besoin d'aide, n'hésite pas ;)

Re: UnderBasic 2

Unread postPosted: 08 Oct 2016, 20:23
by Clément.7
Pour le coup ça ira, déjà j'ai jamais fait de projet en équipe, et ensuite j'y arrive tout seul (pour l'instant ^^). Le plus dur ç'a vraiment été le parser qui vérifie que 2 + 5 * abs(2) c'est un nombre et que "Salut" * 2 c'est pas valide, mais que 2 * L1 ça marche, plus la vérification des arguments pour chaque commande.

D'ailleurs il reste encore un ou deux bugs je crois, je vais corriger ça d'ici les prochains jours. Le plus bête à vrai dire, c'est que j'ai reçu une nSpire hier et que je ne vais plus trop utiliser ma TI-83+ (mais promis je continue le projet, de toutes façons le TI-Basic z80 est 100x meilleur que celui sur TI-Nspire :p)

Re: UnderBasic 2

Unread postPosted: 08 Oct 2016, 20:48
by Hamza.S
Clément.7 wrote:mais promis je continue le projet, de toutes façons le TI-Basic z80 est 100x meilleur que celui sur TI-Nspire :p

tu te bases sur quoi?
côté graphique il n'y a rien mais côté calculs et fonctions de la calculatrice, les z80 sont nulles

Re: UnderBasic 2

Unread postPosted: 08 Oct 2016, 20:54
by Adriweb
Le TI-Basic des Nspire a simplement un objectif différent de celui des z80 (Nspire: maths/science uniquement, et c'est pas mal, c'est même le meilleur Basic pour ça, de loin ; z80: un peu de tout, mais assez limité, c'est très bien pour apprendre à coder) - on peut donc pas vraiment comparer.
Et par défaut, côté Nspire, la puissance de la machine, contrairement à celle des z80, lui permet d'avoir du Lua, ce qui en gros comble les trous de son TI-Basic. Sur z80, on a bien de l'ASM mais ça reste largement plus bas niveau (et donc beaucoup moins accessible à du monde) que du Lua.