Élodie Gamot

Élodie Gamot — 30 juin 2022

Améliorer l'analyse syntaxique

Peut-être avez-vous déjà eu à étudier la fonction mathématique f(x)=xcos(x) et son élégant tracé ?

Graph of xcosx

Si vous avez tenté de la tracer sur la calculatrice avant la sortie de la version 19 de notre logiciel, vous avez sans doute rencontré quelques difficultés, en l’occurrence un écran vide et des valeurs “undef”. De quoi provoquer des interrogations !

Table of undefs

Pour comprendre ce problème, et surtout comprendre sa résolution, nous devons d’abord nous interroger sur le processus d’analyse suivi par la calculatrice lorsque l’on presse le bouton exe à la fin d’un calcul.

Comprendre le parseur

Dans l’article Développer c’est renoncer !, Léa nous expliquait comment la calculatrice procède une fois que l’utilisateur presse exe.

Tout d’abord, la calculatrice essaye de comprendre ce que vous avez écrit.
Si vous écrivez 13+2, la calculatrice commence par identifier les différents termes utilisés dans le calcul : le nombre 13, le symbole +, et le nombre 2. Elle applique ensuite des règles de grammaire, exactement comme vous le faites actuellement en lisant cette phrase. Ainsi, un nombre suivi du symbole + puis d’un autre nombre s’analyse comme une addition entre ceux-ci.

Le procédé qui consiste à parcourir le contenu d’un texte ou d’un fichier en l’analysant pour vérifier sa syntaxe ou en extraire des éléments s’appelle le parsing.

Léa nous expliquait aussi que, lorsque l’on introduit des variables et des fonctions, les choses se compliquent un peu.

Si l’on entre, par exemple, abba(1+2):

  • Est-ce la fonction abba appliquée à 1+2 ?
  • Est-ce la variable abba multipliée par 1+2 ?
  • Est-ce la variable a multipliée par la variable b, multipliée par la variable b, multipliée par la variable a, multipliée par 1+2 ?
  • Est-ce la variable abb multipliée par la fonction a appliquée à 1+2 ?

Avant la version 19, notre parseur, qui analyse les données entrées dans la calculatrice, suivait une règle : toujours créer le nom de variable le plus long possible et, si ce nom est suivi de parenthèses, le comprendre comme un nom de fonction.
Si la règle était simple, elle nécessitait cependant que l’utilisateur écrive très explicitement le signe de la mutiplication.

C’est d’ailleurs pour cette raison que vous vous êtes peut-être trouvé en difficulté en voulant tracer f(x)=xcos(x) !

expression of xcosx

En effet, sans la multiplication explicite, le parseur recherche le nom de variable le plus long possible : xcos. Cependant, comme xcos n’est pas défini, on se retrouve avec une variable inconnue xcos multipliée par la variable x, d’où xcos*(x). Et bien sûr, comme xcos n’est pas défini, la fonction ne l’est pas non plus.

Une première solution

Lorsque l’on est face à un problème, il est important d’envisager plusieurs méthodes de résolution.
Initialement, nous avions songé à faire précéder automatiquement toutes les fonctions de type sin(), cos(), ln(), par le symbole de la multiplication dès lors que l’on pressait la touche correspondante (e.g. *sin()). Malheureusement, cette solution ne fonctionnait pas lorsque l’on devait écrire les fonctions en toutes lettres, ce qui est par exemple le cas lorsque l’on utilise le clavier de son ordinateur sur le simulateur.

Une meilleure solution : améliorer le parseur !

Pour trouver une solution plus efficace, il nous fallait procéder à des ajustements au niveau du parseur et revoir notre algorithme d’analyse.

La multiplication implicite par défaut

Tout d’abord, par défaut, on considère que ab signifie a*b. C’est-à-dire que, à moins que ab ne soit défini comme une variable ou une fonction, on suppose qu’il existe une multiplication implicite.

Pour éviter des conséquences fâcheuses dans l’application Solveur, il est toujours possible de résoudre des équations en utilisant des variables de type chaîne de caractères, mais en utilisant des guillemets : "apple"+"pear"=12.

Analyser de droite à gauche

Quand on analyse une chaîne de caractères abc, on commence par considérer abc, puis bc, et enfin c jusqu’à ce qu’on parvienne, soit à une fonction ou une variable déjà définie, soit à un simple caractère. On répète ensuite cet algorithme avec les caractères restants.

Reprenons notre fonction de départ : f(x) = xcos(x)
Comment la calculatrice va-t-elle analyser notre entrée ?

Parse xcos

Prenons d’autres exemples.

On définit les symboles suivants : a, b, ab, azfoo et foobar. Les cos() et acos() sont des fonctions prédéfinies.

  1. Comment la calculatrice va-t-elle analyser abfoobar(x) ?

    Parse abfoobar

    Même si a et b sont aussi définis, le parseur va commencer par lire la chaîne ab. Si vous souhaitez mutiplier a par b, il vous faudra utiliser le symbole de la multiplication : a*b

  2. Comment la calculatrice va-t-elle analyser acos(x) ?

    Parse acos

    Dans cet exemple aussi, a et cos sont déjà définis. Cependant, le parseur va tout d’abord lire la chaîne de caractères en entier, acos, qui est une fonction prédéfinie. Si vous souhaitez multiplier a par cos, il vous faudra là encore utiliser explicitement le symbole de la multiplication : a*cos

  3. Comment la calculatrice va-t-elle analyser azfoobar(x)?

    Parse azfoobar

    Dans ce dernier exemple, on peut se demander pourquoi le symbole azfoo n’est pas utilisé. L’algorithme d’analyse va en fait éliminer un maximum de caractères en commençant par la gauche. Certes, on aurait pu commencer de l’autre côté, mais grâce à ce comportement on privilégie les fonctions aux symboles. Et cela nous permet d’obtenir a*z*foobar(x) plutôt que azfoo×b×a×r×(x).

    Explorez la calculatrice ! Testez notre nouveau parseur et n’hésitez pas à nous suggérer des améliorations !

Élodie Gamot
Élodie Gamot — Responsable pédagogique

Elodie, c'est la professeure de maths que tout le monde rêverait d'avoir et maintenant nous l'avons chez NumWorks ! Passionnée et passionnante, elle aime raconter des histoires… et pas seulement à propos des mathématiques !