返回不同数据类型的ANTLR AST访问器

2022-04-12 00:00:00 abstract-syntax-tree types java antlr
我完成了ANTLR CST到AST的转换,并创建了一个特定的Visitor<T>接口,该接口允许我访问所有的AST节点,但我遇到的主要问题是,一些访问应该返回不同的数据类型,我不确定如何处理这一问题。 例如,对于简单的算术运算,我希望从它们各自的访问方法返回一个双精度值;但其他字符串操作需要它们各自的节点返回一个字符串。 因为我的访问方法都需要泛型类型T,所以我尝试创建了一个名为Result的类和两个子类DoubleResultStringResult,以便我的访问者可以在访问期间返回字符串或双精度类型,但它似乎很糟糕,并且充满了强制转换和类型检查。 有没有更好的方法来做这样的事情?

以下是示例代码:

public class ExpressionVisitor implements Visitor<Result> {
    ...
    public Result visit(BinaryExpression node) {
        // here the node's left or right can be StringResults
        // So i'd have to do instance and type checks
    }

    public Result visit(StringExpression node) {
        // here i'd return a StringResult specifically
    }
}

编辑: 目标是能够进行字符串算术,例如,像在Python中2*"hello"

但是,二进制表达式访问方法必须检查哪个操作数是字符串(左或右),然后大多数其他访问方法将需要相应地检查和处理DoubleResult或StringResult类型。有没有更干净的方法来实现同样的目标?


解决方案

正如您已经毫无疑问地发现的那样,ANTLR为您生成的Visitor类是一个泛型类,您需要在其中标识预期的返回类型,并且必须返回该类型:

有几种方法可以解决您的问题。(它肯定是在动态类型语言中出现的)。

对于我为教程拼凑的一种简单语言,我只是定义了一个Value类,它可以包含我允许的任何动态类型。我为每种类型使用了getters/setters,并为每种类型使用了is*()方法。我的表达式访问器刚刚返回此动态类型。

注意:在执行之前,我使用了语义验证侦听器,该侦听器使用了一种基于堆栈的方法,在退出表达式时从堆栈中弹出表达式类型(在我访问子级时已推送到堆栈上),验证这些值的类型兼容性,然后将结果类型推送到堆栈上(文字和变量只是将它们的类型推送到堆栈上)。我遇到的任何问题都会在执行之前推送一条错误消息。这样,我知道,在执行类型中,我总是拥有正确的类型。(同样可以在运行时完成;这正是我选择的解决方案。)

实现这一点的另一种可能很方便的方法是,因为您在使用访问者时控制了树导航,所以不必说必须有一个用于整个树的访问者。您可以有多个访问者(每个访问者都有自己的类型),并选择要使用哪个访问者来访问您的子节点。例如,我使用返回NULL类型的Visator访问语句节点,但使用返回我的动态Value类型的Visator访问所有表达式节点。

没有真正的理由不能拥有你想要的访问者,每个访问者都是不同类型的。访问者是无国籍的,这并不少见,所以您可以重复使用它们,在访问每个孩子的适当类型之间来回跳跃。(当然,这假设您可以从父节点确定应该使用哪种访问者类型来访问每个子节点。)

小错误...ANTLR4生成分析树(不是AST)

相关文章