Il existe deux cas différents à considérer, selon la syntaxe de votre langue. Si votre langue utilise des parenthèses pour indiquer l'application de la fonction (par exemple f(2+1)
), la priorité n'est pas pertinente. La fonction doit être poussée sur la pile et sautée après (pour l'exemple ci-dessus, le résultat est 2 1 + f
). Vous pouvez également traiter la fonction comme une valeur et la générer immédiatement, et générer une opération d'invocation de fonction après la parenthèse fermante (qui devrait sinon être traitée de la même manière que toute autre parenthèse), par exemple f 2 1 + $
, où se $
trouve l'opération d'invocation de fonction.
Si votre langage, cependant, n'utilise pas de parenthèses pour indiquer l'invocation d'une fonction, mais place plutôt l'argument directement après la fonction sans aucune ponctuation spéciale (par exemple f 2 + 1
), comme c'est apparemment le cas pour l'exemple de Wikipedia, alors les choses sont un peu plus compliquées. Notez que l'expression que je viens de donner à ás est un exemple ambigu: f est-il appliqué à 2 et 1 ajouté au résultat, ou ajoutons-nous 2 et 1 ensemble, puis appelons f avec le résultat?
Encore une fois, il existe deux approches. Vous pouvez simplement pousser la fonction vers la pile d'opérateurs lorsque vous la rencontrez et lui affecter la priorité que vous souhaitez. C'est l'approche la plus simple, et c'est apparemment ce qu'a fait l'exemple cité. Il y a cependant des problèmes pratiques. Premièrement, comment identifiez-vous une fonction? Si vous avez un ensemble fini, c'est facile, mais si vous avez des fonctions définies par l'utilisateur, cela signifie que votre analyseur doit également être réinjecté dans votre environnement, ce qui peut devenir rapidement désordonné. Et comment gérez-vous les fonctions avec plusieurs arguments?
Mon sentiment est que pour ce style de syntaxe, l'utilisation de fonctions comme des valeurs plus pratiques pour un opérateur d'application de fonction est beaucoup plus logique. Ensuite, vous pouvez simplement injecter l'opérateur d'application chaque fois que vous lisez une valeur et la dernière chose que vous lisez était également une valeur, de sorte que vous n'avez pas besoin d'un moyen spécial de dire quels identificateurs sont des fonctions. Vous pouvez également travailler avec des expressions qui renvoient des fonctions (ce qui est difficile ou impossible avec le style de fonction en tant qu'opération). Et cela signifie que vous pouvez utiliser le curry pour gérer plusieurs fonctions d'argument, ce qui est une simplification massive par rapport à leur gestion directe.
La seule chose que vous devez alors décider est quelle est la priorité de l'application de la fonction. Le choix vous appartient, mais dans toutes les langues que j'ai utilisées qui fonctionnent comme ça, il a été l'opérateur le plus fortement contraignant dans la langue, et a été juste associatif. (La seule variation intéressante étant Haskell, qui en plus d'avoir la version fortement contraignante décrite, a également un synonyme pour cela avec le symbole $
qui est l'opérateur le plus faiblement contraignant dans la langue, permettant des expressions comme f 2 + 1
appliquer f à 2 et f $ 2 + 1
appliquer à l'ensemble du reste de l'expression)
sin( max( 2 3) / 3 * 3.1415)