首页 > 解决方案 > 如何使用antlr4分析.aidl文件的语法?

问题描述

实际上,我被指派分析 .aidl 文件的语法并使用侦听器方法提取语法元素。

为了完成这个,我想了很久,终于搞定了一个.g4文件。

grammar aidl3;
file  : pack* imp* parcelable? interfa? ;

pack : 'package' WS+ PAC_NAME WS* ';' WS* ;

imp : 'import'  WS+ IMP_NAME WS*  ';' WS*  ;

parcelable : 'parcelable' WS+  PARCE_NAME WS*  ';'  WS* ;

interfa :  INTER_TAG? WS* 'interface' WS+ INTER_NAME WS* '{' WS* methods+ WS* '}' WS*; 

methods :  RETURN_TYPE WS+  METHOD_NAME WS* '(' WS* argmentsa* WS* argmentsb* WS* ')' WS* ';' WS* ;

argmentsa : TAG? WS* ARG_TYPE WS+ ARG_NAME WS* ',' WS* ;

argmentsb : TAG? WS* ARG_TYPE WS+ ARG_NAME WS* ;



PAC_NAME : ~[; \n\r]+ ; 
//PAC_NAME : [_a-zA-Z] [_.a-zA-Z0-9]* ;
IMP_NAME : ~[ ;\n\r]+ ;

PARCE_NAME : ~[ ;\n\r.]+ ;

INTER_TAG : 'oneway';

INTER_NAME : ~[ ;\n\r{.]+ ;

RETURN_TYPE : ~[ ;\n\r.]+ ;

METHOD_NAME : ~[ ;\n\r(]+ ;

TAG : 'in' | 'out' | 'inout' ;

//ARG_TYPE : ~[) ,\n\r]+ ;

ARG_TYPE : [a-zA-Z] ~' '* | [a-zA-Z] ~' '* ' ' '[' ']' ;

ARG_NAME : ~[ ,\n\r).]+ ;

WS: [ \t\n\r];

但是,我遇到了一个奇怪的问题:那就是当我试图分析 .aidl 文件时,例如

package android.view.accessibility;
oneway interface IAccessibilityInteractionConnection {
    void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds,
        int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
    void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
        in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback,
        int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
    void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, in Region bounds,
        int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
    void findFocus(long accessibilityNodeId, int focusType, in Region bounds, int interactionId,
        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
        long interrogatingTid, in MagnificationSpec spec);
    void focusSearch(long accessibilityNodeId, int direction, in Region bounds, int interactionId,
        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
        long interrogatingTid, in MagnificationSpec spec);
    void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
        int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
        int interrogatingPid, long interrogatingTid);
}

它会给出这个输出:

[@0,0:6='package',<'package'>,1:0]
[@1,7:7=' ',<WS>,1:7]
[@2,8:41='android.view.accessibility;\noneway',<ARG_TYPE>,1:8]
[@3,42:42=' ',<WS>,2:6]
[@4,43:51='interface',<'interface'>,2:7]
[@5,52:52=' ',<WS>,2:16]
[@6,53:87='IAccessibilityInteractionConnection',<PAC_NAME>,2:17]
[@7,88:88=' ',<WS>,2:52]
[@8,89:89='{',<'{'>,2:53]
[@9,90:90='\n',<WS>,2:54]
[@10,91:91=' ',<WS>,3:0]
[@11,92:92=' ',<WS>,3:1]
[@12,93:93=' ',<WS>,3:2]
[@13,94:94=' ',<WS>,3:3]
[@14,95:98='void',<PAC_NAME>,3:4]
[@15,99:99=' ',<WS>,3:8]
[@16,100:146='findAccessibilityNodeInfoByAccessibilityId(long',<PAC_NAME>,3:9]
[@17,147:147=' ',<WS>,3:56]
[@18,148:167='accessibilityNodeId,',<PAC_NAME>,3:57]

...

您可以在输出行 3 '[@2,8:41='android.view.accessibility;\noneway',ARG_TYPE,1:8]' 中看到,其中表达式 'pack' 使用 'ARG_TYPE' 来匹配 'android .view.accessibility;\noneway'。但是..怎么可能?'ARG_TYPE' 从未出现在表达式 'pack' 中,它应该使用 'PAC_NAME' 来匹配 'android.view.accessibility'

如果有人能帮我解决这个问题,那就太好了,因为我面临着最后期限。事实上,我只是一个新手,我知道我的 g4 文件看起来不太好,所以如果可能的话,你能告诉我如何更好地为 .aidl 编写 g4 吗?或者甚至给我看写答案?

如果您能帮助我,我将不胜感激!谢谢!

标签: parsingantlrantlr4lexeraidl

解决方案


ANTLR 的词法分析器尝试使用尽可能多的字符创建标记。并且由于ARG_TYPE能够匹配android.view.accessibility;\noneway(并且没有其他规则可以匹配更多字符),ARG_TYPE因此创建了一个令牌。只有当 2 个或多个规则匹配相同的字符时,ANTLR 才会选择第一个定义的。

您必须了解词法分析器不会根据解析器尝试匹配的内容创建标记。标记化是一个独立于解析阶段完成的过程。因此,您的大多数规则看起来~[ ;\n\r(]+都太宽泛了。

我建议您查看现有的 Java 语法,并使用它来处理 AIDL 文件。

编辑

如果我采用上面发布的语法文件,并更改:

formalParameter
    :   variableModifier* unannType variableDeclaratorId
    ;

进入:

formalParameter
    :   'in'? variableModifier* unannType variableDeclaratorId
    ;

并改变:

interfaceModifier
    :   annotation
    |   'public'
    |   'protected'
    |   'private'
    |   'abstract'
    |   'static'
    |   'strictfp'
    ;

进入:

interfaceModifier
    :   annotation
    |   'public'
    |   'protected'
    |   'private'
    |   'abstract'
    |   'static'
    |   'strictfp'
    |   'oneway'
    ;

那么您的示例文件将正确解析。


推荐阅读