前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >开发自制语言Monkey编译器:实现复杂算术表达式的执行

开发自制语言Monkey编译器:实现复杂算术表达式的执行

作者头像
望月从良
发布2018-07-19 14:34:20
4710
发布2018-07-19 14:34:20
举报
文章被收录于专栏:Coding迪斯尼Coding迪斯尼

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

代码语言:javascript
复制
(5 + 10 * 2 + 15 / 3) * 2 + -10

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

代码语言:javascript
复制
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中添加如下代码:

代码语言:javascript
复制
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,该函数根据中间运算符对左右表达式运算结果进行计算。我们看看该函数的实现:

代码语言:javascript
复制
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根据表达式中间运算符进行相应的计算。完成上面代码后,编译器就能计算出开头所给表达式的最终结果,代码运行结果如下:

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

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

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

代码语言:javascript
复制
1 < 2; 1 > 2; 1 == 1; 1 != 2;

代码修改如下:

代码语言:javascript
复制
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
}

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

代码语言:javascript
复制
(1+2) > (0 + 3)

得到的执行结果如下:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-02-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coding迪斯尼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档