1. 程式人生 > >實現加減乘除任意組合的語法解析

實現加減乘除任意組合的語法解析

給定一個字串如: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)