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

基于rply开发自定义语言时如何通过Parser实现字符串打印

核心报错原因

代码无法运行、不能正确输出字符串的问题来自4处:

  • Parser中statement语法规则仅添加了装饰器,没有编写对应处理函数,语法定义不完整
  • 现有statement规则仅支持匹配单个STRING token,无法处理引号内被空格拆分为多个STRING的连续单词
  • AST层缺少字符串字面量节点,Print节点调用value.eval()时没有对应实现
  • 主入口提前遍历了lexer返回的迭代器对象,迭代器遍历一次后内容为空,后续解析器拿不到任何token直接抛出异常
具体修改方案

1. 补全AST节点定义(AST.py)

新增字符串字面量节点,实现eval方法返回字符串内容:

class Print():
  def __init__(self, value):
     self.value = value

  def eval(self):
     print(self.value.eval())

# 新增字符串节点
class String():
    def __init__(self, content):
        self.value = content
    
    def eval(self):
        return self.value

2. 完善Parser语法规则(Parser.py)

导入新增的String节点,补全statement规则,支持多个连续STRING token自动拼接为完整字符串:

from rply import ParserGenerator
from ast import Print, String


class Parser():
    def __init__(self):
         self.pg = ParserGenerator(
           ['PRINT', 'QUOTE', 'STRING', 'ENDLN']
         )

    def parse(self):
         @self.pg.production('program : PRINT QUOTE statement QUOTE ENDLN')
         def program(p):
            # p[2]对应语法规则里的statement部分,也就是拼接完成的字符串节点
            return Print(p[2])

         # 匹配单个字符串token
         @self.pg.production('statement : STRING')
         def single_string(p):
            return String(p[0].getstr())
         
         # 匹配多个连续字符串token,递归拼接,单词之间补空格
         @self.pg.production('statement : statement STRING')
         def concat_string(p):
            prev_content = p[0].eval()
            new_word = p[1].getstr()
            return String(f"{prev_content} {new_word}")

    def get_parser(self):
         return self.pg.build()

3. 修复主入口迭代器耗尽问题

rply的lexer返回的是生成器对象,提前遍历会导致后续解析无内容,如需调试打印token要先转成列表存储:

from lexer import Lexer
from parser import Parser

lexer = Lexer().get_lexer()
tokens = lexer.lex(input())

# 调试打印token时请打开以下注释,直接遍历原生成器会导致后续解析失败
# token_list = list(tokens)
# for token in token_list:
#    print(token)

pg = Parser()
pg.parse()
parser = pg.get_parser()
# 调试时传入token_list,正常运行直接传入tokens即可
parser.parse(tokens).eval()

修改完成后输入outln "I love SO";即可正常输出I love SO。

可选优化:如果想简化Parser逻辑,可以直接修改Lexer规则,一次性匹配双引号包裹的完整字符串,不需要拆分后再拼接,对应添加规则:self.lexer.add('STRING', r'"[^"]*"'),解析时去掉首尾引号即可,这种实现方式更符合常规词法分析器的设计逻辑。


内容的提问来源于stack exchange,提问作者gamer merch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 08:24:26