Antlr4 语法存在错误但语法分析器不报错的问题

最近使用Antlr4时,遇到了编写的语法存在错误,但生成语法树并不显示错误,只是将报错位置及之后的全部token丢弃的情况。在此对案例进行分享,并分享一下我的解决方案。

一 问题复现

下边我用一个简化后的案例复现这个现象

文法文件如下(ASSIGN.g4):

grammar ASSIGN;

pfile
    : assignStmt +  //文件由一行或多行赋值语句组成
    ;

assignStmt
    : ID '=' ID operator ID ';'     // 赋值语句是 a = b + c; 格式
    ;

operator
    : '+'|'-'|'*'|'/'
    ;

ID: [a-zA-Z]+ ;
WS: [ \t\r\n]+ -> skip;

下面我们基于此文法生成词法分析器和语法分析器

> antlr4 ASSIGN.g4
> javac *.java

下面我们写一个测试文件(test.txt),文件中包含错误的语法

a = b + c;
+
d = e + f;

我们可以看到,第二行的语法是错误的,只有一个加号,不满足assignStmt语法

下面我们使用这个测试文件生成语法树看下

> grun ASSIGN pfile -gui test.txt

结果如下,没有显示任何报错,语法树只有第一行的内容!!!
在这里插入图片描述

二 排查思路

语法树没有报错,难道之后的token都被丢了吗?于是我先排查了一下token

> grun ASSIGN pfile -tokens test.txt
[@0,0:0='a',<ID>,1:0]
[@1,2:2='=',<'='>,1:2]
[@2,4:4='b',<ID>,1:4]
[@3,6:6='+',<'+'>,1:6]
[@4,8:8='c',<ID>,1:8]
[@5,9:9=';',<';'>,1:9]
[@6,12:12='+',<'+'>,2:0]
[@7,15:15='d',<ID>,3:0]
[@8,17:17='=',<'='>,3:2]
[@9,19:19='e',<ID>,3:4]
[@10,21:21='+',<'+'>,3:6]
[@11,23:23='f',<ID>,3:8]
[@12,24:24=';',<';'>,3:9]
[@13,25:24='<EOF>',<EOF>,3:10]

由结果我们可以看到,所有的token都被正确的识别了,那只能是语法分析的问题了。之后我再通过trace分析了一下语法分析的过程

> grun ASSIGN pfile -trace test.txt
enter   pfile, LT(1)=a
enter   assignStmt, LT(1)=a
consume [@0,0:0='a',<7>,1:0] rule assignStmt
consume [@1,2:2='=',<1>,1:2] rule assignStmt
consume [@2,4:4='b',<7>,1:4] rule assignStmt
enter   operator, LT(1)=+
consume [@3,6:6='+',<3>,1:6] rule operator
exit    operator, LT(1)=c
consume [@4,8:8='c',<7>,1:8] rule assignStmt
consume [@5,9:9=';',<2>,1:9] rule assignStmt
exit    assignStmt, LT(1)=+
exit    pfile, LT(1)=+

通过trace的最后两行,我们可以看到,在正确识别第一行的assignStmt后遇到了token(+),此时这个token无法让语法分析器匹配任意一个规则,而且此时从最顶层规则pfile退出,语法也是完整的,所以直接从顶层退出,且没有报错。

三 解决方案

分析出原因后,解决方案也就有了,我们强制pfile规则匹配到文件结束就可以了,如果不能顺利匹配到文件结束,则说明存在语法错误
pfile规则进行如下修改

pfile
    : assignStmt +  EOF//文件由一行或多行赋值语句和文件结束符组成
    ;

重新生成词法分析器和语法分析器,之后重新生成语法树进行验证

> grun ASSIGN pfile -gui test.txt
line 2:0 extraneous input '+' expecting {<EOF>, ID}

在这里插入图片描述
此时第二行的语法错误被检测到。

本文完~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值