令牌类型取决于以下令牌

问题描述

| 我坚持一个非常简单的语法。谷歌搜索和读书没有帮助。我是最近才开始使用ANTLR的,所以这可能是一个非常简单的问题。 我正在尝试使用ANTLR v3编写一个非常简单的Lexer。
grammar TestLexer;

options {
  language = Java;
}

TEST_COMMENT
    :   \'/*\' WS? TEST WS? \'*/\'
    ;

ML_COMMENT
    :   \'/*\' ( options {greedy=false;} : .)* \'*/\' {$channel=HIDDEN;}
    ;

TEST    :   \'TEST\'
    ;

WS  :   (\' \' | \'\\t\' | \'\\n\' | \'\\r\' | \'\\f\')+ {$channel=HIDDEN;}
    ;
测试班:
public class TestParserInvoker {
    private static void extractCommandsTokens(final String script) throws RecognitionException {

        final ANTlrstringStream input = new ANTlrstringStream(script);
        final Lexer lexer = new TestLexer(input);

        final TokenStream tokenStream = new CommonTokenStream(lexer);
        Token t;
        do {
            t = lexer.nextToken();
            if (t != null) {
                System.out.println(t);
            }
        } while (t == null || t.getType() != Token.EOF);
    }


    public static void main(final String[] args) throws RecognitionException {
        final String script = \"/* TEST */\";
        extractCommandsTokens(script);
    }
}
因此,当测试字符串为\“ / * TEST * / \”时,词法分析器将按预期生成两个标记。一种类型为TEST_COMMENT,另一种类型为EOF。一切都好。 但是,如果测试字符串末尾包含一个额外的空格:\“ / * TEST * / \” lexer会生成三个标记:ML_COMMENT,WS和EOF。 为什么第一个令牌获取ML_COMMENT类型?我认为标记的检测方式仅取决于语法中词法分析器规则的优先级。当然,它不应该依赖于以下标记。 感谢帮助! 附言我可以使用lexer选项filter = true-令牌将获得正确的类型,但是这种方法需要在令牌定义中进行额外的工作。老实说,我不想使用这种词法分析器。     

解决方法

        ANTLR从最高规则开始向下标记字符流,并尝试尽可能地匹配。因此,是的,我也希望为
\"/* TEST */\"
\"/* TEST */ \"
创建一个
TEST_COMMENT
。您始终可以查看词法分析器的生成源代码,以了解为什么它选择为第二个输入创建一个“ 5”。 无论是错误还是预期的行为,我都不会使用看起来很像的单独词法分析器规则。您能在这里解释您真正要解决的问题吗?   user776872写道:      我可以使用lexer选项filter = true-令牌将获得正确的类型,但是这种方法需要在令牌定义中进行额外的工作。老实说,我不想使用这种词法分析器。 我不太明白这句话。您只对输入源的一部分感兴趣吗?在这种情况下,
filter=true
无疑是一个不错的选择。如果要标记所有输入源,则不应使用
filter=true
。 编辑 如果要区分多行注释和Javadoc注释,最好将它们保持在同一规则中,并以the8开头的令牌类型进行更改,如下所示:
grammar T;

// options

tokens {
  DOC_COMMENT;
}

// rules

COMMENT
  :  \'/*\' (~\'*\' .*)? \'*/\'
  |  \'/**\' ~\'/\' .* \'*/\' {$type=DOC_COMMENT;}
  ;
请注意,在ANTLR中,默认情况下,
.*
.+
都是非贪婪的(与流行的看法相反)。 演示版
grammar T;

tokens {
  DOC_COMMENT;
}

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

parse
  :  (t=. {System.out.println(tokenNames[$t.type] + \" :: \" + $t.text);})* EOF
  ;

COMMENT
  :  \'/*\' (~\'*\' .*)? \'*/\'
  |  \'/**\' ~\'/\' .* \'*/\' {$type=DOC_COMMENT;}
  ;

SPACE
  :  \' \' {$channel=HIDDEN;}
  ;
产生: bart @ hades:〜/编程/ ANTLR / Demos / T $ java -cp antlr-3.3.jar org.antlr.Tool T.g bart @ hades:〜/编程/ ANTLR / Demos / T $ javac -cp antlr-3.3.jar * .java bart @ hades:〜/编程/ ANTLR / Demos / T $ java -cp。:antlr-3.3.jar TParser 评论:: / ** / 评论:: / * foo * / DOC_COMMENT :: / ** bar * /