[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: How to obtain the line number of AST node?
On Fri 2006-11-24 at 15:43h, Antti Virtanen wrote on sablecc-user:
> Howdy!
>
> I'm a bit puzzled as I could not find a way to get the line number
> of the AST nodes. The token classes have getLine() since they derive
> from Token, but after AST translation some AST nodes do not contain
> any tokens. AST node classes are derived from Node, which does not
> have getLine() so the line number seems to be forgotten in the
> translatation. What to do now?
Yes, that's a deficiency I encountered as well. Even when all nodes
contain tokens, you get wrong positional info unless _all_ original
tokens are retained in the AST. For example in nodes corresponding to
expressions like "-1" and "(x + 1) * f(y)", when the tokens "-", "("
and ")" are not retained in the AST, then the positional extent of
those nodes is wrongly determined as that of "1" and "x + 1) * f(y".
Another peeve I have is that the position (character index) in the
stream is not made available. To find the position of a specific token
in the input, one has to parse the input externally for newlines to
find the correct line.
Furthermore, determining position info for the nodes by writing an
analysis which propagates the information from the leaf nodes (tokens)
up to the other nodes can be quite tedious, because you have to write
dedicated code for each node type.
I patched my version of SableCC so that the Node class has a method
public void apply(ChildVisitor visitor);
where ChildVisitor is an inner interface of class Node defined as
public interface ChildVisitor
{
public void accept(Node child);
public void accept(List<? extends Node> children);
}
(Unlike Étienne, I happen to prefer the original GoF "visitor"
nomenclature. ;))
(I abused the "ToString" macro in alternatives.txt for implementing
apply(ChildVisitor) for each node type. Given apply(ChildVisitor),
toString can then be implemented generically in Node using an
appropriate ToStringChildVisitor.)
Then I added moved the "pos" and "line" members from the Token class
to the Node class and also added "endPos" and "endLine" members along
with a method updatePositionInfo() which updates these members for
this node (and for all its descendants) using an PositionUpdateVisitor
that implements ChildVisitor.
-- Niklas Matthies