爱嘉牛LA

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

给定一个字符串如:2/(3+4))*(3-1)+6-8 ,用程序解析出来,输出最终的值。这是个AST 语法解析问题,最直观的是建立一颗语法树,然后遍历语法树来获得最终的效果。如下图,建立这么一个语法树,然后广度优先搜索,进行操作就能得到最终的结果。

  

但是,其实我们有更方便的方法去做,不用建立语法树,而是利用栈,给每个操作符号定义优先级,就可以实现这个功能。一共的操作符号有:

(  )  +  -  *  /

只有这四种,定义其优先等级分别为:

( : -1

) : 0

+ : 1

- : 1

* : 2

/ : 2

解析表达式字符串,从左到右把它的字符加入到栈,如果遇到第二个操作符开始,其优先级小于前面的操作符的优先级,则先合并前面的操作符号的操作项,不断得重复此过程直到栈中只有一个符号。

我的程序定义了两个栈,一个栈是存操作符的,一个栈是存数值的。挺多处理的细节不文字表示了,看下面的代码(python实现)

class NodeOpt:
    """
    操作符节点
    """

    def __init__(self, ch, precedence):
        self.ch = ch
        self.precedence = precedence


class AST:
    """
    加减乘除任意组合的语法解析器
    """
    # 操作符栈
    _operatorStack = []
    # 值栈
    _exprStack = []
    # 具体操作符节点
    left_range = NodeOpt(ch='(', precedence=-1)
    right_range = NodeOpt(ch=')', precedence=0)
    add = NodeOpt(ch='+', precedence=1)
    sub = NodeOpt(ch='-', precedence=1)
    mul = NodeOpt(ch='*', precedence=2)
    div = NodeOpt(ch='/', precedence=2)
    __opts = [add, sub, mul, div, left_range, right_range]

    def getOptNode(self, ch):
        """
        根据符号获取节点
        """
        for ops in self.__opts:
            if ops.ch == ch:
                return ops

    def isValue(self, ch):
        """
        判断是否为数值
        """
        if self.isOperator(ch):
            return False
        return True

    def isOperator(self, ch):
        """
        判断是否为操作符
        """
        for ops in self.__opts:
            if ops.ch == ch:
                return True
        return False

    def operator(self, e1, e2, operator):
        """
        执行操作
        """
        opt = operator.ch
        e1 = float(e1)
        e2 = float(e2)
        if opt is '+':
            return e1 + e2
        elif opt is '-':
            return e1 - e2
        elif opt is '*':
            return e1 * e2
        elif opt is '/':
            return e1 / e2
        else:
            return None

    def ifGo(self):
        if len(self._exprStack) >= 2 and len(self._operatorStack) >= 1:
            return True
        else:
            return False

    def parse(self, input):
        """
        :param input: 字符数组

        """

        for ch in input:
            if ch is '(':
                ch = self.getOptNode(ch)
                self._operatorStack.append(ch)
            elif self.isValue(ch):
                self._exprStack.append(ch)

            elif self.isOperator(ch):
                ch = self.getOptNode(ch)
                while self.ifGo() and ch.precedence <= self._operatorStack[-1].precedence:
                    e2 = self._exprStack.pop()
                    e1 = self._exprStack.pop()
                    operator = self._operatorStack.pop()
                    self._exprStack.append(self.operator(e1, e2, operator))

                self._operatorStack.append(ch)

                if ch.ch is ')':
                    while self._operatorStack[-1].ch != '(':
                        self._operatorStack.pop()
                    self._operatorStack.pop()
            else:
                return Exception

        while self.ifGo():
            e2 = self._exprStack.pop()
            e1 = self._exprStack.pop()
            operator = self._operatorStack.pop()
            self._exprStack.append(self.operator(e1, e2, operator))

        return self._exprStack.pop()


if __name__ == '__main__':
    ast = AST()
    myopt = "2/(3+((2-5)+1))*(3-1)+6-8"
    optlist = []
    i = 0
    while i < len(myopt):
        optlist.append(myopt[i])
        i += 1

    result = ast.parse(optlist)
    print(result) 

 

posted on 2018-11-15 00:55  爱嘉牛LA  阅读(883)  评论(0编辑  收藏  举报