2

我正在为公共使用的产品修改 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 */
}
4

3 回答 3

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;}
于 2012-04-17T04:07:30.557 回答
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();}
于 2012-04-16T13:56:50.413 回答
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;}.

另外,请注意,您不要SPACESCOMMENT规则中使用,因为在调用时SPACES执行该skip()方法!

于 2012-04-16T15:23:44.377 回答