以下是我实际语法的简化版本: -
grammar org.hello.World
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate world "http://www.hello.org/World"
Model:
content=AnyContent greetings+=Greeting*;
AnyContent:
(ID | ANY_OTHER)*
;
Greeting:
'<hello>' name=ID '</hello>';
terminal ID:
('a'..'z'|'A'..'Z')+
;
terminal ANY_OTHER:
.
;
如果输入如下,则使用上面的语法: -
&LT;喜&GT;&LT;你好&GT;世界&LT; /你好&GT;
然后我收到一个语法错误,指出不匹配的字符&#39; i&#39;期待第2栏的“ 。
我的要求是AnyContent应匹配&#34;&lt; hi&gt;&#34; ,任何人都可以指导我如何实现这一目标吗?
答案 0 :(得分:1)
如果你想用Xtext制作它。我建议你解决你的问题。你的第一个问题是语法,你需要解析你的文件。第二个问题是语义问题,你想给出一个&#34; sense&#34;到你的objets并告诉谁是容器。定义容器,XML的包含不能在你的语法中完成。
制作自定义Ecore,并使用开始和结束标记制作简单的语法。您并不真正关心标签的名称。 示例:
Model returns XmlFile: (StartTag|EndTag|Text)+;
Text returns Text: text=STRING;
StartTag returns StartTag: '<' name=ID '>';
EndTag returns EndTag: '</' name=ID '>';
更改TokenSource。令牌源将令牌提供给您的Parser。您可以覆盖令牌的性质,合并或拆分它们。
这里的想法是将所有令牌合并到">"
和"</"
之间。
此标记表示文本,因此您可以为包含此元素之间的所有元素创建单个标记。示例:
class CustomTokenSource extends XtextTokenStream{
new(TokenSource tokenSource, ITokenDefProvider tokenDefProvider) {
super(tokenSource,tokenDefProvider)
}
override LT(int k) {
var Token token = super.LT(k)
if(token != null && token.text != null) token.tokenOverride(k);
token
}
在此示例中,您需要在方法&#34; tokenOverride&#34;上添加自定义代码。
在解析器上添加自定义令牌源:
class XDSLParser extends DSLParser{
override protected XtextTokenStream createTokenStream(TokenSource tokenSource) {
return new CustomTokenSource(tokenSource, getTokenDefProvider());
}
}
计算容器:解析后可以计算元素的包含。在它之后,您可以获得您的模型并随意更改它。要做到这一点,你需要覆盖方法&#34; doParse&#34;你的Parser&#34; XDSLParser&#34;如下:
override protected IParseResult doParse(String ruleName, CharStream in, NodeModelBuilder nodeModelBuilder, int initialLookAhead) {
var IParseResult result = super.doParse( ruleName, in, nodeModelBuilder, initialLookAhead)
//Give you model
result.rootASTElement;
return result
}
注意:解析后获得的模型将是平坦的。 xmlFile对象将包含良好顺序中的所有元素。您需要编写一个算法来在AST模型上构建容器。
答案 1 :(得分:0)
由于Xtext使用的antlr词法分析器的性质,这将需要在语法中进行大量调整。词法分析器不会回滚关键字<hello>
:只要它看到<
后跟h
,它就会尝试使用hello-token。这些方面的东西可以起作用:
Model:
content=AnyContent greetings+=Greeting*;
AnyContent:
(ID | ANY_OTHER | '<' (ID | ANY_OTHER | '/' | '>') | '/' | '>' | 'hello')*
;
Greeting:
'<' 'hello '>' name=ID '<' '/' 'hello' '>';
terminal ID:
('a'..'z'|'A'..'Z')+
;
terminal ANY_OTHER:
.
;
这种方法不会扩展到现实世界的语法,但也许有助于走上一些工作轨道。