You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现递归下降表达式解析器触发TypeError如何解决

问题修复方案

错误根因

代码的核心错误出在_advance方法的实现逻辑:你错误地调用next()读取self.tok,而实际存储分词迭代器的变量是self.tokens,第一次执行_advance时self.tok还是初始值None,自然会抛出TypeError: 'NoneType' object is not an iterator的错误。
另外还有一个不影响运行的注释错误:term方法的注释错误写成了factor的语法规则定义,可一并修正。

需要修改的代码段

1. 修正_advance方法

把next()的入参从self.tok改成self.tokens即可:

def _advance(self):
    """Advance one token ahead."""
    self.tok, self.nexttok = self.nexttok, next(self.tokens, None)

2. (可选)修正term方法的注释

def term(self):
    """term ::= factor { ('*'|'/') factor }*"""

完整可运行测试代码

需要先导入依赖的模块re和collections.namedtuple:

import re
from collections import namedtuple

# 符号规则和分词函数保持不变
NUM = r"(?P<NUM>\d+)"
ADD = r"(?P<ADD>\+)"
SUB = r"(?P<SUB>-)"
MUL = r"(?P<MUL>\*)"
TRUEDIV = r"(?P<TRUEDIV>/)"
LEFTPAR = r"(?P<LEFTPAR>\()"
RIGHTPAR = r"(?P<RIGHTPAR>\))"
WS = r"(?P<WS>\s+)"

master_pat = re.compile("|".join([NUM, ADD, SUB, MUL, TRUEDIV,
                                  LEFTPAR, RIGHTPAR, WS]))
Token = namedtuple("Token", ["type", "value"])

def generate_tokens(text):
    scanner = master_pat.scanner(text)
    for match in iter(scanner.match, None):
        tok = Token(match.lastgroup, match.group())
        if tok.type != "WS":
            yield tok

# 修正后的Evaluator类
class Evaluator:
    def parse(self, text):
        self.tokens = generate_tokens(text)
        self.tok = None  # Last symbol covered
        self.nexttok = None  # Next symbol tokenized
        self._advance()  # Load first lookahead token
        return self.expr()

    def _advance(self):
        """Advance one token ahead."""
        self.tok, self.nexttok = self.nexttok, next(self.tokens, None)

    def _accept(self, toktype):
        """Test and consume the next token if it matches toktype."""
        if self.nexttok and self.nexttok.type == toktype:
            self._advance()
            return True
        else:
            return False

    def _expect(self, toktype):
        """Consume next token if it matches toktype or raise SyntaxError"""
        if not self._accept(toktype):
            raise SyntaxError("invalid syntax")

    # Grammar rules
    def expr(self):
        """expression ::= term { ('+'|'-') term }*"""
        exprval = self.term()
        while self._accept("ADD") or self._accept("SUB"):
            op = self.tok.type
            right = self.term()
            if op == "ADD":
                exprval += right
            elif op == "SUB":
                exprval -= right
        return exprval

    def term(self):
        """term ::= factor { ('*'|'/') factor }*"""
        termval = self.factor()
        while self._accept("MUL") or self._accept("TRUEDIV"):
            op = self.tok.type
            right = self.factor()
            if op == "MUL":
                termval *= right
            elif op == "TRUEDIV":
                termval /= right
        return termval

    def factor(self):
        """factor ::= NUM | ( expr )"""
        if self._accept("NUM"):
            return int(self.tok.value)
        elif self._accept("LEFTPAR"):
            exprval = self.expr()
            self._expect("RIGHTPAR")
            return exprval
        else:
            raise SyntaxError("invalid syntax")

# 测试
if __name__ == "__main__":
    evaluator = Evaluator()
    print(evaluator.parse("2"))  # 输出 2
    print(evaluator.parse("(2 + 3) * 7"))  # 输出 35
    print(evaluator.parse("10 + 5 * 2"))  # 输出 20
    print(evaluator.parse("(10 - 3) / 2"))  # 输出 3.5

内容的提问来源于stack exchange,提问作者Alan Bagel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:45:01