我正在为公共使用的产品修改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;} : . )* '*/'
如果我天真地使用上述内容,其他注释会在随后执行树解析器时导致不匹配的令牌错误。 如何忽略未放在“图形”或“状态”前面的所有COMMENT实例?
示例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 */
}
答案 0 :(得分:1)
这是我实际工作的解决方案。 我很喜欢反馈。
基本思路是将评论发送到HIDDEN频道,在我想要的地方手动提取它们, 并使用重写规则在需要时重新插入注释。 提取步骤的灵感来自以下信息: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;}
答案 1 :(得分:0)
这对你有用吗?
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();}
答案 2 :(得分:0)
如何忽略未放在“图表”或“州”前面的所有COMMENT实例?
如果前面有"*/"
或'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;}
。
此外,请注意,您的SPACES
规则中未使用COMMENT
,因为SPACES
执行skip()
方法时会被调用!