Existe-t-il un langage de programmation (ou de script) (ou un langage spécifique à un domaine) ayant deux opérateurs binaires opl
et opr
de même priorité d' opl
être à gauche et opr
à droite?
(Je ne trouve pas un tel exemple, mais j'essaie de coder un analyseur assez général pour gérer ce cas étrange)
Comment les expressions de la forme x opl
y opr
z ou x opr
y opl
z seraient-elles analysées? Et plus généralement avec encore plus d'opérandes?
language-design
parsing
Basile Starynkevitch
la source
la source
x <@ y @> z
à<@
être associatif à gauche et à@>
être associatif à droite, GHC vous donne une "erreur d'analyse de priorité": "ne peut pas mélanger '<@
' [infixl 0] et '@>
' [infixr 0] dans la même expression d'infixe" (où j'ai défini ces opérateurs au niveau 0 pour l'exemple).if_then_else_
ou[1;2;3]
être défini dans des bibliothèques?).Réponses:
Voici trois langages qui vous permettent de définir vos propres opérateurs, qui font deux choses et demie différentes ! Haskell et Coq interdisent tous les deux ces sortes de manigances - mais différemment - tandis qu'Agda permet ce genre de mélange d'associativités.
Tout d'abord, à Haskell , vous n'êtes tout simplement pas autorisé à le faire. Vous pouvez définir vos propres opérateurs et leur donner la priorité (de 0 à 9) et l'associativité de votre choix. Cependant, le rapport Haskell vous interdit de mélanger les associativités :
Donc, dans GHC , si nous définissons un
infixl
opérateur associatif gauche ( )<@
et un opérateur associatif droit@>
au même niveau de priorité - disons 0 - alors l'évaluationx <@ y @> z
donne l'erreur(En fait, vous pouvez également déclarer un opérateur infixe mais non associatif, comme
==
, c'estx == y == z
donc une erreur de syntaxe!)D'un autre côté, il y a le prouveur de langage / théorème de type dépendant Agda (qui, il est vrai, est considérablement moins courant). Agda possède certaines des syntaxes les plus malléables de toutes les langues que je connais, prenant en charge les opérateurs mixfix : la bibliothèque standard contient la fonction
qui, une fois appelé, est écrit
avec les arguments remplissant les traits de soulignement! Je mentionne cela parce que cela signifie qu'il doit prendre en charge une analyse incroyablement flexible. Bien entendu, Agda a aussi des déclarations de fixité (bien que ses niveaux de priorité vont nombres naturels plus arbitraires, et sont généralement en 0-100), et Agda ne vous permettra de mélanger les opérateurs de même priorité mais différents fixités. Je ne peux cependant pas trouver d'informations à ce sujet dans la documentation, j'ai donc dû expérimenter.
Réutilisons notre
<@
et@>
d'en haut. Dans les deux cas simples, nous avonsx <@ y @> z
analyse en tant quex <@ (y @> z)
; etx @> y <@ z
analyse en tant que(x @> y) <@ z
.Je pense que ce qu'Agda fait est de regrouper la ligne en morceaux "associatifs de gauche" et "associatifs de droite", et - à moins que je ne pense à des choses erronées - le morceau associatif de droite obtient la "priorité" en saisissant les arguments adjacents. Cela nous donne donc
analyse en tant que
ou
Cependant, malgré mes expériences, je me suis trompé la première fois que j'ai écrit cela, ce qui pourrait être instructif :-)
(Et Agda, comme Haskell, a des opérateurs non associatifs, qui donnent correctement des erreurs d'analyse, il serait donc possible que les associativités mixtes entraînent également une erreur d'analyse.)
Enfin, il y a le langage Coq , prouveur de théorèmes / type dépendant , qui a une syntaxe encore plus flexible que Agda parce que ses extensions de syntaxe sont en fait implémentées en donnant des spécifications pour les nouvelles constructions syntaxiques, puis en les réécrivant dans le langage de base (vaguement de type macro , Je suppose). Dans Coq, la syntaxe de liste
[1; 2; 3]
est une importation facultative de la bibliothèque standard. De nouvelles syntaxes peuvent même lier des variables!Encore une fois, dans Coq, nous pouvons définir nos propres opérateurs d'infixe et leur donner des niveaux de priorité (de 0 à 99, principalement) et des associativités. Cependant, dans Coq, chaque niveau de priorité ne peut avoir qu'une seule associativité . Donc, si nous définissons
<@
comme associative à gauche, puis essayons de définir@>
comme associative à droite au même niveau - disons, 50 - nous obtenonsLa plupart des opérateurs de Coq sont à des niveaux divisibles par 10; si j'ai eu des problèmes d'associativité (ces associativités de niveau sont globales), j'ai généralement juste augmenté le niveau d'un dans les deux sens (généralement vers le haut).
la source
graphviz
??)\ttfamily \Tree[.<@ [.<@ [.<@ a b ] [.@> c [.@> d [.@> e f ]]]] g ]
.Depuis qu'ils ont été popularisés par Douglas Crockford, les analyseurs Pratt (ou analyseurs Top-Down Operator Precedence) ont commencé à devenir plus courants. Ces analyseurs fonctionnent à partir d'un tableau de priorité et d'associativité des opérateurs, plutôt que d'avoir les règles intégrées dans une grammaire fixe, ils sont donc utiles pour les langages qui permettent aux utilisateurs de définir leurs propres opérateurs.
Ils ont une fonction d'analyse qui fonctionne en analysant d'abord le terme le plus à gauche d'une expression, puis en liant récursivement de nouveaux opérateurs et des termes de droite tant qu'ils se lient de manière appropriée. Les opérateurs associatifs de gauche lieront les termes de droite qui ont la priorité jusqu'à et y compris la même priorité, tandis que les opérateurs associatifs de droite se lient uniquement à leur niveau de priorité, mais ne l'incluent pas. Je crois que cela donne le même arbre d'analyse que pour Agda, cité ci-dessus.
la source