Existe alguma linguagem de programação (ou script) (ou alguma linguagem específica de domínio) com dois operadores binários opl
e opr
de mesma precedência em opl
ser associativo à esquerda e associativo à opr
direita?
(Não consigo encontrar esse exemplo, mas estou tentando codificar algum analisador geral o suficiente para lidar com esse caso estranho)
Como as expressões do formato x opl
y opr
z ou x opr
y opl
z são analisadas? E, geralmente, com ainda mais operandos?
language-design
parsing
Basile Starynkevitch
fonte
fonte
x <@ y @> z
com<@
ser deixado-associativa e@>
estar certo associativo, GHC dá-lhe um "Precedência erro de análise": "Não se pode misturar '<@
' [infixl 0] e '@>
' [infixr 0] na mesma expressão infix" (onde eu definido esses operadores no nível 0, por exemplo).if_then_else_
ou[1;2;3]
definidas em bibliotecas?).Respostas:
Aqui estão três idiomas que permitem definir seus próprios operadores, que fazem duas coisas e meia diferentes ! Haskell e Coq proíbem esse tipo de travessuras - mas de maneira diferente - enquanto a Agda permite esse tipo de mistura de associatividades.
Primeiro, em Haskell , você simplesmente não tem permissão para fazer isso. Você pode definir seus próprios operadores e dar a eles a precedência (de 0 a 9) e a associatividade de sua escolha. No entanto, o Relatório Haskell não permite que você misture associatividades :
Portanto, no GHC , se definirmos um
infixl
operador associativo à esquerda ( )<@
e associativo à direita@>
no mesmo nível de precedência - digamos 0 -, a avaliaçãox <@ y @> z
fornecerá o erro(Na verdade, você também pode declarar que um operador é infixo, mas não associativo, como
==
, portanto, issox == y == z
é um erro de sintaxe!)Por outro lado, há o provador de idiomas / teoremas de tipo dependente Agda (que, reconhecidamente, é consideravelmente menos popular). A Agda possui algumas das sintaxes mais maleáveis de qualquer idioma que eu conheço, suportando operadores mixfix : a biblioteca padrão contém a função
que, quando chamado, está escrito
com os argumentos preenchendo os sublinhados! Menciono isso porque isso significa que ele precisa oferecer suporte à análise incrivelmente flexível. Naturalmente, Agda também tem declarações fixity (embora seus níveis de precedência variam números naturais mais arbitrárias, e são tipicamente em 0-100), e Agda faz permitir que você misturar operadores da mesma precedência, mas diferentes fixities. No entanto, não consigo encontrar informações sobre isso na documentação, então tive que experimentar.
Vamos reutilizar o nosso
<@
e@>
de cima. Nos dois casos simples, temosx <@ y @> z
analisando comox <@ (y @> z)
; ex @> y <@ z
analisando como(x @> y) <@ z
.Acho que o que a Agda faz é agrupar a linha em partes "associativas à esquerda" e "associativas à direita" e - a menos que eu esteja pensando em coisas erradas - o pedaço associativo à direita recebe "prioridade" ao agarrar os argumentos adjacentes. Então isso nos dá
analisando como
ou
No entanto, apesar dos meus experimentos, adivinhei errado na primeira vez que escrevi isso, o que pode ser instrutivo :-)
(E a Agda, como Haskell, tem operadores não associativos, que fornecem erros de análise corretamente, portanto, seria possível que associatividades mistas resultem em um erro de análise também.)
Por fim, há a linguagem Coq , comprovadora de teoremas / de tipo dependente , que possui sintaxe ainda mais flexível que a Agda, porque suas extensões de sintaxe são realmente implementadas fornecendo especificações para as novas construções sintáticas e reescrevendo-as na linguagem principal (vagamente semelhante a macro , Eu suponho). No Coq, a sintaxe da lista
[1; 2; 3]
é uma importação opcional da biblioteca padrão. Novas sintaxes podem até vincular variáveis!Mais uma vez, no Coq, podemos definir nossos próprios operadores de infix e fornecer a eles níveis de precedência (de 0 a 99, principalmente) e associatividades. No entanto, no Coq, cada nível de precedência pode ter apenas uma associatividade . Portanto, se definirmos
<@
como associativo à esquerda e tentarmos definir@>
como associativo à direita no mesmo nível - digamos, 50 - obteremosA maioria dos operadores em Coq está em níveis divisíveis por 10; se eu tive problemas de associatividade (essas associatividades de nível são globais), geralmente apenas aumentamos o nível em um em qualquer direção (geralmente acima).
fonte
graphviz
?)\ttfamily \Tree[.<@ [.<@ [.<@ a b ] [.@> c [.@> d [.@> e f ]]]] g ]
.Desde que foram popularizados por Douglas Crockford, os analisadores Pratt (ou analisadores de precedência de operador descendente) começaram a se tornar mais comuns. Esses analisadores funcionam a partir de uma tabela de precedência e associatividade do operador, em vez de incorporar as regras em uma gramática fixa; portanto, são úteis para idiomas que permitem aos usuários definir seus próprios operadores.
Eles possuem uma função de análise que funciona analisando primeiro o termo mais à esquerda de uma expressão e, em seguida, vinculando recursivamente novos operadores e termos da mão direita, desde que sejam vinculados adequadamente. Operadores associativos de esquerda vincularão termos do lado direito que têm precedência até e inclusive a mesma precedência, enquanto operadores associativos de direita vinculam apenas seu nível de precedência, mas não o incluem. Acredito que isso resulta na mesma árvore de análise que para a Agda, citada acima.
fonte