为什么ANTLR 4不将Unicode字符识别为有效令牌?



我一直在努力让ANTLR 4识别输入中的Unicode字符。

我把我的语法简化为一个更简单的测试,我在一个相关问题的答案上找到了这个答案,但我所做的只是改变它应该识别的字符,但它没有起作用。

语法:

grammar Unicode;
stat: E_CODE* EOF;
E_CODE: '↊' | '↋';

测试等级:

class UnicodeTest {
@Test
fun `parse unicode`() {
val lexer = UnicodeLexer(CharStreams.fromString("↊↋"))
val parser = UnicodeParser(CommonTokenStream(lexer))
val result = parser.stat().text
println("Result = <$result>")
assertThat(result).isEqualTo("↊↋<EOF>")
}
}

当我运行这个时,我得到的是:

> Task :test FAILED
line 1:0 token recognition error at: '↊'
line 1:1 token recognition error at: '↋'
Result = <<EOF>>
expected:<"[↊↋]<EOF>"> but was:<"[]<EOF>">
Expected :"[↊↋]<EOF>"
Actual   :"[]<EOF>"

从stderr来看,它似乎正确地将字符串中的字符提取为Unicode(它确实以String开头,所以更好!(,但随后没有将字符识别为有效令牌。

我不知道如何调试这类事情,因为lexer规则被编译成一个巨大的blob,我不知道该如何读取。我可以验证的是lexer内部的tokens只包含一个元素,EOF。

目前已排除:

  • 语法文件本身是UTF-8
  • Java编译器编码肯定设置为UTF-8。
    tasks.withType<JavaCompile> {
    // Why is this not yet the default? :(
    options.encoding = "UTF-8"
    }
    
  • Kotlin编译器的编码应该始终是UTF-8,没有任何更改选项。之所以提到这一点,是因为我不知道哪个编译器用于编译Java类
  • 当我运行测试时,这些测试也以UTF-8的形式运行。
    tasks.withType<Test> {
    useJUnitPlatform()
    defaultCharacterEncoding = "UTF-8"
    }
    
  • 在主程序中运行代码时,我也遇到了同样的问题,在命令行上可以看到-Dfile.encoding=UTF-8在命令行中

变通办法?

  • 如果我将语法文件更改为显式使用Unicode转义,那么它就可以工作了!好吧,ANTLR是如何读取文件的,它并不像很多人说的那样默认为UTF-8。不过,我计划使用大量的Unicode,并且不想逃避所有内容。所以我想我只需要找到一些合适的Gradle配置,在编译器运行时强制进行编码/
编译源文件的方式(AFAIK(并不重要。

使用您的示例语法,我运行了以下测试:

InputStream inputStream = new ByteArrayInputStream("↊↋".getBytes());
UnicodeLexer lexer = new UnicodeLexer(CharStreams.fromStream(inputStream, StandardCharsets.UTF_8));
UnicodeParser parser = new UnicodeParser(new CommonTokenStream(lexer));
System.out.println(parser.stat().getText());

和:

UnicodeLexer lexer = new UnicodeLexer(CharStreams.fromFileName("input.txt", StandardCharsets.UTF_8));
UnicodeParser parser = new UnicodeParser(new CommonTokenStream(lexer));
System.out.println(parser.stat().getText());

(其中文件input.txt包含↊↋(

两者都导致以下内容被打印到我的控制台上:

↊↋<EOF>

也就是说,你有没有尝试将编码添加到CharStream?

最新更新