基于Python PLY开发转译器:实现多行代码解析的方法及代码示例
如何用PLY实现多行代码的解析与运行?
问题描述
我正在使用Python的PLY库编写一个转译器,但目前仅能读取并转换单行代码。以下是我的Yacc相关实现代码:
lexer = lex.lex() precedence = ( ('left', 'ADD', 'SUB'), ('left', 'MULTI', 'DIV'), ('left', 'RPAREN', 'LPAREN') ) def p_expression_term(p): ''' expression : term ENDOFLINE | var_assign ENDOFLINE | empty ''' p[0] = p[1] def p_expression_empty(p): 'empty : ' pass def p_expression_add(p): 'term : term ADD term' def p_expression_sub(p): 'term : term SUB term' def p_term_multi(p): '''term : term MULTI term ''' def p_term_div(p): 'term : term DIV term' def p_term_pow(p): 'term : term POW term' p[0] = pow(p[1], p[3]) def p_term_factor(p): 'term : factor' p[0] = p[1] def p_factor_num(p): 'factor : NUMBER' p[0] = ['number', p[1]] def p_expressionParenth(p): '''term : LPAREN term RPAREN''' p[0] = p[2] pass def p_var_assign1(p): '''var_assign : NAME EQUAL NAME | NAME EQUAL term ''' p[0] = ast_tree.ast_name1(p[1], p[3]) def p_var_assignBe(p): '''var_assign : LET NAME BE term''' def p_var_assign3(p): '''var_assign : NAME IDENTIFIER EQUAL term''' # Error rule for syntax errors def p_error(p): print("Syntax error in input! at " + str(p)) # Build the parser parser = yacc.yacc() while True: try: s = '''let x be 12;''' except EOFError: break if not s: continue result = parser.parse(s) result = ast_tree.fill_locations(result) print(ast.unparse(result)) exit()
我当前在p_expression_term方法中进行代码解析,此前尝试过GitHub上的一些解决方案但均未生效。请问如何实现对输入中多行代码的运行与解析?能否提供对应的代码片段?
解决方案
你的核心问题在于顶层语法规则只支持单个带结束符的表达式,无法处理多个语句的序列。我们需要修改Yacc的语法结构,让它能识别由多个语句组成的“程序”,同时调整解析逻辑来处理多行输入。
以下是修改后的关键代码片段和解释:
1. 重构顶层语法规则
首先定义一个program规则,用来表示由多个语句组成的完整程序,再定义statement规则对应单个语句(支持换行或分号作为结束符):
# 顶层规则:程序由多个语句组成 def p_program(p): '''program : statement | program statement''' # 收集所有语句到列表中 if len(p) == 2: p[0] = [p[1]] if p[1] is not None else [] else: if p[2] is not None: p[0] = p[1] + [p[2]] else: p[0] = p[1] # 单个语句:表达式 + 结束符(换行或分号),支持空行 def p_statement(p): '''statement : expression ENDOFLINE | expression SEMICOLON | empty ENDOFLINE | empty SEMICOLON''' p[0] = p[1] # 只保留表达式部分,丢弃结束符 # 原表达式规则去掉结束符,专注于表达式本身 def p_expression(p): ''' expression : term | var_assign | empty ''' p[0] = p[1]
2. 修复表达式规则的实现细节
注意你之前的加减乘除规则没有设置p[0],这会导致AST无法正确生成,需要补充:
def p_expression_add(p): 'term : term ADD term' # 这里替换为你的AST构建逻辑,示例用简单结构 p[0] = ['add', p[1], p[3]] def p_expression_sub(p): 'term : term SUB term' p[0] = ['sub', p[1], p[3]] def p_term_multi(p): '''term : term MULTI term ''' p[0] = ['multi', p[1], p[3]] def p_term_div(p): 'term : term DIV term' p[0] = ['div', p[1], p[3]] # 补全var_assignBe规则的p[0]设置 def p_var_assignBe(p): '''var_assign : LET NAME BE term''' p[0] = ast_tree.ast_name1(p[2], p[4]) # 假设和var_assign1逻辑一致
3. 修改解析循环以支持多行输入
原来的测试代码固定了单行输入,现在改成读取多行内容(比如从标准输入读取),并遍历解析后的语句列表处理:
import sys # Build the parser parser = yacc.yacc() try: # 读取多行输入(比如用户输入多行后按Ctrl+D结束) s = sys.stdin.read() except EOFError: s = '' if s: result = parser.parse(s) # 遍历每个语句并处理 for stmt in result: if stmt is not None: stmt = ast_tree.fill_locations(stmt) print(ast.unparse(stmt))
关键修改说明
- 顶层规则重构:通过
program规则允许多个statement的序列,这是支持多行的核心。 - 语句结束符分离:把
ENDOFLINE/SEMICOLON从表达式规则移到statement规则,让表达式本身不依赖结束符,更符合语法逻辑。 - 空行处理:支持空行(通过
empty ENDOFLINE规则),避免空行触发语法错误。 - 补全AST生成:确保所有语法规则都设置了
p[0],否则解析结果会丢失节点。
内容的提问来源于stack exchange,提问作者beton
相关产品推荐
相关产品推荐

