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

溫馨提示×

溫馨提示×

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

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

怎么使用Python制作一個極簡四則運算解釋器

發布時間:2023-04-08 18:00:19 來源:億速云 閱讀:180 作者:iii 欄目:開發技術

本篇內容主要講解“怎么使用Python制作一個極簡四則運算解釋器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用Python制作一個極簡四則運算解釋器”吧!

計算功能演示

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

怎么使用Python制作一個極簡四則運算解釋器

輸出 tokens

怎么使用Python制作一個極簡四則運算解釋器

輸出 AST

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

怎么使用Python制作一個極簡四則運算解釋器

怎么使用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())

總結

本來想在前面說一下為什么叫 my_eval.py,但是感覺看到后面的人不多,那就在這里說好了。如果寫了一個復雜的表達式,那么怎么驗證是否正確的。這里我們直接利用 Python 這個最完美的解釋器就好了,哈哈。這里用 Python 的 eval 函數,你當然是不需要調用這個函數,直接復制計算的表達式即可。我用 eval 函數,只是想表達為什么我的程序會叫 my_eval 這個名字。

怎么使用Python制作一個極簡四則運算解釋器

這樣實現下來,也算是完成了一個簡單的四則運算解釋器了。不過,如果你也做一遍的話,也估計會和我一樣感覺到整個過程很繁瑣。因為分詞和語法解析都有現成的工具可以來完成,而且不容易出錯,可以大大減少工作量。不過,自己來一遍也是很有必要的,在使用工具之前,至少也要了解工具的作用。

到此,相信大家對“怎么使用Python制作一個極簡四則運算解釋器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

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

AI

兴城市| 正宁县| 德阳市| 前郭尔| 海晏县| 武定县| 田阳县| 安阳县| 偏关县| 九龙城区| 囊谦县| 新化县| 饶河县| 太保市| 平顶山市| 阿拉善右旗| 雅安市| 武夷山市| 宣武区| 呼玛县| 中江县| 清镇市| 苗栗县| 富川| 灵寿县| 沿河| 陇西县| 重庆市| 伊吾县| 祁东县| 兰溪市| 周宁县| 依兰县| 晋州市| 崇左市| 贵溪市| 潞城市| 天峨县| 香港| 卫辉市| 西丰县|