Why does the DSL show "Couldn't resolve reference to "? - grammar

I am implementing a grammar with three sections. In the first section I declare components with their interfaces, for instance Component A with interfaces interface_1, interface_2. In the third section I declare some restrictions, for instance component A can acces component B through interface XXXX. When I try to cross-reference the interfaces of a component I get the error "Couldn't resolve reference to ProbeInterface 'interface_1'"?.
I tried several examples from internet but none of them works to my case.
This is part of my grammar:
ArchitectureDefinition:
'Abstractions' '{' abstractions += DSLAbstraction+ '}'
'Compositions' '{' compositions += DSLComposition* '}'
'Restrictions' '{' restrictions += DSLRestriction* '}'
;
DSLComposition:
DSLProbe|DSLSensor
;
DSLRestriction:
'sensor' t=[DSLSensor] 'must-access-probe' type = [DSLProbe] 'through-interface' probeinterface=[ProbeInterface] ';'
;
DSLSensor:
'Sensor' name=ID ';'
;
DSLProbe:
'Probe' name=ID ('with-interface' probeinterface=ProbeInterface)? ';'
;
ProbeInterface :
name+=ID (',' name+=ID)*
;
And the implementation:
Abstractions
{
Sensor sensor_1 ;
Probe probe_1 with-interface interface_1, interface_2;
}
Compositions{}
Restrictions
{
sensor sensor_1 must-access-probe probe_1 through-interface
interface_1;
}
I expect that interface_1 or interface_2 can be referenced by the grammar.
Thanks.

the grammar you posted is incomplete
the way you define the interfaces is really bad.
default naming works only with single valued name attributes
ProbeInterface :
name+=ID (',' name+=ID)*
;
better
DSLProbe:
'Probe' name=ID ('with-interface' probeinterfaces+=ProbeInterface ("," probeinterfaces+=ProbeInterface)*)? ';'
;
ProbeInterface :
name=ID
;
it looks like the qualified name of a Interface is
<probename>.<interfacename>
you either have to adapt the name provider
or the grammar and model to use qualiedname ref=[Thing|FQN] with FQN: ID ("." ID)*;
or you implement scoping properly which is what you want to do likely in your case since you want to restrict the inferfaces for specific probes
here is a sample
override getScope(EObject context, EReference reference) {
if (reference === MyDslPackage.Literals.DSL_RESTRICTION__PROBEINTERFACE) {
if (context instanceof DSLRestriction) {
val probe = context.type
return Scopes.scopeFor(probe.probeinterfaces)
}
}
super.getScope(context, reference)
}

Related

Capturing content which can start with Parser keywords in Xtext

The following is the simplified version of my actual grammar :-
grammar org.hello.World
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate world "http://www.hello.org/World"
Model:
content=AnyContent greetings+=Greeting*;
AnyContent:
(ID | ANY_OTHER)*
;
Greeting:
'<hello>' name=ID '</hello>';
terminal ID:
('a'..'z'|'A'..'Z')+
;
terminal ANY_OTHER:
.
;
So using above grammar if my input is like :-
<hi><hello>world</hello>
Then I am getting an syntax error saying that mismatched character 'i' expecting 'e' at Column 2 .
My requirement is that AnyContent should match "<hi>" , can anyone guide me about how to achieve that?
If you want to make it with Xtext. I advice you to split your problem. You first problem is syntaxic, you need to parser your file. The second problem is semantic, you want to give a "sense" to your objets and tell who is the container. Define the container and the containment for XML can't be done inside your grammar.
Make a custom Ecore and make an easy grammar, with start and end tag. You don't really care about the name of your tag.
Example :
Model returns XmlFile: (StartTag|EndTag|Text)+;
Text returns Text: text=STRING;
StartTag returns StartTag: '<' name=ID '>';
EndTag returns EndTag: '</' name=ID '>';
Change the TokenSource. The token source will give the token to your Parser. You can override the nature of your token, merge or split them.
The idea here is to merge all token outside the between of ">" and "</".
This token represent a Text, so you can create a single token for all elements containing between this elements. Example :
class CustomTokenSource extends XtextTokenStream{
new(TokenSource tokenSource, ITokenDefProvider tokenDefProvider) {
super(tokenSource,tokenDefProvider)
}
override LT(int k) {
var Token token = super.LT(k)
if(token != null && token.text != null) token.tokenOverride(k);
token
}
In this example you need to add your custom code on the method "tokenOverride".
Add your custom token source on your parser :
class XDSLParser extends DSLParser{
override protected XtextTokenStream createTokenStream(TokenSource tokenSource) {
return new CustomTokenSource(tokenSource, getTokenDefProvider());
}
}
Compute the containement : the containment of your elements can be compute after the parsing. After it, you can get your model and change it as you will. To make it, you need to override the method "doParse" of your Parser "XDSLParser" as follow :
override protected IParseResult doParse(String ruleName, CharStream in, NodeModelBuilder nodeModelBuilder, int initialLookAhead) {
var IParseResult result = super.doParse( ruleName, in, nodeModelBuilder, initialLookAhead)
//Give you model
result.rootASTElement;
return result
}
Note : The model that you obtain after the parsing will be flat. The xmlFile Object will contain all the elements in the good order. You need to write an algorithm to build the containement on your AST model.
This will require a lot of tweaking in the grammar due to the nature of the antlr lexer that is used by Xtext. The lexer will not roll back for the keyword <hello>: As soon as it sees a < followed by an h it'll try consume the hello-token. Something along these lines could work though:
Model:
content=AnyContent greetings+=Greeting*;
AnyContent:
(ID | ANY_OTHER | '<' (ID | ANY_OTHER | '/' | '>') | '/' | '>' | 'hello')*
;
Greeting:
'<' 'hello '>' name=ID '<' '/' 'hello' '>';
terminal ID:
('a'..'z'|'A'..'Z')+
;
terminal ANY_OTHER:
.
;
The approach won't scale for real world grammars but maybe it helps to get on the some working track.

ANTLR 4 taking decisions from a parse tree

I need to take some decisions depending on the structure and information in a parse tree, this is an example of the trees I am generating now:
The decisions for generating code will depend on the operator(";","AND","OR","XOR") between two workflows, for instance the code I need to generate from this tree is
mustPrecede(T6,T4) AND mustPrecede(T6,T1)
AND mustPrecede(T4,T5) AND mustPrecede(T1,T5)
For this I need to find out that the operator between T6 and (T4 AND T1) is ";" (sequential composition operator) for taking a decision and then I need to find out that between T4 and T1 the operator is "AND" and then I need to get the T4 and T1 to make a relation with T5. My question is how can I encode this in a parser?.
This is my grammar definition
grammar Hello;
execution: workflow EOF;
workflow : Task
| workflow OPERATOR workflow
|'(' workflow (OPERATOR workflow)+ ')'
;
Task : 'T' ('0'..'9')+
| 'WF' ('0'..'9')+
;
OPERATOR: 'AND'
| 'OR'
| 'XOR'
| ';'
;
WS : [ \t\n\r]+ -> channel(HIDDEN) ;
You created one token, OPERATOR, which represents all of your operators. This makes it very difficult to distinguish between the different operators. An easier set of rules would be the following:
operator
: AND
| OR
| XOR
| SEMI
;
AND : 'AND';
OR : 'OR';
XOR : 'XOR;
SEMI : ';';
You would also replace references to OPERATOR with references to operator. Then, in your implementation of a listener or visitor, you could create methods like the following (using an example from a listener).
#Override
public void enterWorkflow(WorkflowContext ctx) {
List<? extends OperatorContext> operatorContexts = ctx.operator();
if (operatorContexts.isEmpty()) {
// handle just a Task
} else {
for (OperatorContext operatorContext : ctx.operator()) {
switch (operatorContext.getStart().getType()) {
case HelloLexer.AND:
// handle 'AND'
break;
case HelloLexer.OR:
// handle 'OR'
break;
case HelloLexer.XOR:
// handle 'XOR'
break;
case HelloLexer.SEMI:
// handle ';'
break;
default:
throw new IllegalStateException("Unrecognized operator.");
}
}
}
}

Antrl lexer/parser exception understanding

I have the following language i wish to parse using antlr 1.2.2.
TEST <name>
{
<param_name> = <param value>;
}
while
<...> - means user value, not part of the language keywords
for example
TEST myTest
{
my_param = 1.0;
}
the value can be an integer, a real or a quated string
my_param = 1.0;, my_param = 1; and my_param = "myStringValue"; are all valid inputs.
here is the grammer for this parsing.
parse_test : TESTKEYWORD TEST_NAME '{' param_value_def '}';
param_value_def : ID EQUALS param_value ';';
param_value : REAL|INTEGER|QUOTED_STRING;
TESTKEYWORD : 'TEST';
QUOTED_STRING : '"' ~('"')* '"';
INTEGER : MINUS? DIGIT DIGIT*
REAL : INTEGER '.' DIGIT DIGIT*;
EQUALS : '=';
fragment
MINUS : '-';
fragment
DIGIT : '0'..'9';
when i feed the sample input to the antlr interpreter, i get a `MismatchedTokenException' related to the param_value rule.
can you help me cipher the error message and what i am doing wrong?
thanks
Although ANTLRWorks is not a tool well written, you can use its debugger to see which token in the input leads to this exception, and then you can see which rules need to be revised (since you did not post the full grammar).
http://www.antlr.org/works/index.html

variable not passed to predicate method in ANTLR

The java code generated from ANTLR is one rule, one method in most times. But for the following rule:
switchBlockLabels[ITdcsEntity _entity,TdcsMethod _method,List<IStmt> _preStmts]
: ^(SWITCH_BLOCK_LABEL_LIST switchCaseLabel[_entity, _method, _preStmts]* switchDefaultLabel? switchCaseLabel*)
;
it generates a submethod named synpred125_TreeParserStage3_fragment(), in which mehod switchCaseLabel(_entity, _method, _preStmts) is called:
synpred125_TreeParserStage3_fragment(){
......
switchCaseLabel(_entity, _method, _preStmts);//variable not found error
......
}
switchBlockLabels(ITdcsEntity _entity,TdcsMethod _method,List<IStmt> _preStmts){
......
synpred125_TreeParserStage3_fragment();
......
}
The problem is switchCaseLabel has parameters and the parameters come from the parameters of switchBlockLabels() method, so "variable not found error" occurs.
How can I solve this problem?
My guess is that you've enabled global backtracking in your grammar like this:
options {
backtrack=true;
}
in which case you can't pass parameters to ambiguous rules. In order to communicate between ambiguous rules when you have enabled global backtracking, you must use rule scopes. The "predicate-methods" do have access to rule scopes variables.
A demo
Let's say we have this ambiguous grammar:
grammar Scope;
options {
backtrack=true;
}
parse
: atom+ EOF
;
atom
: numberOrName+
;
numberOrName
: Number
| Name
;
Number : '0'..'9'+;
Name : ('a'..'z' | 'A'..'Z')+;
Space : ' ' {skip();};
(for the record, the atom+ and numberOrName+ make it ambiguous)
If you now want to pass information between the parse and numberOrName rule, say an integer n, something like this will fail (which is the way you tried it):
grammar Scope;
options {
backtrack=true;
}
parse
#init{int n = 0;}
: (atom[++n])+ EOF
;
atom[int n]
: (numberOrName[n])+
;
numberOrName[int n]
: Number {System.out.println(n + " = " + $Number.text);}
| Name {System.out.println(n + " = " + $Name.text);}
;
Number : '0'..'9'+;
Name : ('a'..'z' | 'A'..'Z')+;
Space : ' ' {skip();};
In order to do this using rule scopes, you could do it like this:
grammar Scope;
options {
backtrack=true;
}
parse
scope{int n; /* define the scoped variable */ }
#init{$parse::n = 0; /* important: initialize the variable! */ }
: atom+ EOF
;
atom
: numberOrName+
;
numberOrName /* increment and print the scoped variable from the parse rule */
: Number {System.out.println(++$parse::n + " = " + $Number.text);}
| Name {System.out.println(++$parse::n + " = " + $Name.text);}
;
Number : '0'..'9'+;
Name : ('a'..'z' | 'A'..'Z')+;
Space : ' ' {skip();};
Test
If you now run the following class:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String src = "foo 42 Bar 666";
ScopeLexer lexer = new ScopeLexer(new ANTLRStringStream(src));
ScopeParser parser = new ScopeParser(new CommonTokenStream(lexer));
parser.parse();
}
}
you will see the following being printed to the console:
1 = foo
2 = 42
3 = Bar
4 = 666
P.S.
I don't know what language you're parsing, but enabling global backtracking is usually overkill and can have quite an impact on the performance of your parser. Computer languages often are ambiguous in just a few cases. Instead of enabling global backtracking, you really should look into adding syntactic predicates, or enabling backtracking on those rules that are ambiguous. See The Definitive ANTLR Reference for more info.

How to pass CommonTree parameter to an Antlr rule

I am trying to do what I think is a simple parameter passing to a rule in Antlr 3.3:
grammar rule_params;
options
{
output = AST;
}
rule_params
: outer;
outer: outer_id '[' inner[$outer_id.tree] ']';
inner[CommonTree parent] : inner_id '[' ']';
outer_id : '#'! ID;
inner_id : '$'! ID ;
ID : ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' )* ;
So the inner[CommonTree parent] generates the following:
inner4=inner((outer_id2!=null?((Object)outer_id2.tree):null));
resulting in this error:
The method inner(CommonTree) in the type rule_paramsParser is not applicable for the arguments (Object)
As best I can tell, this is the exact same as the example in the Antrl book:
classDefinition[CommonTree mod]
(Kindle Location 3993) - sorry I don't know the page number but it is in the middle of the book in chapter 9, section labeled "Creating Nodes with Arbitrary Actions".
Thanks for any help.
M
If you don't explicitly specify the tree to be used in your grammar, .tree (which is short for getTree()) will return a java.lang.Object and a CommonTree will be used as default Tree implementation. To avoid casting, set the type of tree in your options { ... } section:
options
{
output=AST;
ASTLabelType=CommonTree;
}