Question

I got stuck with my xtext grammar definition. Basically I like to define multiple parameters for a component. The component should contain at least one parameter definition paramA OR paramB OR paramC OR (paramA AND paramB) OR (paramB AND paramC) OR (paramA AND paramB AND paramC).

Overall these are 6 cases, as you can see in my grammar definition:

Component:
    'Define available parameters:' (
        (newParamA = ParamA | newParamB = ParamB | newParamC = ParamC)
        | (newParamA = ParamA & newParamB = ParamB)
        | (newParamA = ParamA & newParamC = ParamC)
        | (newParamB = ParamB & newParamC = ParamC)
        | (newParamA = ParamA & newParamB = ParamB & newParamC = ParamC)
    )
;

ParamA: ('paramA = ' paramA=Integer ';');
ParamB: ('paramB = ' paramB=Integer ';');
ParamC: ('paramC = ' paramC=Integer ';');

// Datatype
Integer returns ecore::EIntegerObject: '-'? INT;

Here is what is working when I reduce my grammar to use (newParamA = ParamA | newParamB = ParamB | newParamC = ParamC) only, means without the other cases in the first code snippet:

Define available parameters:
    paramA = 1;
...
Define available parameters:
    paramB = 2;
...
Define available parameters:
    paramC = 3;

But I like to be able to define multiple available params in my dsl, e.g.

Define available parameters:
    paramA = 1; paramB = 2;
...
Define available parameters:
    paramB = 2; paramC = 3;
...
Define available parameters:
    paramA = 1; paramB = 2; paramC = 3;

Any idea how to resolve that issue? Hope you can help me, I'ld appreciate any help!

This is the error I get when generating the grammar from code snippet #1:

warning(200): ../my.packagename/src-gen/my/packagename/projectname/parser/antlr/internal/InternalMyDSL.g:722:1: Decision can match input such as "'paramC = ' '-' RULE_INT ';'" using multiple alternatives: 1, 3, 4, 5
As a result, alternative(s) 3,5,4 were disabled for that input
Semantic predicates were present but were hidden by actions.

...

4514 [main] ERROR enerator.CompositeGeneratorFragment  - java.io.FileNotFoundException: ..\my.packagename.ui\src-gen\my\packagename\projectname\ui\contentassist\antlr\internal\InternalMyDSLParser.java (The system cannot find the file specified)
org.eclipse.emf.common.util.WrappedException: java.io.FileNotFoundException: ..\my.packagename.ui\src-gen\my\packagename\projectname\ui\contentassist\antlr\internal\InternalMyDSLParser.java (The system cannot find the file specified)
    at org.eclipse.xtext.util.Files.readFileIntoString(Files.java:129)
    at org.eclipse.xtext.generator.parser.antlr.AbstractAntlrGeneratorFragment.simplifyUnorderedGroupPredicates(AbstractAntlrGeneratorFragment.java:130)
    at org.eclipse.xtext.generator.parser.antlr.AbstractAntlrGeneratorFragment.simplifyUnorderedGroupPredicatesIfRequired(AbstractAntlrGeneratorFragment.java:118)
    at org.eclipse.xtext.generator.parser.antlr.XtextAntlrUiGeneratorFragment.generate(XtextAntlrUiGeneratorFragment.java:86)

Here is a workaround I've tried (which works) but it's not a solution because the keywords within the language are changing to avoid the parser error:

('newParamA1 = ' paramA1=Integer ';')
| ('newParamB1 = ' paramB1=Integer ';')
| ('newParamC1 = ' paramC1=Integer ';')
| (('newParamA2 = ' paramA2=Integer ';') & ('newParamB2 = ' paramB2=Integer ';'))
| (('newParamA3 = ' paramA3=Integer ';') & ('newParamC2 = ' paramC2=Integer ';'))
| (('newParamB3 = ' paramB3=Integer ';') & ('newParamC3 = ' paramC3=Integer ';'))
| (('newParamA4 = ' paramA4=Integer ';') & ('newParamB4 = ' paramB4=Integer ';') & ('newParamC4 = ' paramC4=Integer ';'))
Was it helpful?

Solution 2

What you want to do is something like this:

You want a simple grammar (as Sebastian described it):

(newParamA = ParamA)? & (newParamB = ParamB)? & (newParamC = ParamC)?

To make sure that at least one parameter is required, you can write your own validator, which could look like this:

class MyDSLValidator extends AbstractMyDSLValidator {
    @Check
    def void atLeastOneParameter(Component component) {
        if (component.newParamA == null && component.newParamB == null && component.newParamC == null) {
            error('requires at least one parameter definition', MyDSLPackage.Literals.COMPONENT__PARAMA);
        }
    }
}

OTHER TIPS

I think what you really want is a validation that ensures that at least one parameter is given on the semantic level rather than on the syntactic level. This will greatly simplify your grammar, e.g you could just use

(newParamA = ParamA)? & (newParamB = ParamB)? & (newParamC = ParamC)?

(parenth. added for clarity)

Also note that it's generally a good idea to avoid spaces in keywords. You should prefer 'paramA' '=' over 'paramA ='. This will greatly improve the error handling in the lexer / parser.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top