首页 > 解决方案 > 在 Kotlin 中编写附加访问者函数

问题描述

我正在尝试在 Kotlin 中编写一个将两个整数相加的访问者函数。我一直在处理一些示例代码,但我无法弄清楚这些.value.visit功能是什么。它似乎没有在示例代码中声明,所以我不确定如何在我的代码中声明它。每当我编译代码时,我都会收到一条错误消息,指出该值是未解析的引用。

相关的 Kotlin 代码:

package backend
import org.antlr.v4.runtime.*
import grammar.*

abstract class Data

class IntData(val value: Int): Data() {
    override fun toString(): String
    = "Int($value)"
}

class Context(): HashMap<String, Data>() {
    constructor(parent: Context): this() {
        this.putAll(parent)
    }
}


abstract class Expr {
    abstract fun eval(scope: Context): Data
    
    fun run(program: Expr) {
        try {
            val data = program.eval(Context())
            println("=> ${data}")
        } catch(e: Exception) {
            println("[err] ${e}")
        }
    }
}

class IntLiteral(val value: Int): Expr() {
    override fun eval(scope:Context): Data 
    = IntData(value)
}

enum class Op {
    Add,
    Sub,
    Mul,
    Div
}

class Arithmetic(
    val op: Op,
    val left: Expr,
    val right: Expr): Expr() {
    override fun eval(scope: Context): Data {
        val x = (left.eval(scope) as IntData).value
        val y = (right.eval(scope) as IntData).value
        return IntData(
            when(op) {
                Op.Add -> x + y
                Op.Mul -> x * y
                Op.Sub -> x - y
                Op.Div -> x / y
            }
        )
    }
}


}


class Compiler: PLBaseVisitor<Expr>() {
    
    val scope = mutableMapOf<String, Expr>()
    
    override fun visitAddExpr(ctx: PLParser.AddExprContext): Expr {
        val xValue = this.visit(ctx.x)
        val yValue = this.visit(ctx.y)
        val result = xValue.value + yValue.value
        return IntLiteral(result)
    }
    
}

相关 Antlr 语法:

expr        : x=expr '+' y=expr # addExpr
        | x=expr '-' y=expr # subExpr
        | x=expr '*' y=expr # mulExpr
        | x=expr '/' y=expr # divExpr
        ;

我试图执行的代码:

val test = """
x=1+2
print(x)
"""

fun parse(source: String): PLParser.ProgramContext {
    val input = CharStreams.fromString(source)
    val lexer = PLLexer(input)
    val tokens = CommonTokenStream(lexer)
    val parser = PLParser(tokens)
}

val testTree = parse(source1)

val testTree = parse(source1)

fun execute(program: Expr?) {
    if(program == null) {
        println("Program is null.")
        return
    }
    try {
        val data = program.eval(Context())
        println("> ${data}")
    } catch(e: Exception) {
        println("[err] ${e}")
    }
}

execute(testProgram)

示例代码:

data class NodeValue(val value: Int)
val visitor = object: CalcBaseVisitor<NodeValue>() {
    override fun visitAddition(ctx: CalcParser.AdditionContext): NodeValue {
        val xValue = this.visit(ctx.x)
        val yValue = this.visit(ctx.y)
        return NodeValue(xValue.value + yValue.value)
    }
    override fun visitValue(ctx: CalcParser.ValueContext): NodeValue {
        val lexeme = ctx.Number().getText()
        return NodeValue(lexeme.toInt())
}
}

标签: kotlincompiler-constructionantlr

解决方案


您没有显示您的program.eval()方法的代码。

eval 函数需要创建一个访问者的实例。(你已经做到了并称之为visitor)。

您的program变量中也有根 expr 节点。

现在您将让您的访问者“访问”该节点并保存返回值:

val nodeVal = visitor.visit(program)

那时nodeVal.value将有访问该表达式的结果。

注意:由于您正在对访问者进行评估,因此您的Arithmetic课程实际上没有任何用处(除非您重构访问者以使用它而不是仅仅进行数学运算,但作为访问者,我认为这没有多大价值已经很容易阅读了)。


推荐阅读