Hi Alexander,
See below.
On 2012-11-25 18:23, Alexander Ryzhov wrote:
[...]Thanks for the suggestion. The example needs
several changes in order to work:
1) rename defaultCase -> defaultIn;
I really meant:
@Override
public void defaultCase(Node node) {
...
}
This method is called for every token (in DepthFirstAdapter). It is
not called for other nodes (because of redefinitions).
2) add if(node instanceof Token) since defaultIn
is also called for Start which is not a Token;
A simple cast is sufficient, as it is not called for non-token
nodes.
For other nodes, you want to use defaultOut, in the reverse
adapter, as the last visited token is the first one.
3) replace two maps with one map where the value is a
LineAndPos object.
You can play with it as you wish. :)
4) instead of using the token as the key for the map,
add a loop over all parent nodes and put line/pos information for
all parents of the token node.
You seem to forget about empty alternatives...
Productions
p =
{alt1} a b c |
{alt2} q;
q = ;
Notice how
q has no children to give us a position. The
reverse adapter will give it the location of
EOF. Empty
alternatives are the motivation for using the reverse adapter.
That will work but I can't say it's ideal because the
complexity of the algorithm is N square where N is the number of
nodes in the grammar plus the overhead of HashMap.
As far as I can see, it would be O(n), where n is
the number of nodes in the AST, ignoring the cost of the HashMap. I
don't see where you see quadratic complexity in my proposed code.
Unless I missed something?
I will use the suggested approach but I wish AST came
with this information pre-computed since the desire to link the
AST to the source text is quite typical (error reporting,
visualization).
SableCC 4 will have a clean implementation of locations. But this is
actually difficult, as the position of a should be observably
constant. The problem is that, sometimes, the user can get hold of a
node before the AST is completely built using semantic selectors and
investigators; like the filter() method of SableCC 2/3.
On a related subject, I'd like to add that line/pos
isn't always sufficient. In some cases, it's desirable to get
absolute position of the token from the beginning of the file -
some editors use absolute positioning in the API. Converting
line/pos to absolute position isn't trivial. Also, there is the
start line/pos of the token but no end line/pos. Although it can
be calculated using token text, it's more reliable to have it --
it doesn't add much memory.
Something like this is planned in SableCC 4 (e.g. start and
end location for every node of the AST). For SableCC 3, my
proposed tree walker should do the trick.
If you wish to compute end location, you must use the normal forward
adapter, but still override defaultOut.
Have fun!
Etienne