zoukankan      html  css  js  c++  java
  • 实现加减乘除任意组合的语法解析

    给定一个字符串如: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) 
  • 相关阅读:
    二级联动选择框的实现
    vimperator
    Ipan笔记-2
    git的一些补充点
    联想云部署的笔记心得
    关于vim的折叠
    ipan笔记
    php中浮点数计算问题
    Chrome 控制台报错Unchecked runtime.lastError: The message port closed before a response was received
    PHP-redis中文文档
  • 原文地址:https://www.cnblogs.com/aijianiula/p/9961331.html
Copyright © 2011-2022 走看看