如何在ANTLR中使用greedy = false选项访问匹配的属性块?

时间:2011-01-13 04:35:46

标签: java antlr grammar greedy non-greedy

我的ANTLR语法中有一条规则:

COMMENT :  '/*' (options {greedy=false;} : . )* '*/' ;

此规则只是匹配c风格的注释,因此它将接受任意一对/ *和* /以及介于两者之间的任意文本,并且它可以正常工作。

我现在要做的是在规则匹配时捕获/ *和* /之间的所有文本,以使其可以被操作访问。像这样:

COMMENT :  '/*' e=((options {greedy=false;} : . )*) '*/' {System.out.println("got: " + $e.text);

这种方法不起作用,在解析过程中,在到达“/ *”之后的第一个字符时给出“没有可行的选择”

我不清楚是否/如何做到这一点 - 欢迎任何建议或指导,谢谢。

2 个答案:

答案 0 :(得分:4)

请注意,您只需执行以下操作:

getText().substring(2, getText().length()-2)
<{1>} token上的

,因为第一个和最后两个字符始终为COMMENT/*

您也可以删除*/,因为options {greedy=false;} :.*都不合适(尽管没有.+他们 贪婪)(i )。

修改

或者使用.令牌上的setText(...)立即放弃Comment/*。一个小小的演示:

档案*/

T.g

然后生成一个解析器&amp; lexer,编译所有.java文件并运行包含main方法的解析器:

java -cp antlr-3.2.jar org.antlr.Tool T.g
javac -cp antlr-3.2.jar *.java
java -cp .:antlr-3.2.jar TParser 
  (or `java -cp .;antlr-3.2.jar TParser` on Windows)

将产生以下输出:

grammar T;

@parser::members {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream(
                "/* abc */   \n" +
                "            \n" + 
                "/*          \n" +
                "   DEF      \n" + 
                "*/            "
        );
        TLexer lexer = new TLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        TParser parser = new TParser(tokens);
        parser.parse();
    }
}

parse
  :  ( Comment {System.out.printf("parsed :: >\%s<\%n", $Comment.getText());} )+ EOF
  ;

Comment
  :  '/*' .* '*/' {setText(getText().substring(2, getText().length()-2));}
  ;

Space
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

(i)The Definitive ANTLR Reference,第4章,扩展的BNF子规则,第86页。

答案 1 :(得分:1)

试试这个:

COMMENT :
  '/*' {StringBuilder comment = new StringBuilder();} ( options {greedy=false;} : c=. {comment.appendCodePoint(c);} )* '*/' {System.out.println(comment.toString());};

另一种实际返回StringBuilder对象的方法,以便您可以在程序中使用它:

COMMENT returns [StringBuilder comment]:
  '/*' {comment = new StringBuilder();} ( options {greedy=false;} : c=. {comment.append((char)c);} )* '*/';