Xtext :确定何时必须调用可选的

Xtext : identify when a optional must be call

我正在使用 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'

该规则适用于第一个,但不适用于第二个。预计括号之间没有关系声明。 我认为这是由于使用以下形式调用规则 relationDeclaration 的声明:

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

我不明白哪里出了问题。 我错过了什么? 我该怎么做才能让它发挥作用?

提前致谢。

在你的 RelationDeclaration 语法中,你似乎错过了一些可选的标记问号 (isPrivate?='private')? (varsAreDisjoint?='disj')?(同样的问题遍布整个语法)

?= 将属性声明为可选的,但只有围绕规则调用的 ? 使其实际上是可选的