I'd like your advice concerning a recurring problem concerning my usage of Treetop,that I cannot fix...from time to time. I'm probably missing something.
I suspect many of you have the right idiom or habits to solve that.
I generally use Treetop like the following :
However, I hit a classical error message, that I cannot generally fix :
parsetree.rb:380:in `to_ast': undefined method `to_ast' for SyntaxNode
offset=149, "":Treetop::Runtime::SyntaxNode (NoMethodError)
I am puzzled here because an empty string "" seems to be emitted instead of one of my custom nodes.
In this example, on this line 380 I have the following code ( it is about a finite state machine)
# in parsetree.rb
class Next < Tree
def to_ast
ret=Ldl::Ast::Next.new
ret.name=ns.to_ast
if cond
ret.condition=cond.c.to_ast
end
ret.actions=acts.to_ast # <==== line 380
ret
end
end
class NextActions < Tree
def to_ast
eqs.elements.collect{|eq| eq.to_ast}
end
end
And my piece of grammar concerned by the error is :
rule nextstate
space? 'next' space ns:identifier space? cond:('?' space? c:expression)? space
acts:next_actions? <Ldl::ParseTree::Next>
end
rule next_actions
space? eqs:equation+ space 'end' space <Ldl::ParseTree::NextActions>
end
Your problem is with the behaviour of optional expressions.
The acts:next_actions is optional. If this optional element is unmatched in the input, you don't get a NextActions node but an epsilon. You should detect that by saying something like:
ret.actions = acts.empty? ? [] : acts.to_ast
The same problem may occur because the sequence named by the tag cond: is optional. If this sequence doesn't exist in the input, then it has no content "c". In that case "cond" will still be defined and your "if" statement will be true, but cond.c.to_ast will fail.
Short answer: When you use an optional expression, you should tag it and test the tag for empty? before trying to use the content.