Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

王林
王林ke hadapan
2023-04-21 11:46:091626semak imbas

Demonstrasi fungsi pengiraan

Berikut ialah maklumat bantuan program, dan kemudian beberapa ujian operasi empat aritmetik yang mudah Nampaknya tiada masalah (saya tidak dapat menjamin bahawa program ini tidak mempunyai pepijat! ).

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Token output

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Output AST

Mesej JSON yang diformatkan ini terlalu panjang untuk tontonan langsung. Kami memberikannya untuk melihat gambar rajah pokok yang dijana akhir (lihat dua blog sebelumnya untuk kaedah). Simpan JSON berikut dalam fail, di sini saya memanggilnya demo.json, dan kemudian laksanakan arahan berikut: pytm-cli -d LR -i demo.json -o demo.html, dan kemudian buka fail html yang dijana dalam penyemak imbas.

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Kod

Semua kod ada di sini, anda hanya perlukan satu fail my_eval.py untuk dijalankan Jika ya, hanya salin, tampal, dan ikuti langkah-langkah dalam demonstrasi.

Node, BinOp dan Constan ialah kelas yang digunakan untuk mewakili nod.
Kaedah lexizer dalam Kalkulator digunakan untuk pembahagian perkataan Pada asalnya, saya bercadang untuk menggunakan regularization Jika anda telah membaca blog saya sebelum ini bolehkah saya mendapati bahawa saya menggunakan ungkapan biasa untuk membahagikan perkataan (kerana terdapat program pembahagian perkataan yang mudah dalam ungkapan biasa dokumentasi rasmi Python). Tetapi saya melihat bahawa orang lain menulis participles dengan tangan, jadi saya melakukan perkara yang sama, tetapi ia tidak terasa sangat baik, ia sangat membosankan dan terdedah kepada kesilapan.
Kaedah penghuraian adalah untuk menghurai, terutamanya untuk menganalisis struktur ungkapan, menentukan sama ada ia mematuhi tatabahasa empat operasi aritmetik, dan akhirnya menjana pepohon ungkapan (ASTnya).

"""
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 &#39;0&#39; <= ch <= &#39;9&#39;:
                num_str = ch
                index += 1
                while index < len(self.expr):
                    n = self.expr[index]
                    if &#39;0&#39; <= n <= &#39;9&#39;:
                        if ch == &#39;0&#39;:
                            raise Exception("Invalid number!")
                        num_str = n
                        index += 1
                        continue
                    break
                self.toks.append({
                    "kind": "INT",
                    "value": int(num_str)
                })
            elif ch in [&#39;+&#39;, &#39;-&#39;, &#39;*&#39;, &#39;/&#39;, &#39;(&#39;, &#39;)&#39;]:
                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&#39;
        E&#39; -> + T E&#39; | - T E&#39; | ɛ
        """
        # E -> E E&#39;
        left = self.parse_term()
        # E&#39; -> + T E&#39; | - T E&#39; | ɛ
        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&#39;
        T&#39; -> * F T&#39; | / F T&#39; | ɛ
        """
        # T -> F T&#39;
        left = self.parse_factor()
        # T&#39; -> * F T&#39; | / F T&#39; | ɛ
        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 -> &#39;(&#39; E &#39;)&#39; | num | name
        """
        tok = self.get_token()
        kind = tok["kind"]
        value = tok["value"]
        if kind == &#39;(&#39;:
            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 [&#39;+&#39;, &#39;-&#39;, &#39;*&#39;, &#39;/&#39;, &#39;(&#39;, &#39;)&#39;, &#39;num&#39;]")
    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[&#39;kind&#39;]:3s} ==> {t[&#39;value&#39;]}")
    elif args.ast:    # 输出 JSON 表示的 AST
        print(json.dumps(tree.visit(), indent=4))
    else:             # 计算结果
        print(tree.eval())

Ringkasan

Saya pada asalnya ingin bercakap tentang mengapa ia dipanggil my_eval.py di hadapan, tetapi saya merasakan tidak ramai orang di belakangnya, jadi saya akan mengatakannya di sini. Jika anda menulis ungkapan yang kompleks, bagaimana anda mengesahkan sama ada ia betul? Di sini kita hanya boleh menggunakan Python, jurubahasa yang paling sempurna, haha. Fungsi eval Python digunakan di sini Sudah tentu, anda tidak perlu memanggil fungsi ini, hanya menyalin ungkapan yang dikira secara langsung. Saya menggunakan fungsi eval hanya untuk menyatakan mengapa program saya dipanggil my_eval.

Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah

Selepas dilaksanakan dengan cara ini, ia boleh dianggap sebagai melengkapkan penterjemah empat aritmetik mudah. Walau bagaimanapun, jika anda melakukannya sekali lagi, anda mungkin akan merasakan bahawa keseluruhan proses itu sangat menyusahkan seperti saya. Oleh kerana terdapat alat sedia untuk pembahagian perkataan dan analisis tatabahasa, dan ia tidak terdedah kepada kesilapan, beban kerja boleh dikurangkan dengan banyak. Walau bagaimanapun, perlu melakukannya sendiri Sebelum menggunakan alat, anda mesti memahami fungsi alat tersebut.

Atas ialah kandungan terperinci Menggunakan Python untuk melaksanakan empat penterjemah aritmetik mudah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam