antlr4:无法按预期识别令牌

问题描述

我正在尝试使用antlr4构建语法,该语法应该能够将中间解析结果存储为变量,可以访问以供以后使用。我考虑过要使用一个关键字,例如 as (或德语 als ),它将触发此存储功能。除此之外,我还有一个通用令牌 ID ,它将与任何可能的标识符匹配。 存储能力应该是用户的选择。因此,我正在使用?在我的语法定义中。

我的语法如下:

grammar TokenTest;

@header {
package some.package.declaration;
}

AS : 'als' ;
VALUE_ASSIGNMENT : AS ID ;

ID : [a-zA-Z_][a-zA-Z0-9_]+ ;

WS : [ \t\n\r]+ -> skip ;

ANY : . ;

formula  :  identifier=ID (variable=VALUE_ASSIGNMENT)?  #ExpressionIdentifier
;

编译该语法没有失败。但是,当我尝试应用以下TestNG测试时,无法解释其行为:

package some.package.declaration;

import java.util.List;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import some.package.declaration.TokenTestLexer;

public class TokenTest {

    private static List<Token> getTokens(final String input) {
        final TokenTestLexer lexer = new TokenTestLexer(CharStreams.fromString(input));
        final CommonTokenStream tokens = new CommonTokenStream(lexer);
        tokens.fill();
        return tokens.getTokens();
    }

    @DataProvider (name = "tokenData")
    public Object[][] tokenData() {
        return new Object [][] {
            {"result",new String[] {"result"},new int[] {TokenTestLexer.ID}},{"als",new String[] {"als"},new int[] {TokenTestLexer.AS}},{"result als x",new String[] {"result","als","x"},new int[] {TokenTestLexer.ID,TokenTestLexer.AS,TokenTestLexer.ID}},};
    }

    @Test (dataProvider = "tokenData")
    public void testTokenGeneration(final String input,final String[] expectedTokens,final int[] expectedTypes) {
//      System.out.println("test token generation for <" + input + ">");
        Assert.assertEquals(expectedTokens.length,expectedTypes.length);
        final List<Token> parsedTokens = getTokens(input);
        Assert.assertEquals(parsedTokens.size()-1/*EOF is a token*/,expectedTokens.length);
        for (int index = 0; index < expectedTokens.length; index++) {
            final Token currentToken = parsedTokens.get(index);
            Assert.assertEquals(currentToken.getText(),expectedTokens[index]);
            Assert.assertEquals(currentToken.getType(),expectedTypes[index]);
        }
    }

}

第二个测试告诉我 als 一词被解析为 AS 令牌。但是,第三项测试无法正常工作。我认为它是一个 ID 令牌,后跟一个 AS 令牌,最后是一个 ID 令牌。但是,最后一个令牌将被识别为 ANY -令牌。

如果我按以下方式更改 AS -令牌的定义:

fragment AS : 'als' ;

还有另一种奇怪的行为。当然,第二个测试用例不再起作用,因为不再有 AS 令牌。那不足为奇。相反,第三个测试用例中的x将被识别为 ANY 令牌。但是,我认为整个“ als x”序列是一个 VALUE_ASSIGNMENT 令牌。我究竟做错了什么?任何帮助都将非常好。

亲切的问候!

解决方法

但是,第三项测试无法按预期进行。我假设它是一个ID令牌,然后是一个AS令牌,最后是一个ID令牌。但是,最后一个令牌将被识别为ANY令牌

那是因为您定义了:

ID : [a-zA-Z_][a-zA-Z0-9_]+ ;

其中+表示“一个或多个”。您可能想要的是“零个或多个”:

ID : [a-zA-Z_][a-zA-Z0-9_]* ;

但是,我假设整个“ als x”序列是VALUE_ASSIGNMENT令牌。我在做什么错了?

请注意,解析器规则而不是词法分析器规则会跳过空格。这意味着VALUE_ASSIGNMENT仅匹配alsFOO,而不匹配als FOO。此规则可能应该是解析器规则:

value_assignment : AS ID ;