如何最好地编写此 xtext 语法

How best to write this xtext grammar

我正在使用Xtext,需要解决以下两个问题。

问题#1

假设我有三个规则 a、b 和 c。我想允许这些规则的任何顺序,除了 b 和 c 应该只出现一次。这样的文法怎么写才好?

这是我想出的:

root:
  a+=a*
  b=b
  a+=a*
  c=c
  a+=a*
;
a: 'a';
b: 'b';
c: 'c';

有没有更好的写根语法的方法? b和c还是要有严格的顺序,不太理想

问题#2

看看这个语法:

root:
    any+=any*
    x=x
    any+=any*
;

any:
    name=ID
    '{'
        any+=any*
    '}'
;

x:
    name='x' '{' y=y '}'
;

y:
    name='y' '{' z=z '}'
;

z:
    name='z' '{' any+=any* '}'
;

使用这个语法,我希望能够编写如下语言:

a {
    b {

    }

    c {
        y {

        }
    }
}

x {
    y {
        z {
            the_end {}
        }
    }
}

但是,由于节点 "y" 出现在 "c" 下,我收到错误消息。这是为什么?是不是因为现在"y"已经在其中一个规则中作为终结符,它不能出现在语法的其他任何地方?

如何修正这个语法?

对于问题#1,我们可以调整语法如下:

root:
  a+=a*
  (
    b=b a+=a* c=c
    |
    c=c a+=a* b=b
  )
  a+=a*
;
a: 'a';
b: 'b';
c: 'c';

另一方面,问题 #2 无法通过语法真正解决,因为解析器永远无法区分 ID 和特殊关键字 "x"、"y" 或 "z" .也许更好的策略是保持语法简单,如下所示: 根: 任何+=任何+ ;

any:
  name=ID
  '{'
    any+=any+
  '}'
;

并通过验证器执行特殊的 x/y/z 层次结构。

对于问题 #1:

root: a+=a* (b=b a+=a* & c=c a+=a*);

对于问题 #2,您需要这样的 datatype rule

IdOrABC: ID | 'a' | 'b' | 'c' ;

并且您必须在 any 规则中使用它,例如 name=IdOrABC 而不是 name=ID