antlr v3上下文感知条件评论包含

时间:2012-04-16 04:49:56

标签: comments antlr channel

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

3 个答案:

答案 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()方法时会被调用!