Parsing 如何在antlr4中使用Listener方法来获取解析器的内容?

Parsing 如何在antlr4中使用Listener方法来获取解析器的内容?,parsing,antlr,antlr4,lexer,Parsing,Antlr,Antlr4,Lexer,就我而言,antlr4的侦听器方法似乎只能直接获取终端节点的信息——特别是Lexer节点 但是,现在我希望把解析器的信息发布如下: type : primitiveType | referencedType | arrayType | listType | mapType | 'void' ; primitiveType : 'byte' | 'short' | 'i

就我而言,antlr4的侦听器方法似乎只能直接获取终端节点的信息——特别是Lexer节点

但是,现在我希望把解析器的信息发布如下:

type : 
        primitiveType
    |   referencedType
    |   arrayType
    |   listType
    |   mapType
    |   'void'
    ;

primitiveType : 
        'byte'
    |   'short'
    |   'int'
    |   'long'
    |   'char'  
    |   'float'
    |   'double'
    |   'boolean'
    ;
referencedType : 
        'String'
    |   'CharSequence'
    |   selfdefineType
    ;
首先,我想弄清楚如何直接获取
primitiveType
的内容,并将
byte
short
等内容输出,而不将其更改为Lexer(TerminalNode)。我已经检查了
aidlParser.java
(aidl.g4是我的初始语法文件)的代码(

其次,我想知道是否有一种方法可以知道解析器实际匹配的是什么。例如,我想知道
type
的哪个规则(比如
primitiveType
referencedType
…)用于匹配语法中的类型,而不必访问每个子节点(实际上是Lisenter方法中的规则)键入,然后查看哪一个包含某些内容

以下是我的.g4文件的完整代码:

grammar aidl;
//parser

//file
file : packageDeclaration* importDeclaration* parcelableDeclaration? interfaceDeclaration? ;
//packageDeclaration
packageDeclaration :'package' packageName ';';

packageName :   Identifier 
    | 
                packageName '.' Identifier;


// importDeclaration
importDeclaration 
    : 'import'  importName   ';'   
    ;

importName : Identifier 
|     
             importName '.' Identifier; 


//parcelableDeclaration
parcelableDeclaration : 'parcelable'   parcelableName   ';'   ;

parcelableName : Identifier ; 


//interfaceDeclaration
interfaceDeclaration :  interfaceTag?  'interface'  interfaceName  '{'  methodsDeclaration+  '}' ; 

interfaceTag : 'oneway' ;

interfaceName : Identifier ;


// methodsDeclaration
methodsDeclaration :  methodTag? returnType  methodName  '(' parameters?  ')'  ';'  ;

methodName : Identifier ;

methodTag: 'oneway';

returnType : type ; 


// parameters
parameters
    :   parameter (',' parameter)*
    ;


parameter
    :   parameterTag?  parameterType parameterName ;

parameterType : type ;

parameterName : Identifier;

parameterTag : 'in' | 'out' | 'inout' ;


// type 

type : 
        primitiveType
    |   referencedType
    |   arrayType
    |   listType
    |   mapType
    |   'void'
    ;

primitiveType : 
        'byte'
    |   'short'
    |   'int'
    |   'long'
    |   'char'  
    |   'float'
    |   'double'
    |   'boolean'
    ;
referencedType : 
        'String'
    |   'CharSequence'
    |   selfdefineType
    ;
selfdefineType : Identifier;

arrayType : primitiveType  dims
        |   referencedType dims
         ;

listType : 'List' ('<' (primitiveType | referencedType) (',' (primitiveType | referencedType))* '>')?;

mapType : 'Map' ('<' (primitiveType | referencedType) (',' (primitiveType | referencedType))* '>')?;

dims
    :    '[' ']' ( '[' ']')*
    ;



//Lexer

// Identifier
Identifier
    :   JavaLetter JavaLetterOrDigit*
    ;

fragment
JavaLetter
    :   [a-zA-Z$_] // these are the "java letters" below 0x7F
    |   // covers all characters above 0x7F which are not a surrogate
        ~[\u0000-\u007F\uD800-\uDBFF]
        {Character.isJavaIdentifierStart(_input.LA(-1))}?
    |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
        [\uD800-\uDBFF] [\uDC00-\uDFFF]
        {Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
    ;

fragment
JavaLetterOrDigit
    :   [a-zA-Z0-9$_] // these are the "java letters or digits" below 0x7F
    |   // covers all characters above 0x7F which are not a surrogate
        ~[\u0000-\u007F\uD800-\uDBFF]
        {Character.isJavaIdentifierPart(_input.LA(-1))}?
    |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
        [\uD800-\uDBFF] [\uDC00-\uDFFF]
        {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
    ;


WS  :  [ \t\r\n\u000C]+ -> skip
    ;

语法辅助; //分析器 //文件 文件:packageDeclaration*importDeclaration*parcelableDeclaration?interfaceDeclaration; //包装声明 packageDeclaration:'package'packageName';'; packageName:标识符 | packageName“.”标识符; //进口折扣 进口折扣 :'import'importName';' ; importName:标识符 | 导入名称“.”标识符; //包裹申报 parcelableDeclaration:“parcelable'parcelableName';”; parcelableName:标识符; //接口声明 interfaceDeclaration:interfaceTag?'interface'interfaceName'{'methodsDeclaration+'}'; 接口标签:“单向”; 接口名称:标识符; //方法说明 methodsDeclaration:methodTag?returnType methodName'(“参数”)“”; 方法名称:标识符; methodTag:‘单向’; 返回类型:返回类型; //参数 参数 :参数(“,”参数)* ; 参数 :parameterTag?parameterType parameterName; 参数类型:类型; 参数名称:标识符; 参数标签:“in”|“out”|“inout”; //类型 类型: 基本类型 |引用类型 |阵列类型 |列表类型 |地图类型 |“无效” ; 基本类型: “字节” |“短” |“int” |“长” |“char” |“浮动” |“双人” |“布尔” ; 引用类型: “字符串” |“字符序列” |自定义类型 ; selfdefineType:标识符; arrayType:基本类型dims |引用类型dims ; listType:'列表'('')?; 映射类型:“映射”(“”)?; 昏暗 : '[' ']' ( '[' ']')* ; //雷克瑟 //标识符 标识符 :JavaLetter javaletterDigit* ; 片段 爪哇字母 :[a-zA-Z$\//这些是0x7F下面的“java字母” |//覆盖0x7F以上不是代理项的所有字符 ~[\u0000-\u007F\uD800-\uDBFF] {Character.isJavaIdentifierStart(_input.LA(-1))}? |//涵盖U+10000到U+10FFFF的UTF-16代理项对编码 [\uD800-\uDBFF][\uDC00-\uDFFF] {Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2),(char)_input.LA(-1))}? ; 片段 JavaletterDigit :[a-zA-Z0-9$\这些是0x7F下面的“java字母或数字” |//覆盖0x7F以上不是代理项的所有字符 ~[\u0000-\u007F\uD800-\uDBFF] {Character.isJavaIdentifierPart(_input.LA(-1))}? |//涵盖U+10000到U+10FFFF的UTF-16代理项对编码 [\uD800-\uDBFF][\uDC00-\uDFFF] {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2),(char)_input.LA(-1))}? ; WS:[\t\r\n\u000C]+->跳过 ;
我衷心感谢您及时提供的帮助!

一旦您的解析运行结束,您将得到一个解析树。您可以将该树向下遍历到您感兴趣的节点(通常使用解析树侦听器,并且只覆盖与您的问题相关的enter/exit*方法)。在
enterPrimitveType
方法中,您将获得一个
EnterPrimitiveTypeContext
参数。使用其
getText
方法获取匹配的文本


对于你的第二个问题,你也可以这样做,只需使用
enterType
方法即可。在规则中,
EnterTypeContext
参数具有每个备选方案的成员。请检查哪个选项不为null,以查看哪个选项实际匹配。

谢谢!我会尝试一下!实际上
toString
方法似乎没有起作用nd只返回一个[]。但是,它的
getText()
方法的工作原理与toString类似,解析器节点也可以使用它。是的,这很可能是Mike的意思。我将编辑他的答案以反映这一点。