91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Python實現一個簡單的四則運算解釋器

發布時間:2023-04-21 16:57:11 來源:億速云 閱讀:92 作者:iii 欄目:編程語言

本文小編為大家詳細介紹“怎么使用Python實現一個簡單的四則運算解釋器”,內容詳細,步驟清晰,細節處理妥當,希望這篇“怎么使用Python實現一個簡單的四則運算解釋器”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

計算功能演示

這里先展示了程序的幫助信息,然后是幾個簡單的四則運算測試,看起來是沒問題了(我可不敢保證,程序沒有bug!)。

怎么使用Python實現一個簡單的四則運算解釋器

輸出 tokens

怎么使用Python實現一個簡單的四則運算解釋器

輸出 AST

這個格式化的 JSON 信息太長了,不利于直接看到。我們將它渲染出來看最后生成的樹形圖。保存下面這個 JSON 在一個文件中,這里我叫做 demo.json,然后執行如下命令:pytm-cli -d LR -i demo.json -o demo.html,然后再瀏覽器打開生成的 html 文件。

怎么使用Python實現一個簡單的四則運算解釋器

代碼

所有的代碼都在這里了,只需要一個文件 my_eval.py,想要運行的話,復制、粘貼,然后按照演示的步驟執行即可。

Node、BinOp、Constan 是用來表示節點的類.
Calculator 中 lexizer 方法是進行分詞的,本來我是打算使用正則的,如果你看過我前面的博客的話,可以發現我是用的正則來分詞的(因為 Python 的官方文檔正則表達式中有一個簡易的分詞程序)。不過我看其他人都是手寫的分詞,所以我也這樣做了,不過感覺并不是很好,很繁瑣,而且容易出錯。
parse 方法是進行解析的,主要是解析表達式的結構,判斷是否符合四則運算的文法,最終生成表達式樹(它的 AST)。

"""
Grammar

G -> E
E -> T E'
E' -> '+' T E' | '-' T E' | ?
T -> F T'
T' -> '*' F T' | '/' F T' | ?
F -> '(' E ')' | num | name

"""

import json
import argparse


class Node:
    """
    簡單的抽象語法樹節點,定義一些需要使用到的具有層次結構的節點
    """

    def eval(self) -> float: ...   # 節點的計算方法
    def visit(self): ...           # 節點的訪問方法


class BinOp(Node):
    """
    BinOp Node
    """

    def __init__(self, left, op, right) -> None:
        self.left = left
        self.op = op
        self.right = right

    def eval(self) -> float:
        if self.op == "+":
            return self.left.eval() + self.right.eval()
        if self.op == "-":
            return self.left.eval() - self.right.eval()
        if self.op == "*":
            return self.left.eval() * self.right.eval()
        if self.op == "/":
            return self.left.eval() / self.right.eval()
        return 0

    def visit(self):
        """
        遍歷樹的各個節點,并生成 JSON 表示
        """

        return {
            "name": "BinOp",
            "children": [
                self.left.visit(),
                {
                    "name": "OP",
                    "children": [
                        {
                            "name": self.op
                        }
                    ]
                },
                self.right.visit()
            ]
        }


class Constant(Node):
    """
    Constant Node
    """

    def __init__(self, value) -> None:
        self.value = value

    def eval(self) -> float:
        return self.value

    def visit(self):
        return {
            "name": "NUMBER",
            "children": [
                {
                    "name": str(self.value)  # 轉成字符是因為渲染成圖像時,需要該字段為 str
                }
            ]
        }


class Calculator:
    """
    Simple Expression Parser
    """

    def __init__(self, expr) -> None:
        self.expr = expr           # 輸入的表達式
        self.parse_end = False     # 解析是否結束,默認未結束
        self.toks = []             # 解析的 tokens
        self.index = 0             # 解析的下標

    def lexizer(self):
        """
        分詞
        """
        index = 0
        while index < len(self.expr):
            ch = self.expr[index]
            if ch in [" ", "\r", "\n"]:
                index += 1
                continue
            if '0' <= ch <= '9':
                num_str = ch
                index += 1
                while index < len(self.expr):
                    n = self.expr[index]
                    if '0' <= n <= '9':
                        if ch == '0':
                            raise Exception("Invalid number!")
                        num_str = n
                        index += 1
                        continue
                    break
                self.toks.append({
                    "kind": "INT",
                    "value": int(num_str)
                })
            elif ch in ['+', '-', '*', '/', '(', ')']:
                self.toks.append({
                    "kind": ch,
                    "value": ch
                })
                index += 1
            else:
                raise Exception("Unkonwn character!")

    def get_token(self):
        """
        獲取當前位置的 token
        """
        if 0 <= self.index < len(self.toks):
            tok = self.toks[self.index]
            return tok
        if self.index == len(self.toks):  # token解析結束
            return {
                "kind": "EOF",
                "value": "EOF"
            }
        raise Exception("Encounter Error, invalid index = ", self.index)

    def move_token(self):
        """
        下標向后移動一位
        """
        self.index += 1

    def parse(self) -> Node:
        """
        G -> E
        """
        # 分詞
        self.lexizer()
        # 解析
        expr_tree = self.parse_expr()
        if self.parse_end:
            return expr_tree
        else:
            raise Exception("Invalid expression!")

    def parse_expr(self):
        """
        E -> T E'
        E' -> + T E' | - T E' | ?
        """
        # E -> E E'
        left = self.parse_term()
        # E' -> + T E' | - T E' | ?
        while True:
            tok = self.get_token()
            kind = tok["kind"]
            value = tok["value"]

            if tok["kind"] == "EOF":
                # 解析結束的標志
                self.parse_end = True
                break
            if kind in ["+", "-"]:
                self.move_token()
                left = BinOp(left, value, self.parse_term())
            else:
                break

        return left

    def parse_term(self):
        """
        T -> F T'
        T' -> * F T' | / F T' | ?
        """
        # T -> F T'
        left = self.parse_factor()
        # T' -> * F T' | / F T' | ?
        while True:
            tok = self.get_token()
            kind = tok["kind"]
            value = tok["value"]

            if kind in ["*", "/"]:
                self.move_token()
                right = self.parse_factor()
                left = BinOp(left, value, right)
            else:
                break

        return left

    def parse_factor(self):
        """
        F -> '(' E ')' | num | name
        """
        tok = self.get_token()
        kind = tok["kind"]
        value = tok["value"]
        if kind == '(':
            self.move_token()
            expr_node = self.parse_expr()
            if self.get_token()["kind"] != ")":
                raise Exception("Encounter Error, expected )!")
            self.move_token()
            return expr_node
        if kind == "INT":
            self.move_token()
            return Constant(value=value)

        raise Exception("Encounter Error, unknown factor: ", kind)


if __name__ == "__main__":
    # 添加命令行參數解析器
    cmd_parser = argparse.ArgumentParser(
        description="Simple Expression Interpreter!")
    group = cmd_parser.add_mutually_exclusive_group()
    group.add_argument("--tokens", help="print tokens", action="store_true")
    group.add_argument("--ast", help="print ast in JSON", action="store_true")
    cmd_parser.add_argument(
        "expr", help="expression, contains ['+', '-', '*', '/', '(', ')', 'num']")
    args = cmd_parser.parse_args()

    calculator = Calculator(expr=args.expr)
    tree = calculator.parse()
    if args.tokens:   # 輸出 tokens
        for t in calculator.toks:
            print(f"{t['kind']:3s} ==> {t['value']}")
    elif args.ast:    # 輸出 JSON 表示的 AST
        print(json.dumps(tree.visit(), indent=4))
    else:             # 計算結果
        print(tree.eval())

讀到這里,這篇“怎么使用Python實現一個簡單的四則運算解釋器”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

辽中县| 延长县| 湖南省| 长乐市| 青川县| 佛冈县| 梅州市| 武陟县| 永和县| 玉门市| 呼图壁县| 锡林浩特市| 阿荣旗| 酉阳| 五莲县| 都兰县| 寿光市| 手机| 民县| 漳浦县| 洞口县| 苗栗县| 万荣县| 繁昌县| 定边县| 宁晋县| 尚义县| 吉安市| 晋中市| 新昌县| 无为县| 华安县| 静乐县| 手游| 云阳县| 普宁市| 孟津县| 汝城县| 土默特左旗| 墨竹工卡县| 广汉市|