真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器

本文小編為大家詳細(xì)介紹“怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比平邑網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式平邑網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋平邑地區(qū)。費(fèi)用合理售后完善,十年實(shí)體公司更值得信賴。

計(jì)算功能演示

這里先展示了程序的幫助信息,然后是幾個(gè)簡(jiǎn)單的四則運(yùn)算測(cè)試,看起來(lái)是沒問(wèn)題了(我可不敢保證,程序沒有bug?。?。

怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器

輸出 tokens

怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器

輸出 AST

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

怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器

代碼

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

Node、BinOp、Constan 是用來(lái)表示節(jié)點(diǎn)的類.
Calculator 中 lexizer 方法是進(jìn)行分詞的,本來(lái)我是打算使用正則的,如果你看過(guò)我前面的博客的話,可以發(fā)現(xiàn)我是用的正則來(lái)分詞的(因?yàn)?Python 的官方文檔正則表達(dá)式中有一個(gè)簡(jiǎn)易的分詞程序)。不過(guò)我看其他人都是手寫的分詞,所以我也這樣做了,不過(guò)感覺并不是很好,很繁瑣,而且容易出錯(cuò)。
parse 方法是進(jìn)行解析的,主要是解析表達(dá)式的結(jié)構(gòu),判斷是否符合四則運(yùn)算的文法,最終生成表達(dá)式樹(它的 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:
    """
    簡(jiǎn)單的抽象語(yǔ)法樹節(jié)點(diǎn),定義一些需要使用到的具有層次結(jié)構(gòu)的節(jié)點(diǎn)
    """

    def eval(self) -> float: ...   # 節(jié)點(diǎn)的計(jì)算方法
    def visit(self): ...           # 節(jié)點(diǎn)的訪問(wèn)方法


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):
        """
        遍歷樹的各個(gè)節(jié)點(diǎn),并生成 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)  # 轉(zhuǎn)成字符是因?yàn)殇秩境蓤D像時(shí),需要該字段為 str
                }
            ]
        }


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

    def __init__(self, expr) -> None:
        self.expr = expr           # 輸入的表達(dá)式
        self.parse_end = False     # 解析是否結(jié)束,默認(rèn)未結(jié)束
        self.toks = []             # 解析的 tokens
        self.index = 0             # 解析的下標(biāo)

    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):
        """
        獲取當(dāng)前位置的 token
        """
        if 0 <= self.index < len(self.toks):
            tok = self.toks[self.index]
            return tok
        if self.index == len(self.toks):  # token解析結(jié)束
            return {
                "kind": "EOF",
                "value": "EOF"
            }
        raise Exception("Encounter Error, invalid index = ", self.index)

    def move_token(self):
        """
        下標(biāo)向后移動(dòng)一位
        """
        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":
                # 解析結(jié)束的標(biāo)志
                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__":
    # 添加命令行參數(shù)解析器
    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:             # 計(jì)算結(jié)果
        print(tree.eval())

讀到這里,這篇“怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


分享文章:怎么使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的四則運(yùn)算解釋器
地址分享:http://weahome.cn/article/jipoes.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部