我正在修改一个公共使用的产品的DSL语法。目前,所有的/*...*/注释都被默默地忽略了,但是我需要修改它,以便将放置在某些关键元素之前的注释解析到AST中。我需要保持向后兼容性,这样用户仍然可以在整个DSL中随意添加注释,并且只包括那些关键注释。
解析器语法目前看起来有点像这样:
grammar StateGraph;
graph: 'graph' ID '{' graph_body '}';
graph_body: state+;
state: 'state' ID '{' state_body '}';
state_body: transition* ...etc...;
transition: 'transition' (transition_condition) ID ';';
COMMENT: '/*' ( options {greedy=false;} : . )* '*/' {skip();}放置在“graph”和“state”元素之前的注释包含有意义的描述和注释,需要包含在已解析的AST中。所以我已经修改了这两条规则,不再跳过评论:
graph: comment* 'graph' ID '{' graph_body '}';
state: comment* 'state' ID '{' state_body '}';
COMMENT: '/*' ( options {greedy=false;} : . )* '*/'如果我天真地使用上面的注释,那么在随后执行树解析器时,其他注释会导致不匹配的令牌错误。如何忽略没有放在'graph‘或'state’前面的所有注释实例?
DSL示例如下:
/* Some description
* @some.meta.info
*/
graph myGraph {
/* Some description of the state.
* @some.meta.info about the state
*/
state first {
transition if (true) second; /* this comment ignored */
}
state second {
}
/* this comment ignored */
}发布于 2012-04-17 12:07:31
这就是我实际得到的解决方案。我希望得到反馈。
基本思想是将注释发送到隐藏通道,在我想要它们的地方手动提取它们,并使用重写规则在需要的地方重新插入注释。提取步骤的灵感来自这里的信息:http://www.antlr.org/wiki/pages/viewpage.action?pageId=557063。
现在的语法是:
grammar StateGraph;
@tokens { COMMENTS; }
@members {
// matches comments immediately preceding specified token on any channel -> ^(COMMENTS COMMENT*)
CommonTree treeOfCommentsBefore(Token token) {
List<Token> comments = new ArrayList<Token>();
for (int i=token.getTokenIndex()-1; i >= 0; i--) {
Token t = input.get(i);
if (t.getType() == COMMENT) {
comments.add(t);
}
else if (t.getType() != WS) {
break;
}
}
java.util.Collections.reverse(comments);
CommonTree commentsTree = new CommonTree(new CommonToken(COMMENTS, "COMMENTS"));
for (Token t: comments) {
commentsTree.addChild(new CommonTree(t));
}
return commentsTree;
}
}
graph
: 'graph' ID '{' graph_body '}'
-> ^(ID {treeOfCommentsBefore($start)} graph_body);
graph_body: state+;
state
: 'state' ID '{' state_body '}'
-> ^(ID {treeOfCommentsBefore($start)} staty_body);
state_body: transition* ...etc...;
transition: 'transition' (transition_condition) ID ';';
COMMENT: '/*' .* '*/' {$channel=HIDDEN;}发布于 2012-04-16 21:56:50
这对你有效吗?
grammar StateGraph;
graph: 'graph' ID '{' graph_body '}';
graph_body: state+;
state: .COMMENT 'state' ID '{' state_body '}';
state_body: .COMMENT transition* ...etc...;
transition: 'transition' (transition_condition) ID ';';
COMMENT: '/*' ( options {greedy=false;} : . )* '*/' {skip();}发布于 2012-04-16 23:23:44
如何忽略没有放在'graph‘或'state’前面的所有注释实例?
您可以在注释的结束"*/"之后检查前面是否有'graph'或'state',中间有一些可选的空格,这样就可以做到这一点。如果是这样的话,什么都不要做,如果不是这样的话,谓词就会失败,您就会违反规则,简单地skip()注释令牌。
在ANTLR语法中,如下所示:
COMMENT
: '/*' .* '*/' ( (SPACE* (GRAPH | STATE))=> /* do nothing, so keep this token */
| {skip();} /* or else, skip it */
)
;
GRAPH : 'graph';
STATE : 'state';
SPACES : SPACE+ {skip();};
fragment SPACE : ' ' | '\t' | '\r' | '\n';请注意,默认情况下,.*和.+是不贪婪的:不需要设置options{greedy=false;}。
另外,要注意不要在COMMENT规则中使用SPACES,因为SPACES在被调用时会执行skip()方法!
https://stackoverflow.com/questions/10168844
复制相似问题