我正在尝试构建一种可以声明方法和字段的语言,并对泛型有内在的支持。我希望能够使用像String
这样的原始类型,并声明我自己的类。
这应该是有效的语法:
String somePrimitive
class MyClass { }
MyClass someObject;
class List { }
List<String> stringList;
List<MyClass> objectList;
List<String> getNames() { }
我有一个支持这些操作的语法:
Model:
(members+=ModelMembers)*;
ModelMembers:
Class | Field | MethodDeclaration
;
Class:
'class' name=ID '{' '}'
;
Field:
type=Type
name=ID
;
enum PrimitiveType: STRING="String" | NUMBER="Number";
Type:
(
{TypeObject} clazz=[Class] ("<" a+=Type ("," a+=Type)* ">")?
|
{TypePrimitive} type=PrimitiveType
)
;
MethodDeclaration:
returnType=Type name=ID "(" ")" "{"
"}"
;
但它包含错误:
[fatal] rule rule__ModelMembers__Alternatives has non-LL(*) decision due to recursive rule invocations reachable from alts 2,3. Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
问题似乎源于Type
规则是递归的,并且可以匹配为MethodDeclaration
或Field
的开头。
但是,可以找出正在构建的规则,因为该方法在名称后面会有() { }
。
真正让我困惑的是,如果我用简单[Class]
替换递归规则,例如Field: type=[Class] name=ID
(和MethodDeclaration
相同)语法有效。
当我看到Type
的实例时,我发现存在一些歧义,因为它可能导致方法或字段....但是当我用[Class]
替换时,这完全相同。类的实例可以引导到方法或字段。
如何使用Type
模糊不清,但使用[Class]
时不明确?
答案 0 :(得分:1)
这不是您问题的直接答案,但您是否考虑过使用Xbase而不是简单的Xtext?使用Xbase,您可以简单地使用符合您所需要的预定义规则:
还有更多。
以下是一些有用的链接:
如果Xbase不适合您,那么您可以从中学习Xbase-Xtext-Grammar。
答案 1 :(得分:1)
这个语法解析示例代码而不会抛出错误(布局是Terence Parr所青睐的,ANTLR人。我发现它有很大帮助):
Model
: (members+=ModelMembers)*
;
ModelMembers
: Class
| MethodDeclaration
| Field
;
Class
: 'class' name=ID '{' '}'
;
Field
: type=Type name=ID ';'
;
PrimitiveType
: ("String" |"Number")
;
TypeReferenceOrPrimitive
: {TypeClass} type=[Class]
| {TypePrimitive} PrimitiveType
;
Type
: {TypeObject} clazz=[Class] ("<" a+=TypeReferenceOrPrimitive ("," a+=TypeReferenceOrPrimitive)* ">")?
| {TypePrimitive} type=PrimitiveType
;
MethodDeclaration
: returnType=Type name=ID "(" ")" "{" "}"
;
我不是Xtext专家所以可能有更好的方法。我的'诀窍'是 define TypeReferenceOrPrimitive 。为了获得更容易处理的AST,您可能需要更多地使用语法。