Antlr4解析器在Python 3.7中放错位置的令牌上过早结束 我尝试过的事情:

问题描述

我遇到了一个问题,如果我的解析器找到了它无法放置在任何规则中的标记,那么即使没有更多标记放置,它也会在没有显式报告错误的情况下结束。确切地说,令牌实际上是可以识别的(我有一条几乎是万能的规则),但是令牌放错了位置,不能被任何规则覆盖。在这种情况下,我的解析器成功结束,没有报告任何错误(至少响亮)。

我看到的是这种情况: 要解析的代码

.class public final Ld;
.super Ljava/lang/Object;
.source "java-style lambda group"

# interfaces
.implements Landroid/content/DialogInterface$OnClickListener;
<misplaced-tokens>

# static fields
.field public static final f:Ld;

.field public static final g:Ld;

...

(请注意<misplaced-tokens>令牌,实际上是五个令牌-见下文。我希望解析在这里出错。)

已解析的令牌:

[@0,0:5='.class',<'.class'>,1:0]
[@1,7:12='public',<'public'>,1:7]
[@2,14:18='final',<'final'>,1:14]
[@3,20:22='Ld;',<QUALIFIED_TYPE_NAME>,1:20]
[@4,24:29='.super',<'.super'>,2:0]
[@5,31:48='Ljava/lang/Object;',2:7]
[@6,50:56='.source',<'.source'>,3:0]
[@7,58:82='"java-style lambda group"',<STRING_LIteraL>,3:8]
[@8,85:96='# interfaces',<LINE_COMMENT>,channel=1,5:0]
[@9,98:108='.implements',<'.implements'>,6:0]
[@10,110:158='Landroid/content/DialogInterface$OnClickListener;',6:12]
[@11,160:160='<',<'<'>,7:0]
[@12,161:169='misplaced',<IDENTIFIER>,7:1]
[@13,170:170='-',<'-'>,7:10]
[@14,171:176='tokens',7:11]
[@15,177:177='>',<'>'>,7:17]
[@16,180:194='# static fields',9:0]
[@17,196:201='.field',<'.field'>,10:0]
...

解析进度:

enter   parse,LT(1)=.class
enter   statement,LT(1)=.class
enter   classDirective,LT(1)=.class
consume [@0,<30>,1:0] rule classDirective
enter   classModifier,LT(1)=public
consume [@1,<53>,1:7] rule classModifier
exit    classModifier,LT(1)=final
enter   classModifier,LT(1)=final
consume [@2,<56>,1:14] rule classModifier
exit    classModifier,LT(1)=Ld;
enter   className,LT(1)=Ld;
enter   referenceType,LT(1)=Ld;
consume [@3,<1>,1:20] rule referenceType
exit    referenceType,LT(1)=.super
exit    className,LT(1)=.super
exit    classDirective,LT(1)=.super
exit    statement,LT(1)=.super
enter   statement,LT(1)=.super
enter   superDirective,LT(1)=.super
consume [@4,<33>,2:0] rule superDirective
enter   superName,LT(1)=Ljava/lang/Object;
enter   referenceType,LT(1)=Ljava/lang/Object;
consume [@5,2:7] rule referenceType
exit    referenceType,LT(1)=.source
exit    superName,LT(1)=.source
exit    superDirective,LT(1)=.source
exit    statement,LT(1)=.source
enter   statement,LT(1)=.source
enter   sourceDirective,LT(1)=.source
consume [@6,<32>,3:0] rule sourceDirective
enter   sourceName,LT(1)="java-style lambda group"
enter   stringLiteral,LT(1)="java-style lambda group"
consume [@7,<304>,3:8] rule stringLiteral
exit    stringLiteral,LT(1)=.implements
exit    sourceName,LT(1)=.implements
exit    sourceDirective,LT(1)=.implements
exit    statement,LT(1)=.implements
enter   statement,LT(1)=.implements
enter   implementsDirective,LT(1)=.implements
consume [@9,<31>,6:0] rule implementsDirective
enter   implementsName,LT(1)=Landroid/content/DialogInterface$OnClickListener;
enter   referenceType,LT(1)=Landroid/content/DialogInterface$OnClickListener;
consume [@10,6:12] rule referenceType
exit    referenceType,LT(1)=<
exit    implementsName,LT(1)=<
exit    implementsDirective,LT(1)=<
exit    statement,LT(1)=<
exit    parse,LT(1)=<

(请注意解析是主要规则的方式,尽管管道中还有很多令牌,但实际上是在这里退出的)

我尝试过的事情:

我尝试重新实现认的错误策略和错误侦听器,并将其添加到lexer和解析器中,只是想看看是否会遇到这些断点。不会碰到任何覆盖所有方法的断点(有时reportAttemptingFullContext除外)。

这是我添加覆盖的方式:

def parseFile(self,filePath):
    errorListener = MyErrorListener()
    strategy = MyErrorStrategy()
    file = FileStream("file.smali")
    lexer = SmaliLexer(file)
    lexer.removeErrorListeners()
    lexer.addErrorListener(errorListener)
    lexer.addErrorListener(strategy)
    stream = CommonTokenStream(lexer)
    parser = SmaliParser(stream)
    parser.removeErrorListeners()
    parser.addErrorListener(errorListener)
    parser.addErrorListener(strategy)
    tree = parser.parse()
    ...

我的设置如下:

Windows 10 OS
Python 3.7
Antlr4 v4.8 - antlr-4.8-complete.jar
pip-installed runtime: antlr4_python3_runtime-4.8-py3-none-any.whl

对于使Antlr4真正考虑重写的侦听器和策略的任何帮助,我将不胜感激,这样我既可以报告错误进行调试,又可以进行不同的处理。谢谢!

解决方法

Antlr4解析器过早结束

当您调用的规则parse未被内置EOF标记“锚定”时,可能会发生这种情况:

parse
 : expression
 ;

expression
 : expression '+' expression
 | NUMBER
 ;

在上述情况下,当输入为1+2时,生成的解析器将愉快地解析1+2 3

如果要强制解析器使用输入流中的所有令牌,请在开始规则中添加EOF

parse
 : expression EOF
 ;