本文介绍了从PLY yacc访问并打印AST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在使用PLY编译一种语言(C-减法),以构建词法分析器和解析器。在PLY文档中很清楚,构建AST完全由用户决定(https://www.dabeaz.com/ply/ply.html#ply_nn2):
Yacc.py的输出通常是抽象语法树(AST)。但是,这完全由用户决定。那么,在我的词法分析器和解析器正常工作的情况下,我如何构建一个AST阅读器(因为正如文档中所说,输出是一个AST,所以我只需要访问它)?我正在尝试使用下面的代码,但仅收到
None
作为响应。
AST代码:
def dumpast(node):
_dumpast(node)
print('pass 3')
print('')
def _dumpast(node, level=0):
if isinstance(node, tuple):
indent(level)
nchildren = len(node) - 1
print("(%s" % node[0], end='')
if nchildren > 0:
print(" ", end='')
for c in range(nchildren):
_dumpast(node[c+1], level+1)
if c != nchildren-1:
print(' ', end='')
print(")", end='')
elif isinstance(node, list):
indent(level)
nchildren = len(node)
print("[", end='')
if nchildren > 0:
print(" ", end='')
for c in range(nchildren):
_dumpast(node[c], level+1)
if c != nchildren-1:
print(' ', end='')
print("]", end='')
else:
print("%s" % str(node), end='')
def indent(level):
print('')
for i in range(level):
print(' |',end='')
和main.py
:
import ply.yacc as yacc
import ply.lex as lex
from tabulate import tabulate
import sys
from lexer import *
from parser import Parser
from ast import dumpast
lexer = lex.lex()
print('pass 1')
parser = yacc.yacc(module=Parser)
with open(sys.argv[1], 'r') as f:
dumpast(parser.parse(f.read(),lexer))
print('pass 2')
响应:
通过%1
非第3页通过2
我做错了什么吗?或者,有没有人可以分享AST建筑教程来访问PLY?
编辑:包括parser.py以显示解析的工作原理:
import ply.yacc as yacc
import lexer
from state import state
class Parser():
tokens = lexer.tokens
def p_program(p):
'program : declaration_list'
state.ast = p[1]
print('passou 4')
def p_declaration_list(p):
'''declaration_list : declaration_list declaration
| declaration'''
if len(p) == 3:
p[0] = p[1]
p[0].append(p[2])
else:
p[0] = p[1]
def p_declaration(p):
'''declaration : var_declaration
| fun_declaration'''
state.ast = p[1]
def p_var_declaration(p):
'''var_declaration : type_specifier ID
| type_specifier ID LBRACKET NUM RBRACKET'''
if len(p) == 3:
p[0] = ('ASSIGN', ('ID', p[1]))
else:
p[0] = ('ASSIGN', ('ID', p[1]), ('NUM', p[4]))
def p_type_specifier(p):
'''type_specifier : INT
| VOID'''
state.ast = p[1]
def p_fun_declaration(p):
'fun_declaration : type_specifier ID LPAREN params RPAREN compound_stmt'
p[0] = ('ASSIGN', ('ID', p[1]), p[4], p[6])
def p_params(p):
'''params : param_list
| VOID'''
state.ast = p[1]
def p_param_list(p):
'''param_list : param_list COLON param
| param'''
if len(p) == 4:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = p[1]
def p_param(p):
'''param : type_specifier ID
| type_specifier ID LBRACKET RBRACKET'''
p[0] = ('ASSIGN', ('ID', p[1]))
def p_compound_stmt(p):
'compound_stmt : LKEY local_declarations statement_list RKEY'
p[0] = (p[2], p[3])
def p_local_declarations(p):
'''local_declarations : local_declarations var_declaration
| empty'''
if len(p) > 1:
p[0] = (p[1], p[2])
else:
pass
def p_statement_list(p):
'''statement_list : statement_list statement
| empty'''
if len(p) > 1:
p[0] = p[1]
p[0].append(p[3])
else:
pass
def p_statement(p):
'''statement : expression_stmt
| compound_stmt
| selection_stmt
| iteration_stmt
| return_stmt'''
state.ast = p[1]
def p_expression_stmt(p):
'''expression_stmt : expression SEMICOLON
| SEMICOLON'''
if len(p) == 3:
p[0] = p[1]
else:
pass
def p_selection_stmt(p):
'''selection_stmt : IF LPAREN expression RPAREN statement
| IF LPAREN expression RPAREN statement ELSE statement'''
if len(p) == 6:
p[0] = ('IF', p[3], p[5], ('NIL',))
else:
p[0] = ('IF', p[3], p[5], p[7])
def p_iteration_stmt(p):
'iteration_stmt : WHILE LPAREN expression RPAREN statement'
p[0] = ('WHILE', p[3], p[5])
def p_return_stmt(p):
'''return_stmt : RETURN SEMICOLON
| RETURN expression SEMICOLON'''
if len(p) == 3:
p[0] = ('RETURN',)
else:
p[0] = ('RETURN', p[2])
def p_expression(p):
'''expression : var EQUAL expression
| simple_expression'''
if len(p) > 2:
p[0] = ('ASSIGN', (p[1], p[3]))
else:
p[0] = [p[1]]
def p_var(p):
'''var : ID
| ID LBRACKET expression RBRACKET'''
if len(p) == 2:
p[0] = ('ID', p[1])
else:
p[0] = (('ID', p[1]), [p[3]])
def p_simple_expression(p):
'''simple_expression : additive_expression relop additive_expression
| additive_expression'''
if len(p) == 4:
p[0] = (p[1], ('RELOP', p[2]), p[3])
else:
p[0] = [p[1]]
def p_relop(p):
'''relop : LESSOREQUAL
| LESS
| GREAT
| GREATOREQUAL
| DOUBLEEQUAL
| NOTEQUAL'''
p[0] = ('RELOP', p[1])
def p_additive_expression(p):
'''additive_expression : additive_expression addop term
| term'''
if len(p) == 4:
p[0] = (p[1], p[2], p[3])
else:
p[0] = p[1]
def p_addop(p):
'''addop : PLUS
| MINUS'''
p[0] = p[1]
def p_term(p):
'''term : term mulop factor
| factor'''
if len(p) == 4:
p[0] = (p[1], p[2], p[3])
else:
p[0] = p[1]
def p_mulop(p):
'''mulop : MULT
| DIV'''
p[0] = p[1]
def p_factor(p):
'''factor : LPAREN expression RPAREN
| var
| call
| NUM'''
if len(p) == 4:
p[0] = p[2]
elif p == 'NUM':
p[0] = ('ASSIGN', ('NUM', p[1]))
else:
p[0] = p[1]
def p_call(p):
'call : ID LPAREN args RPAREN'
p[0] = (('ID', p[1]), p[3])
def p_args(p):
'''args : arg_list
| empty'''
if p == '':
pass
else:
state.ast = p[1]
def p_args_list(p):
'''arg_list : arg_list COLON expression
| expression'''
if len(p) == 4:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = p[1]
def p_error(p):
if not p:
print("SYNTAX ERROR AT EOF")
def p_empty(p):
'empty :'
pass
推荐答案
parser.parse()
返回顶层还原操作放置到p[0]
中的任何内容。您的顶级缩减操作不会将任何内容放入p[0]
。所以parse函数返回None
,这就是您传递给AST转储程序的内容。
state.ast
这样的状态(或全局)变量来从PLY解析器返回值;这是一种您可能从不同解析器生成器的解决方案中复制的模式。我注意到,您还将state.ast
赋值给state.ast
,而不是在其他操作中设置p[0]
,即使在解析器生成器中也不可能是正确的,因为解析器生成器没有提供更方便的机制来返回顶级结果。这些也需要更正。
这篇关于从PLY yacc访问并打印AST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!