我有以下的antlr4语法:
grammar CategoryExpr;
@header {
package org.example.antlr;
}
moneyTerm
: dollars moneyTermSuffixes*
;
moneyTermSuffixes
: '*' DIGITS # MoneyMult
| '/' DIGITS # MoneyDiv
;
dollars : DIGITS ('.' DIGITS)? ;
DIGITS : [0-9]+ ;
ERRORCHAR : . ;
以及以下Kotlin代码:
private class MyListener : CategoryExprBaseListener() {
override fun enterMoneyTerm(ctx: MoneyTermContext) {
System.out.println(ctx.dollars().text.toDouble()) // ctx.dollars() unexpectedly returns null here!
}
override fun exitMoneyMult(ctx: CategoryExprParser.MoneyMultContext) {}
override fun exitMoneyDiv(ctx: CategoryExprParser.MoneyDivContext) {}
override fun exitMoneyTerm(ctx: MoneyTermContext) {
System.out.println(ctx.dollars().text.toDouble()) // ctx.dollars() returns non-null here.
}
}
fun testMoneyTerm() {
val input = CharStreams.fromString("1.5")
val lexer = CategoryExprLexer(input)
val tokens = CommonTokenStream(lexer)
val listener = MyListener()
CategoryExprParser(tokens).apply {
errorHandler = BailErrorStrategy()
buildParseTree = false
addParseListener(listener)
moneyTerm()
}
}
我的计划是使用entermoneyterm listener回调函数将my listener的成员变量(属性)初始化为与“美元”解析规则匹配的值,然后让exitmoneymult和exitmoneydiv的侦听器通过乘以或除以与每个规则关联的数字值来修改该变量的值。
但是,这种方法似乎不起作用,因为在entermoneyterm函数中,如果我尝试计算“ctx.dollars()”它意外地返回空值。(我似乎无法在EnterMoneyTerm调用中检索与“美元”关联的值。)
请注意,如果我调用exitMoneyTerm中的ctx.dollars().text,我会得到正确的返回值(“1.5”),但到那时,当然为时已晚,因为我需要从左到右进行乘法和除法运算,到那时,我已经从moneyTermSuffixes中恢复过来了。
我不明白为什么会发生这种“从ctx.dollars()返回空值”的行为,或者如何处理它。(在调试过程中,我注意到MoneyTermContext对象的“children”对象设置为空,这解释了为什么dollars()返回空值,但本身无法解释。)
我想我可以列出货币后缀隐含的乘法和除法,然后在exitmoneyterm中的事实之后应用它们,但这看起来相当不雅,如果可能的话,我宁愿避免它。
有人能告诉我为什么ctx.dollars()在entermoneyterm中返回空值,或者我能做些什么,以便在分析moneytermsaffixes之前收集“dollars”文本的值吗?
编辑:
为了澄清这一点,请注意,在我的大型应用程序的上下文中,转换为使用基于树查询器的方法而不是基于侦听器的方法并不是一个真正的选择。我希望有一种方法可以最小限度地修改我的语法,以确保解析器调用了侦听器回调,为我提供“美元”规则匹配的完整文本值,然后再开始为MoneyTermSuffixes规则发出回调。