自制Monkey语言编译器:执行复杂算术表达式的运算

前几节,我们大费周章的详细解释如何对复杂的算术表达式进行语法解析,也就是让程序懂得理解复杂的算术表达式,本节我们探讨如何执行复杂表达式对应的运算并给出最终结果。我们先看这么个算术表达式:

(5 + 10 * 2 + 15 / 3) * 2 + -10

上面算术表达式涉及到多种运算符,再加上含有括号,因此程序在解读这个表达式时,还需考虑到运算的优先级。我们看看如何让程序懂得把这个运算式的结果计算出来。前面我们提到过中序表达式,它是具备这种性质的表达式,中间是一个运算符,运算符的左右两边也是表达式,回顾前几节代码,在MonkeyCompilerParser.js中,我们用以下代码来表示中序表达式:

class InfixExpression extends Expression {
  constructor(props) {
    super(props)
    this.token = props.token
    this.left = props.leftExpression
    this.operator = props.operator
    this.right = props.rightExpression
    var s = "(" + this.left.getLiteral() + " " + this.operator 
            + this.right.getLiteral() + ")"
    this.tokenLiteral = s
    this.type = "InfixExpression"
  }
}

当语法解析读取表达式后,会执行上面代码构造一个InfixExpression对象。该对象含有三个关键部分,一个是left,对应的是运算符左边的表达式,一个是operator,也就是运算符,另一个是right,也就是运算符右边表达式。我们做代码执行时,需要先解释执行左边表达式得到表达式结果,然后执行右边表达式得到表达式运算结果,最后根据运算符将左右表达式的值进行相应运算,由此相应的执行代码实现如下,在MonkeyCompilerEvaluator.js中添加如下代码:

class MonkeyEvaluator {
    eval (node) {
        var props = {}
        switch (node.type) {
        ...
        case "InfixExpression":
          var left = this.eval(node.left)
          var right = this.eval(node.right)
          return this.evalInfixExpression(node.operator, left, right)
        ...
        }

在解析中序表达式时,代码先分别递归式的解析运算符左右两边表达式,得到左右表达式的运行结果并把结果封装在相应的符号对象里,然后执行evalInfixExpression,该函数根据中间运算符对左右表达式运算结果进行计算。我们看看该函数的实现:

evalInfixExpression(operator, left, right) {
        if (left.type() === left.INTEGER_OBJ && 
            right.type() === right.INTEGER_OBJ) {
            return this.evalIntegerInfixExpression(
                operator, left, right)
        }

        return null
    }

    evalIntegerInfixExpression(operator, left, right) {
        var leftVal = left.value
        var rightVal = right.value
        var props = {}
        var resultType = "integer"
        
        switch (operator) {
            case "+":
              props.value = leftVal + rightVal
              break;
            case "-":
              props.value = leftVal - rightVal
              break;
            case "*":
              props.value = leftVal * rightVal
              break;
            case "/":
              props.value = leftVal / rightVal
              break;
            default:
              return null
        }
        console.log("eval infix expression result is:",
            props.value)
            
        var result = null
        if (resultType === "integer") {
            result = new Integer(props)
        }
        
        return result
    }

它先确保左右表达式执行后得到的是整形,然后调用evalIntegerInfixExpression根据表达式中间运算符进行相应的计算。完成上面代码后,编译器就能计算出开头所给表达式的最终结果,代码运行结果如下:

《自制Monkey语言编译器:执行复杂算术表达式的运算》 这里写图片描述

经过多重步骤的运算后,编译器对表达式的计算所得结果为50.

更详细的讲解和代码调试演示过程,请点击链接

我们继续完善代码,使得编译器对算术表达式的运算能支持比较运算符,也就是我们要让编译器能懂得如下表达式的运算:

1 < 2; 1 > 2; 1 == 1; 1 != 2;

代码修改如下:

evalIntegerInfixExpression(operator, left, right) {
    ....
    switch (operator) {
    ....
    case "==":
              resultType = "boolean"
              props.value = (leftVal === rightVal)
              break;
             case "!=":
               resultType = "boolean"
               props.value = (leftVal !== rightVal)
               break
             case ">":
               resultType = "boolean"
               props.value = (leftVal > rightVal)
               break
             case "<":
               resultType = "boolean"
               props.value = (leftVal < rightVal)
               break
             case ">=":
               resultType = "boolean"
               props.value = (leftVal >= rightVal)
               break
             case "<=":
               resultType = "boolean"
               props.value = (leftVal <= rightVal)
               break
             default:
               return null
    }
    console.log("eval infix expression result is:",
            props.value)
    var result = null
    if (resultType === "integer") {
        result = new Integer(props)
    } else if (resultType === "boolean") {
        result = new Boolean(props)
    }
    
    return result
}

上面代码完成后,编译器可以解释执行比较性质的算术表达式,在编辑框中输入如下内容:

(1+2) > (0 + 3)

得到的执行结果如下:

《自制Monkey语言编译器:执行复杂算术表达式的运算》 这里写图片描述

更详细的讲解和代码调试演示过程,请点击链接

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

《自制Monkey语言编译器:执行复杂算术表达式的运算》 这里写图片描述

    原文作者:望月从良
    原文地址: https://www.jianshu.com/p/a3f939c92587
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞