禁用空格来匹配字符前缀



我是一个写语法的新手,我已经读了大约一半的Antlr4:权威指南,我想我应该对我正在写的语法进行一下修改。我被一些听起来很基本的东西卡住了,但事实证明比我想象的要难。

我试图解析小(android反汇编)类声明。它看起来像这样:

.class public Lcom/packageName/example;

规则是,所有完全限定的类都以L为前缀,然后包部分用/分隔,然后类名是;之前的最后一部分。

所以我有一个一般的WS : [ trn]+ -> skip ;在我的词法分析器部分,但我正在努力与如何禁用解析fullyQualifiedClass时。我想禁用它,以便在没有L的情况下返回第一个classPackageComponent,但如果忘记了L,则将显示Error: 'L' expected'。包名也是一样,包名和它们的/分隔符之间不能有空格。我知道问题是我的解析器甚至没有看到WS字符,因为Lexer只是把它们扔了出去。我应该如何处理这个问题?渠道是答案吗?我还没有读到这一章,但其他帖子暗示它可能是。

我的错误语法代码如下:

grammar smali;
smaliClass : classDeclaration;
classDeclaration : '.class' accessModifier fullyQualifiedClass;
accessModifier: 'public' | 'private';
fullyQualifiedClass: 'L' ~WS classPackage? className;
classPackage: (classPackageComponent ~WS '/')+;
classPackageComponent: Identifier;
className: Identifier;

Identifier
    :   Letter (Letter|JavaIDDigit)*
    ;
fragment
Letter
    :  'u0024' |
       'u0041'..'u005a' |
       'u005f' |
       'u0061'..'u007a' |
       'u00c0'..'u00d6' |
       'u00d8'..'u00f6' |
       'u00f8'..'u00ff' |
       'u0100'..'u1fff' |
       'u3040'..'u318f' |
       'u3300'..'u337f' |
       'u3400'..'u3d2d' |
       'u4e00'..'u9fff' |
       'uf900'..'ufaff'
    ;
fragment
JavaIDDigit
    :  'u0030'..'u0039' |
       'u0660'..'u0669' |
       'u06f0'..'u06f9' |
       'u0966'..'u096f' |
       'u09e6'..'u09ef' |
       'u0a66'..'u0a6f' |
       'u0ae6'..'u0aef' |
       'u0b66'..'u0b6f' |
       'u0be7'..'u0bef' |
       'u0c66'..'u0c6f' |
       'u0ce6'..'u0cef' |
       'u0d66'..'u0d6f' |
       'u0e50'..'u0e59' |
       'u0ed0'..'u0ed9' |
       'u1040'..'u1049'
   ;
WS : [ trn]+ -> skip ;

首先要处理的几个问题:

    词法分析器和解析器在很大程度上是分开的:解析器不能修改Lexer的操作解析器应该处理令牌,而不是字符或字符字符串——Lexer无法看到解析器中发生了什么,所以您将失去Lexer进行某些优化的能力
  1. Lexer不插入空白令牌之间的令牌认识到

词法分析程序

Class: '.class' ;
Semi: ';' ; 
Modifier: 'public' | 'private';
Slash: '/' ;
ClassPrefix : 'L' { isPrefix() }? ;
Identifier :   Letter (Letter|JavaIDDigit)* ;
WS : [ trn]+ -> skip ;
...

Lexing .class public Lcom/packageName/example;(如果isPrefix()总是返回false)将产生令牌流:

Class, Modifier, Identifier, Slash, Identifier, Slash, Identifier, Semi

这就是解析器将看到的内容。因此,解析器规则变成

classDeclaration : Class Modifier fullyQualifiedClass ;
fullyQualifiedClass: ClassPrefix? (Identifier Slash)* Identifier Semi ;

ClassPrefix的问题是,没有自然的分隔符,您可以使用它分离出来。不过,有很多方法可以绕过这个问题。

也许最直接的方法是让Lexer检查,每次Lexer看到'L'时,它是否在看起来像类名的东西的开头。这就是谓词'{isPrefix()}?是打算做的事。查看这里和这里的谓词实现示例。

另一种方法是从Lexer中完全删除ClassPrefix规则,并在解析器规则操作中检测前缀,或者更好的是,在随后的解析树遍历中检测前缀:
fullyQualifiedClass: (Identifier Slash)* Identifier Semi ;

Identifier的第一个实例是一个Token,其中包含与该Token匹配的底层文本。可以调用生成的解析器类'YourParser'.FullyQualifiedClassContext.Identifier()的每个实例,以返回所遇到的标识符令牌的列表,该列表按从左到右的顺序排列。检查最左边的前缀,并相应地处理。

相关内容

  • 没有找到相关文章

最新更新