前言
之前通过
我们得到了一个抽象语法树,通过遍历抽象语法树,我们就可以得到相应的计算结果。
计算
通过后续遍历,我们可以得到相应的计算结果。
class Interpreter(private val parser: Parser) {
fun interpret():Int {
val ast = parser.parse()
return visit(ast)
}
private fun visit(ast: AST): Int {
when (ast) {
is BinOp -> {
return when (ast.op.tokenType) {
TokenType.PLUS -> {
visit(ast.left) + visit(ast.right)
}
TokenType.MIN -> {
visit(ast.left) - visit(ast.right)
}
TokenType.MUL -> {
visit(ast.left) * visit(ast.right)
}
TokenType.DIV -> {
visit(ast.left) / visit(ast.right)
}
else -> {
throw RuntimeException("error ast")
}
}
}
is Num -> {
return ast.token.value.toInt()
}
else -> {
throw RuntimeException("error ast")
}
}
}
}
我们定义一个Interpreter类,该来持有Parser引用,通过条用Parser的parse方法,我们可以得到一个抽象语法树。创建一个visit方法,这里我们后续遍历抽象语法树,为什么采用后序遍历,因为之前在得到抽象语法树的时候,我们曾经说过,通过节点的深度我们来保证运算的优先级,后续遍历帮我们保持了这种特性。之前我们的抽象语法树只有两种类型的节点,一是BinOp,用来代表运算符,左右两个子节点为计算的值,一个是Num,代表具体的数值。当节点类型是BinOp的时候,根据他们的tokenType,将它的左右子节点visit后返回的值进行加减乘除相应的处理,如果是Num节点,则直接返回相应参数值。
最后
这样整个一个四则运算基本就实现了,写上测试代码。
fun main() {
while (true) {
val scanner = Scanner(System.`in`)
val text = scanner.nextLine()
val lexer = Lexer(text)
// var nextToken = lexer.getNextToken()
// while (TokenType.EOF != nextToken.tokenType) {
// println(nextToken.toString())
// nextToken = lexer.getNextToken()
// }
val parser = Parser(lexer)
val interpreter=Interpreter(parser)
println("result is ${interpreter.interpret()}")
}
}
相关文章
代码已经上传到github,后续会不断更新 CompilerDemo
关注我的公众号”滑板上的老砒霜“