|
|
|
Re: Making an editor with xtext for an existing DSL (Robot Framework) [message #837676 is a reply to message #837500] |
Fri, 06 April 2012 00:45 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
On 2012-05-04 20:59, Mikko Korpela wrote:
> About my question 4:
> I abstracted too much out of the example. So this little language
> definition hopefully points out what I'm aiming at.
>
> grammar org.xtext.example.mydsl.MyDsl with
> org.eclipse.xtext.common.Terminals
>
> generate myDsl "HERE WAS A LINK BUT I CAN NOT USE IT BECAUSE I HAVE LESS
> THAN 25 MESSAGES POSTED TO THiS NEWSGROUP"
>
Hint, post "Forum rule that 25 posts must have been made in order to
post a link sucks!" 25 times in a suitable forum... (one that the
webmasters read ;)
> Model:
> (foos+=Foo)+
> '{' (bars+=Bar ';') '}';
>
> Foo:
> bar=[Bar] | some=ID;
>
> Bar:
> name=ID;
>
>
> So I have some text that can be a reference to another location or not..
> and I'm unable to identify it before I have the actual elements (Bars).
> Are the situation and solutions still similar as the ones pointed out in
> the original response?
ok, so that does not work - the parser is doing its work long before the
linker kicks in - the parser simply can not know what to do when it sees
an ID - should it use it as a reference to a Bar, or as "some" ID that
is not a reference to something that exists elsewhere. There is no
simple way to specify this in the grammar.
There are a couple of different solutions.
- Does ID always reference something that exists (ie. in both the Bar
and "some" cases)? If so, make it a reference to the supertype of all
the things that it may reference.
- Use some syntactic marker (but guessing that is out of the question if
the grammar for the language already exists) (e.g. ('+' bar = [Bar]) |
some = ID ;
- If what follows ID when used as a bar reference makes it
distinguishable from a "some" then you can use a predicate. i.e.
Foo: =>(bar = [Bar] SOMETHING_NOT_FOLLOWING_SOME) | some = ID ;
or vice versa after "some":
Foo: bar = [Bar] | =>(some = ID SOMETHING_NOT_FOLLOWING_BAR_REF) ;
Which means, if you at the point of the => see an ID, and then
SOMETHING_NOT_FOLLOWING_xxx then take this path. This disambiguates the
ID. The SOMETHING_NOT... is some token/rule that makes the combination
unique.
(Remember [x] is shorthand for [x | ID])
- Do your own linking - i.e. assign the ID to a feature, and then check
if it is a valid reference in the hook "afterModelLinked" in the linker.
(There are a few more things to do though regarding keeping track of
references (unresolved and resolved) to get the builds compute the
correct build order / what to rebuild when something changes. (I use
this approach in cloudsmith/geppetto @ github).
- If there is something in the ID that makes it possible to determine if
it is a Bar reference or not then you could try to tackle the problem
that way.
- You can write your own lexer that makes use of the global index of
exported elements. It looks up the ID, and if there is an exported Bar
in the index it produces a BarReference token instead of an ID token.
This is more complicated if there are references to a Bar defined in the
same resource. You basically have to parse the file with a second parser
to find all the bars, and then also include these in your lookup.
Your grammar then becomes:
Foo : bar = [Bar | BarReference] | some = ID ;
Bar : name = ID;
Hope this helps explaining how it works, and some of your options.
Regards
- henrik
|
|
|
Powered by
FUDForum. Page generated in 0.02609 seconds