Antlr Tool与antlr runtime的版本一致性问题

1. 意外的问题

  • 在学习Antlr4的visitor模式时,使用IDEA的Antlr插件完成了Hello.g4文件的编译,指定的package为com.sunrise.hello

  • 使用visitor模式遍历语法解析树,遍历过程中打印hello语句

    public class HelloVisitorImpl extends HelloBaseVisitor<String> {
        @Override
        public String visitR(HelloParser.RContext ctx) {
            System.out.printf("hello %s\n", ctx.NAME().getText());
            return super.visitR(ctx);
        }
        // main方法,使用visitor模式遍历语法解析树,以打印hello语句
        public static void main(String[] args) {
            String input = "hello lucy\n" +
                    "hello wold\n" +
                    "by sunrise";
            // 词法解析
            CharStream stream = CharStreams.fromString(input);
            HelloLexer lexer = new HelloLexer(stream);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
    
            // 语法解析
            HelloParser parser = new HelloParser(tokens);
            ParseTree parseTree = parser.r();
    
            // 遍历语法解析树
            HelloVisitorImpl visitor = new HelloVisitorImpl();
            visitor.visit(parseTree);
    
        }
    }
    
  • 运行main()方法,执行报错:

    ANTLR Tool version 4.11.1 used for code generation does not match the current runtime version 4.8Exception in thread "main" java.lang.ExceptionInInitializerError
    	at com.sunrise.hello.visitor.HelloVisitorImpl.main(HelloVisitorImpl.java:26)
    Caused by: java.lang.UnsupportedOperationException: java.io.InvalidClassException: org.antlr.v4.runtime.atn.ATN; Could not deserialize ATN with version 4 (expected 3).
    	at org.antlr.v4.runtime.atn.ATNDeserializer.deserialize(ATNDeserializer.java:187)
    	at com.sunrise.hello.HelloLexer.<clinit>(HelloLexer.java:127)
    	... 1 more
    Caused by: java.io.InvalidClassException: org.antlr.v4.runtime.atn.ATN; Could not deserialize ATN with version 4 (expected 3).
    	... 3 more
    
  • 分析异常栈的栈顶错误信息:代码是由4.11.1版本的Antrl Tool生成的,运行时的时候antlr runtime4.8版本的,二者不匹配

  • 查看IDEA Antlr插件的描述以及maven中配置的antlr-runtime后,发现确实如此:

2. 错误原因分析

  • 从错误提示,大致可以猜出:Antlr Tool版本与antlr runtime应该保持一致
  • 若不了解Antlr Tool和antlr runtime的分工,则无法理解为何要保持一致。
  • 回看Antlr4的官网,发现有如下介绍:
    • complete jar,里面包含Antlr Tool和Java runtime
    • Java runtime jar:负责编译、执行Java语言的parser/lexer
  • 总结起来:Antlr Tool负责将.g4文件编译为指定语言的代码,例如Java语言。Java语言的parser或lexer的编译、执行,则需要依靠antlr runtime
  • 4.x版本的Antlr Tool生成的Java语言的parser和lexer,需要使用4.x的org.antlr:antlr4-runtime

3. 解决办法

  • 要么使用4.8版本的Antlr Tool重新编译.g4文件,要么将org.antlr:antlr4-runtime的版本更新为4.11.1
  • 为了方便,这里选择更新org.antlr:antlr4-runtime的版本

4. 更离奇的错误

  • 现在使用4.11.1版本完成了.g4文件的编译、parser/lexer的Java代码编译

  • 突发奇想,使用grun命令测试语法规则,报错如下:

    $ grun com.sunrise.hello.Hello r -gui
    ANTLR Tool version 4.11.1 used for code generation does not match the current runtime version 4.8ANTLR Runtime version 4.11.1 used for parser compilation does not match the current runtime version 4.8Exception in thread "main" java.lang.ExceptionInInitializerError
            at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
            at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
            at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at org.antlr.v4.gui.TestRig.process(TestRig.java:144)
            at org.antlr.v4.gui.TestRig.main(TestRig.java:119)
    Caused by: java.lang.UnsupportedOperationException: java.io.InvalidClassException: org.antlr.v4.runtime.atn.ATN; Could not deserialize ATN with version 4 (expected 3).
            at org.antlr.v4.runtime.atn.ATNDeserializer.deserialize(ATNDeserializer.java:187)
            at com.sunrise.hello.HelloLexer.<clinit>(HelloLexer.java:127)
            ... 6 more
    Caused by: java.io.InvalidClassException: org.antlr.v4.runtime.atn.ATN; Could not deserialize ATN with version 4 (expected 3).
            ... 8 more
    
  • 又是版本不一致导致的 😂 😂,.g4文件的编译、parser的Java代码编译,都是使用4.11.1版本,但是却使用4.8的antlr runtime运行字节码

  • 总结: .g4文件的编译、parser/lexer的代码编译、parser/lexer字节码的运行,需要保持版本一致!

  • 这也是为什么开源组件喜欢使用maven plugin实现.g4文件的编译,并使用maven property保证maven plugin和antlr-runtime的版本一致的原因

5. 题外话

  • 编译.g4文件生成Java代码,使用的是哪个版本的Antlr,在Java代码中有标识

  • 例如,使用内含4.11.1的IDEA插件编译得到的Java类,第一行就标识了Antlr版本为4.11.1

  • 使用antlr4编译生成的Java代码,标识的Antlr版本为4.8

  • 使用4.7.1的maven plugin编译生成的Java代码,标识的Antlr版本为4.7.1

  • 同时,在Parser、Lexer的代码中,还以static方法做了runtime版本的check

  • 这些标识能告知开发者,应该使用哪个版本的antrl-runtime去编译、执行;这些check,则能避免Antlr Tool与antlr runtime版本不一致带来的问题

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值