Xtext : определить, когда необходимо вызвать необязательный параметр

Я использую xtext для определения грамматики. У меня проблема с оценкой синтаксиса во время выполнения.

правило - подписьДекларация. Вот полная грамматика:

// automatically generated by Xtext
grammar org.xtext.alloy.Alloy with org.eclipse.xtext.common.Terminals

import "http://fr.cuauh.als/1.0" 
import "http://www.eclipse.org/emf/2002/Ecore" as ecore

//specification ::= [module] open* paragraph* 
//ok
Specification returns Specification:
    {Specification}
    (module=Module)?
    (opens+=Library (opens+=Library)*)?
    (paragraphs+=Paragraph (paragraphs+=Paragraph)*)?;

//module ::= "module" name  [ "["  ["exactly"] name  ("," ["exactly"] num)*    "]" ]
//module ::= "module" name?  [ "["  ["exactly"] name  ("," ExactlyNum )* "]" ]
//ok
Module returns Module:
    {Module}
    'module' (name=IDName)? ('['(exactly?='exactly')? extensionName=[IDref] (nums+=ExactlyNums ( "," nums+=ExactlyNums)*)?']')?
    ;

IDName returns IDName:
    name=ID
;
terminal ID         : '^'?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'/')*;
//open ::= ["private"]  "open"  name  [ "[" ref,+ "]" ]  [ "as" name ]
//open ::= ["private"]  "open"  path  [ "[" ref,+ "]" ]  [ "as" name ]
//ok
Library returns Library:
    {Library}
    (private?='private')? 'open' path=EString ('['references+=Reference (',' references+=Reference)*']')? ('as' alias=Alias)? 
    ;
//a path 
//ok
//terminal PATH returns ecore::EString :
//  ('a'..'z'|'A'..'Z'|'_'|'.')+('/'('a'..'z'|'A'..'Z'|'_'|'.')+)*
//;

//paragraph ::= factDecl | assertDecl | funDecl | cmdDecl | enumDecl | sigDecl
//paragraph ::= factDecl | assertDecl | funDecl | predDecl | cmdDecl | enumDecl | sigDecl
//ok
Paragraph returns Paragraph:
    FactDeclaration | AssertDeclaration | FunctionDeclaration | PredicatDeclaration | CmdDeclaration | EnumerationDeclaration | SignatureDeclaration;

//cmdDecl ::= [name ":"] ("run"|"check") (name|block) scope
//cmdDecl ::= [name ":"] command (ref|block) scope ["expect (0|1)"]
//ok
CmdDeclaration returns CmdDeclaration:
    (name=IDName ':')? operation=cmdOp referenceOrBlock=ReferenceOrBlock (scope=Scope)? (expect?='expect' expectValue=EInt)?;

//ok
ReferenceOrBlock returns ReferenceOrBlock:
    BlockExpr | ReferenceName;  

//sigDecl ::= sigQual* "sig" name,+ [sigExt] "{" decl,* "}" [block]
//sigDecl ::= ["private"] ["abstract"] [quant] "sig" name [sigExt] "{" relDecl,* "}" [block]
//ok
SignatureDeclaration returns SignatureDeclaration:
    {SignatureDeclaration}
    (isPrivate?='private')? (isAbstract?='abstract')? (quantifier=SignatureQuantifier)? 'sig' name=IDName (extension=SignatureExtension)? '{'
    (relations+=RelationDeclaration ( ',' =>relations+=RelationDeclaration)* )? 
    '}'
    (block=Block)?;

//ok
SignatureExtension returns SignatureExtension:
    SignatureinInheritance | SignatureInclusion;


TypeScopeTarget returns TypeScopeTarget:
    Int0 | Seq | ReferenceName;

//name ::= ("this" | ID) ["/" ID]*
//ok do not need to be part of the concrete syntax
//Name returns Name:
//  thisOrId=ThisOrID ('/'ids+=ID0( "/" ids+=ID0)*)?;

//ok do not need to be part of the concrete syntax
//ThisOrID returns ThisOrID:
//  ID0 | This;

EBoolean returns ecore::EBoolean:
    'true' | 'false';

//["exactly"] num
//ok
ExactlyNums returns ExactlyNums:
    exactly?='exactly' num=Number;

//ok do not need to be part of the concrete syntax
//  IDName | IDref;

IDref returns IDref:
    namedElement=[IDName]
;


This returns This:
    {This}
    'this'
    ;

EString returns ecore::EString:
    STRING | ID;

//ok
EInt returns ecore::EInt:
    '-'? INT;

Alias returns Alias:
    {Alias}
    name=IDName;



//factDecl ::= "fact" [name] block
//ok
FactDeclaration returns FactDeclaration:
    'fact' (name=IDName)? block=Block;

//assertDecl ::= "assert" [name] block
//ok
AssertDeclaration returns AssertDeclaration:
    'assert' (name=IDName)? block=Block ;

//funDecl ::= ["private"] "fun" [ref "."] name "(" decl,* ")" ":" expr block
//funDecl ::= ["private"] "fun" [ref "."] name "[" decl,* "]" ":" expr block
//funDecl ::= ["private"] "fun" [ref "."] name                ":" expr block
//
//funDecl ::= ["private"] "fun" [ref "."] name ["(" paramDecl,* ")" | "[" paramDecl,* "]" ] ":" expr block
//ok
FunctionDeclaration returns FunctionDeclaration:
    (private?='private')? 'fun' (reference=[Reference] ".")?    name=IDName
        ('(' (parameters+=ParameterDeclaration ( "," parameters+=ParameterDeclaration)*)? ')'|
         '[' (parameters+=ParameterDeclaration ( "," parameters+=ParameterDeclaration)*)? ']')?
        ':' ^returns=Expression
        block=Block;

//funDecl ::= ["private"] "pred" [ref "."] name "(" decl,* ")" block
//funDecl ::= ["private"] "pred" [ref "."] name "[" decl,* "]" block
//funDecl ::= ["private"] "pred" [ref "."] name                block
//
//predDecl ::= ["private"] "pred" [ref "."] name ["(" paramDecl,* ")" | "[" paramDecl,* "]" ] ":" block
//ok
PredicatDeclaration returns PredicatDeclaration:
    (private?='private')? 'pred' (reference=[Reference|EString] ".")? name=IDName
        ('(' (parameters+=ParameterDeclaration ( "," parameters+=ParameterDeclaration)*)? ')'|
         '[' (parameters+=ParameterDeclaration ( "," parameters+=ParameterDeclaration)*)? ']')?
        block=Block;


//enumDecl ::= "enum" name "{" name  ("," name)*  "}"
//enumDecl ::= "enum" name "{" enumEl  ("," enumEl)*  "}"
//ok
EnumerationDeclaration returns EnumerationDeclaration:
    'enum' name=IDName '{' enumeration+=EnumerationElement ( "," enumeration+=EnumerationElement)* '}';


//ok
EnumerationElement returns EnumerationElement:
    {EnumerationElement}
    name=IDName;

//"lone" | "one" | "some" 
//ok
enum SignatureQuantifier returns SignatureQuantifier:
    lone = 'lone' | one = 'one' | some = 'some';


//decl ::= ["private"] ["disj"] name,+ ":" ["disj"] expr
//decl ::= ["private"] ["disj"] name,+ ":" ["disj"] expr
//ok
RelationDeclaration returns RelationDeclaration:
    (isPrivate?='private')? (varsAreDisjoint?='disj')? names+=VarDecl (',' names+=VarDecl)* ':' (expressionIsDisjoint?='disj')? expression=Expression;

//sigExt ::= "extends" ref
//ok
SignatureinInheritance returns SignatureinInheritance:
    'extends' extends=Reference;
//sigExt ::= "in" ref ["+" ref]*
//ok
SignatureInclusion returns SignatureInclusion:
    'in' includes+=Reference ( "+" includes+=Reference)* ;

//ok
VarDecl returns VarDecl:
    {VarDecl}
    name=IDName;

//decl ::= ["private"] ["disj"] name,+ ":" ["disj"] expr
//ok
ParameterDeclaration returns ParameterDeclaration:
    (isPrivate?='private')? (varsAreDisjoint?='disj')? names+=VarDecl ( "," names+=VarDecl)* ':' (expressionIsDisjoint?='disj')? expression=Expression;

//("run"|"check")
//ok
enum cmdOp returns cmdOp:
    run = 'run' | check = 'check';


//expr ::= 
//1)          "let" letDecl,+ blockOrBar
//2)        | quant decl,+    blockOrBar
//3)        | unOp expr
//4)        | expr binOp   expr
//5)        | expr arrowOp expr
//6)        | expr ["!"|"not"] compareOp expr
//7)        | expr ("=>"|"implies") expr "else" expr
//8)        | expr "[" expr,* "]"
//9)        |     number
//10)       | "-" number
//11)       | "none"
//12)       | "iden"
//13)       | "univ"
//14)       | "Int"
//15)       | "seq/Int"
//16)       | "(" expr ")"
//17)       | ["@"] Name
//18)       | block
//19)       | "{" decl,+ blockOrBar "}" 

//  expr ::= leftPart [rightPart]
Expression returns Expression:
    lhs=NonLeftRecursiveExpression (=>parts=NaryPart)?;     

//4)        | expr binOp   expr
//5)        | expr arrowOp expr
//6)        | expr ["!"|"not"] compareOp expr
//7)        | expr ("=>"|"implies") expr "else" expr
//8)        | expr "[" expr,* "]"
//ok
NaryPart returns NaryPart:
    BinaryOrElsePart | CallPart;

//4)        | expr binOp   expr
//5)        | expr arrowOp expr
//6)        | expr ["!"|"not"] compareOp expr
//7)        | expr ("=>"|"implies") expr "else" expr
//
//7)        | expr ("=>"|"implies") expr "else" expr
//4)5)6)    | expr binaryOperator expr*
//ok
BinaryOrElsePart returns BinaryOrElsePart:
    =>('=>'|'implies') rhs=Expression (=>'else' else=Expression)? |
    operator=BinaryOperator rhs=Expression ;

//8)        | expr "[" expr,* "]"
//it is just the right part
//ok
CallPart returns CallPart:
    {CallPart}
    '['(params+=Expression ( "," params+=Expression)*)?']';


//1)          "let" letDecl,+ blockOrBar
//2)        | quant decl,+    blockOrBar
//19)       | "{" decl,+ blockOrBar "}" 
//18)       | block
//          | terminalExpression
NonLeftRecursiveExpression returns NonLeftRecursiveExpression:
    LetExpression | QuantifiedExpression | CurlyBracketsExpression | BlockExpr | TerminalExpression;

//1)          "let" letDecl,+ blockOrBar
//ok
LetExpression returns LetExpression:
    'let' letDeclarations+=LetDeclaration ( "," letDeclarations+=LetDeclaration)* blockOrBar=BlockOrBar;

//2)        | quant decl,+    blockOrBar
//ok
QuantifiedExpression returns QuantifiedExpression:
    quantifier=QuantifiedExpressionQuantifier varDeclaration+=VarDeclaration ( "," varDeclaration+=VarDeclaration)* blockOrBar=BlockOrBar;

//
//binOp ::= "||" | "or" | "&&" | "and" | "&" | "<=>" | "iff" | "=>" | "implies" | "+" | "-" | "++" | "<:" | ":>" | "." | "<<" | ">>" | ">>>"
//compareOp ::= "=" | "in" | "<" | ">" | "=<" | ">="
//arrowOp ::= ["some"|"one"|"lone"|"set"] "->" ["some"|"one"|"lone"|"set"]
//ok
BinaryOperator returns BinaryOperator:
    RelationalOperator | CompareOperator | ArrowOperator;

//ok
RelationalOperator returns RelationalOperator:
    operator=RelationalOp;

//binOp ::= "||" | "or" | "&&" | "and" | "&" | "<=>" | "iff" | "=>" | "implies" | "+" | "-" | "++" | "<:" | ":>" | "." | "<<" | ">>" | ">>>"
//ok
enum RelationalOp returns RelationalOp:
                or = '||' | and = '&&' | union = '+' | intersection = '&' | difference = '-' | equivalence = '<=>' | override = '++' 
                | domain = '<:' | range = ':>' | join = '.' ; // | lshift = '<<' | rshift = '>>' | rrshift = '>>>'; 

//["!"|"not"] compareOp
//ok
CompareOperator returns CompareOperator:
    (negated?='!' | negated?='not')? operator=CompareOp;

//compareOp ::= "=" | "in" | "<" | ">" | "=<" | ">="
enum CompareOp returns CompareOp:
                equal = '=' | inclusion = 'in' | lesser = '<' | greater = '>' | lesserOrEq = '<=' | greaterOrEq = '>=';

//arrowOp ::= ["some"|"one"|"lone"|"set"] "->" ["some"|"one"|"lone"|"set"]
//ok
ArrowOperator returns ArrowOperator:
    {ArrowOperator}
    (leftQuantifier=ArrowQuantifier)? '->' (=>rightQuantifier=ArrowQuantifier)?;

//"some"|"one"|"lone"|"set"
//ok
enum ArrowQuantifier returns ArrowQuantifier:
                lone = 'lone' | one = 'one' | some = 'some' | set = 'set' ; 

//19)       | "{" decl,+ blockOrBar "}" 
//ok
CurlyBracketsExpression returns CurlyBracketsExpression:
    '{' varDeclarations+=VarDeclaration ( "," varDeclarations+=VarDeclaration)* blockOrBar=BlockOrBar '}';

//blockOrBar ::= block
//blockOrBar ::= "|" expr
//ok
BlockOrBar returns BlockOrBar:
    BlockExpr | Bar;    

//blockOrBar ::= "|" expr
//ok
Bar returns Bar:
    '|' expression=Expression;

//block ::= "{" expr* "}"
//ok
BlockExpr returns BlockExpr:
    {BlockExpr}
    '{' (expressions+=Expression ( "," expressions+=Expression)*)?'}';

//3)         unOp expr
//         | finalExpression    
TerminalExpression returns TerminalExpression:
    UnaryExpr | finalExpression ;   

//3)         unOp expr
//ok
UnaryExpr returns UnaryExpr:
    unOp=UnaryOperator expression=TerminalExpression;

//unOp ::= "!" | "not" | "no" | "some" | "lone" | "one" | "set" | "seq" | "#" | "~" | "*" | "^"
//unOp ::= "!" | "not" |"#" | "~" | "*" | "^"
//ok
enum UnaryOperator returns UnaryOperator:
                not = 'not' | card = '#' | transpose = '~' | reflexiveClosure = '*' | closure = '^' | not2 = '!';


//16)       | "(" expr ")"
//9)        |     number
//10)       | "-" number
//17)       | ["@"] Name
//11)       | "none"
//12)       | "iden"
//13)       | "univ"
//14)       | "Int"
//15)       | "seq/Int"

//16)       | "(" expr ")"
//10)       | ["-"] number
//17)       | "@" Name
//17)       | reference
//12)13)    | constante
finalExpression returns TerminalExpression: 
    BracketExpression | NumberExpression | NotExpandedExpression | ReferenceExpression | ConstantExpression;    

//16)       | "(" expr ")"
//ok    
BracketExpression returns BracketExpression:
    '('expression=Expression')';

//9)        |     number
//10)       | "-" number
//ok    
Number returns Number:
    NumberExpression;

//ok
NumberExpression returns NumberExpression:
    value=EInt;

//17)       | ["@"] Name
//17)       | "@" Name
//ok
NotExpandedExpression returns NotExpandedExpression:
    '@' name=[IDref];

//ok
ReferenceExpression returns ReferenceExpression:
    reference=Reference;

//ref ::= name | "univ" | "Int" | "seq/Int"
//ok
Reference returns Reference:
    ReferenceName | ConstanteReference;

//ok
ConstanteReference returns ConstanteReference:
    cst=constanteRef;

//13)       | "univ"
//14)       | "Int"
//15)       | "seq/Int"
//ok
enum constanteRef returns constanteRef:
                int = 'Int' | seqint = 'seq/Int' | univ = 'univ';

//ok
ReferenceName returns ReferenceName:
    name=IDref;

//ok
ConstantExpression returns ConstantExpression:
    constante=Constant;

//11)       | "none"
//12)       | "iden"
//ok
enum Constant returns Constant:
                none = 'none' | iden = 'iden';


//ok    
Block returns Block:
    BlockExpr;

//letDecl ::= name "=" expr
//ok
LetDeclaration returns LetDeclaration:
    varName=VarDecl '=' expression=Expression;

//quant ::= "all" | "no" | "some" | "lone" | "one" | "sum"
//quant ::= "all" | "no" | "some" | "lone" | "one" | "null"
//ok
enum QuantifiedExpressionQuantifier returns QuantifiedExpressionQuantifier:
                no = 'no' | one = 'one' | lone = 'lone' | some = 'some' | all = 'all' | null = 'null';

//decl ::= ["private"] ["disj"] name,+ ":" ["disj"] expr
//ok
VarDeclaration returns VarDeclaration:
    (isPrivate?='private')? (varsAreDisjoint?='disj')? names+=VarDecl ( "," names+=VarDecl)* ':' (expressionIsDisjoint?='disj')? expression=Expression;


//scope ::= "for" number                   ["expect" (0|1)]
//scope ::= "for" number "but" typescope,+ ["expect" (0|1)]
//scope ::= "for"              typescope,+ ["expect" (0|1)]
//scope ::=                                ["expect" (0|1)]
//
//scope ::= "for" [number] ["but"] typescope,* 
//ok
Scope returns Scope:
    {Scope}
    'for' (number=Number)? (but?='but')? (typeScope+=TypeScope ( "," typeScope+=TypeScope)*)?;

//typescope ::= ["exactly"] number [name|"int"|"seq"]
//typescope ::= ExactlyNumber target
TypeScope returns TypeScope:
    num=ExactlyNums target=[TypeScopeTarget];


//[name|"int"|"seq"]
//[Validname|"int"|"seq"]
//ok
TypeScopeTarget_Impl returns TypeScopeTarget:
    {TypeScopeTarget}
    ;

Int0 returns Int:
    {Int}
    'Int'
    ;

Seq returns Seq:
    {Seq}
    'Seq'
    ;

Но во время выполнения редактора у меня есть следующая ошибка на маленьком примере:

sig A {}
sig B {
    a : A
}

Multiple markers at this line (line a : A)
- no viable alternative at input 'A'
- missing EOF at '->'
- missing '}' at 'a'

правило работает для первого, но не для второго. Ожидается, что между скобками нет отношения. Я думаю, что это связано с объявлением вызова правила ratioDeclaration с формой:

(relations+=RelationDeclaration ( ',' relations+=RelationDeclaration)*)?

Я не могу понять, что не так. Что я пропустил? Что я могу сделать, чтобы заставить его работать?

Заранее спасибо.


person user2858691    schedule 27.12.2015    source источник
comment
Вам нужно предоставить больше вашей грамматики. Например. как выглядят VarDecl и Expression? Всегда хорошей стратегией является сокращение случая до минимального полностью воспроизводимого примера. Часто вы сами решаете проблему, делая это. Если нет, другим будет легче понять это позже.   -  person Sven Efftinge    schedule 28.12.2015
comment
Привет! Спасибо за внимание, я добавил детали в грамматику. В первой версии я старался сделать ее простой для большего понимания.   -  person user2858691    schedule 28.12.2015
comment
грамматика еще не закончена. интересная часть: каким выражением следует анализировать «A» после «:»? СсылочноеВыражение?   -  person Christian Dietrich    schedule 28.12.2015
comment
Я забыл это правило, я просто добавил его   -  person user2858691    schedule 29.12.2015


Ответы (1)


в вашей грамматике для RelationDeclaration кажется, что вы пропустили некоторые необязательные знаки вопроса (isPrivate?='private')? (varsAreDisjoint?='disj')? (та же проблема во всей грамматике)

?= объявляет атрибут необязательным, но только ? вокруг вызова правила делает его фактически необязательным

person Christian Dietrich    schedule 28.12.2015
comment
Привет, спасибо за ответ. В моей модели isPrivate является логическим значением, запись isPrivate?='private' должна проверять, написано ли ключевое слово 'private', не так ли? Я пробовал с (isPrivate?='private')? (varsAreDisjoint?='disj')? в декларации отношения правила и проблема сохраняется, должен ли я попробовать всю грамматику? PS: То же самое касается ключевого слова varsAreDisjoint. - person user2858691; 29.12.2015
comment
нет, с точки зрения грамматики isPrivate?='private' совпадает с 'private', поэтому это необязательно. вариант использования для этого (flag?='true' | 'false'). поэтому, если у вас нет альтернатив или вы пометили его как необязательный, он обязателен, и флаг всегда будет истинным. И вы должны использовать один и тот же шаблон во всех местах, где у вас есть этот флаг (ваша грамматика не завершена, поэтому я не могу попробовать) - person Christian Dietrich; 29.12.2015
comment
Я добавил полную грамматику с изменениями, которые вы предложили. Я попробовал это, но то же самое продолжается. - person user2858691; 29.12.2015
comment
ваша грамматика не генерируется (она остается рекурсивной) - person Christian Dietrich; 29.12.2015
comment
К сожалению, я забыл сгенерировать, когда пытался. Я исправил грамматику, чтобы избежать левой рекурсии, и теперь моя проблема решена, благодаря вам. Я внес исправление в грамматику выше, все еще есть некоторые ошибки, но я думаю, что справлюсь, спасибо. - person user2858691; 29.12.2015