aprendizagem Treetop
Pergunta
Estou tentando me ensinar gerador de gramática Treetop de Ruby. Eu estou achando que não só é a documentação lamentavelmente escassa para o "melhor" lá fora, mas que não parecem funcionar tão intuitivamente como eu esperava.
Em um nível alto, eu realmente adoraria um tutorial melhor do que os docs no local ou o vídeo, se houver um.
Em um nível inferior, aqui está uma gramática eu não posso começar a trabalhar em tudo:
grammar SimpleTest
rule num
(float / integer)
end
rule float
(
(( '+' / '-')? plain_digits '.' plain_digits) /
(( '+' / '-')? plain_digits ('E' / 'e') plain_digits ) /
(( '+' / '-')? plain_digits '.') /
(( '+' / '-')? '.' plain_digits)
) {
def eval
text_value.to_f
end
}
end
rule integer
(( '+' / '-' )? plain_digits) {
def eval
text_value.to_i
end
}
end
rule plain_digits
[0-9] [0-9]*
end
end
Quando eu carregá-lo e executar algumas afirmações em um objeto de teste muito simples, eu acho:
assert_equal @parser.parse('3.14').eval,3.14
funciona bem, enquanto
assert_equal @parser.parse('3').eval,3
levanta o erro: NoMethodError: método `eval privada' chamado para #
Se eu inverter inteiro e flutuar na descrição, ambos inteiros e carros alegóricos me dar esse erro. Eu acho que isso pode estar relacionado à antecipação limitado, mas não consigo encontrar qualquer informação em qualquer um dos documentos até mesmo cobrir a ideia de avaliar no "ou" contexto
Um pouco mais informação que pode ajudar. informações de aqui pp tanto para aqueles parse () blocos.
O float:
SyntaxNode+Float4+Float0 offset=0, "3.14" (eval,plain_digits):
SyntaxNode offset=0, ""
SyntaxNode+PlainDigits0 offset=0, "3":
SyntaxNode offset=0, "3"
SyntaxNode offset=1, ""
SyntaxNode offset=1, "."
SyntaxNode+PlainDigits0 offset=2, "14":
SyntaxNode offset=2, "1"
SyntaxNode offset=3, "4":
SyntaxNode offset=3, "4"
O Integer ... nota que parece ter sido definida de seguir a regra número inteiro, mas não pegou o método eval ():
SyntaxNode+Integer0 offset=0, "3" (plain_digits):
SyntaxNode offset=0, ""
SyntaxNode+PlainDigits0 offset=0, "3":
SyntaxNode offset=0, "3"
SyntaxNode offset=1, ""
Update:
Eu tenho o meu especial de trabalho problema, mas não tenho idéia por que:
rule integer
( '+' / '-' )? plain_digits
{
def eval
text_value.to_i
end
}
end
Isso não faz sentido com os documentos que estão presentes, mas apenas remover os parênteses adicionais fez o jogo incluir a classe Inteiro1, bem como Integer0. Inteiro1 é, aparentemente, a classe segurando o método eval (). Eu não tenho idéia por que este é o caso.
Eu ainda estou procurando mais informações sobre copa de árvore.
Solução
Infelizmente, a documentação do Treetop suga. Muito. E os exemplos no site não são úteis. Descobri que dzone tem uma bela grande coleção de gramáticas copa de árvore:
Outras dicas
Você pode apreciar agradável de Paulo Battley, simples tutorial em Começando com Treetop
Começando com uma gramática mínima, ele mostra como criar um analisador e, em seguida, através de um par de iterações adiciona apenas um pouco de funcionalidade. Foi apenas o suficiente para me tirar os blocos de partida.
Roland Swingler fez uma apresentação sobre Treetop para LRUG: http://skillsmatter.com/podcast/ajax-ria/treetop que eu achei útil para começar.
Citrus é uma alternativa muito mais leves para copa: http://github.com/mjijackson/citrus
Eu segui este Treetop introdutória tutorial um par de anos atrás, para entender os conceitos básicos de copa de árvore.
E então Uma rápida introdução para escrevendo um analisador com Treetop , útil para mim porque ele explica como mapear os nós de árvore sintaxe para instâncias de classe rubi.
Eu apenas comecei a experimentar com TreeTop.
Eu tentei a mudança
rule num
(float / integer)
end
para
rule num
(float / integer)
{
def eval
text_value.to_f
end
}
end
E parece trabalho.
Os docs Copa parecem assumir que você já sabe uma quantidade razoável sobre gramática de análise sintática de expressão (PEG). Treetop é inteiramente baseado em PEG. PEGs são maiores do que apenas Treetop porém, ou seja, eles são usados ??em outras bibliotecas de análise também. Em aprender Copa da árvore, eu achei muito útil para estudar-se sobre PEGs em geral. Isso preenchimento ajudou em muitas das lacunas na documentação.
Este é um bug. Os parênteses desnecessários em torno da regra para um inteiro faz com que a construção de um módulo extra para conter a definição de eval, e este módulo não se misturam no nó, so 'eval' não está disponível. Você pode ver isso claramente se você comparar o código Ruby (gerado usando o comando tt) para as versões com e sem esses parênteses extras.