PLY:缺少“如果”语句

2024-05-16 12:59:56 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我第一次尝试使用PLY或任何lexer/parser工具,所以我不确定到底出了什么问题

我正在尝试实现一种基于Python语法的小型汇编语言,特别是对于带有缩进块的if语句。下面是一个例子:

if d0 == 0x42:
    a1 = d2
d0 = 0

我编写了一个解析器来处理INDENTDEDENT,它生成这个令牌列表:

LexToken(IF,'if',1,0)
LexToken(REGISTER,'d0',1,3)
LexToken(IS_EQUAL,'==',1,6)
LexToken(NUMBER,'0x42',1,9)
LexToken(COLON,':',1,13)
LexToken(INDENT,'\t',2,15)
LexToken(REGISTER,'a1',2,16)
LexToken(EQUAL,'=',2,19)
LexToken(REGISTER,'d2',2,21)
LexToken(DEDENT,'d0',3,24)
LexToken(REGISTER,'d0',3,24)
LexToken(EQUAL,'=',3,27)
LexToken(NUMBER,'0',3,29)

这似乎没问题(这些INDENTDEDENT{},linenolexpos是错误的,但我不使用它们)

我的解析器是:

import ply.yacc as yacc

# Get the token map from the lexer.  This is required.
from asmlexer import tokens, MyLexer
from instr import *


def p_statement_assignment(p):
    'statement : assignment'
    print('statmt1 :', [x for x in p])
    p[0] = p[1]
    
def p_statement_ifstatmt(p):
    'statement : ifstatmt'
    print('statmt2 :', [x for x in p])
    p[0] = p[1]
    
def p_assignment(p):
    'assignment : value EQUAL value'
    print("assignment :", [x for x in p])
    p[0] = Move(p[3], p[1])

def p_ifstatmt(p):
    'ifstatmt : IF condition COLON INDENT statement DEDENT'
    print("IF :", [x for x in p])
    p[0] = If(p[2], body = p[5])

def p_condition_equal(p):
    'condition : value IS_EQUAL value'
    print("condition ==", [x for x in p])
    p[0] = "%s == %s" % (p[1], p[3])
    
def p_value_register(p):
    'value : REGISTER'
    print('register :', [x for x in p])
    p[0] = Register(p[1])

def p_value_number(p):
    'value : NUMBER'
    print('value:', [x for x in p])
    p[0] = Value(p[1])

# Error rule for syntax errors
def p_error(p):
    print(p)
    print("Syntax error in input!")

# Build the parser
class MyParser(object):
    def __init__(self):
        lexer = MyLexer()
        self.lexer = lexer
        self.parser = yacc.yacc()
    
    def parse(self, code):
        self.lexer.input(code)
        result = self.parser.parse(lexer = self.lexer)
        return result

if True:
    with open("test.psm") as f:
        data = f.read()

    parser = MyParser()
    result = parser.parse(data)
    print(result)
    print(result.get_code())

似乎缺少IF标记:

register : [None, 'd0']
value: [None, '0x42']
condition == [None, <instr.Register object at 0x000002429DA5E340>, '==', <instr.Value object at 0x000002429DA5E250>]
register : [None, 'a1']
register : [None, 'd2']
assignment : [None, <instr.Register object at 0x000002429DA2C970>, '=', <instr.Register object at 0x000002429DA5E5E0>]
statmt1 : [None, <instr.Move object at 0x000002429DA5E370>]
LexToken(REGISTER,'d0',3,24)
Syntax error in input!
value: [None, '0']
None
Traceback (most recent call last):
  File ".\asmparser.py", line 137, in <module>
    print(result.get_code())
AttributeError: 'NoneType' object has no attribute 'get_code'

我不明白为什么


Tags: inselfnoneregisterparserforobjectvalue
1条回答
网友
1楼 · 发布于 2024-05-16 12:59:56

语法的开始符号是statement,因此语法描述的输入由一条语句组成,要么是赋值语句,要么是条件语句。因此,该酉语句后面的标记必须是输入的结尾。但事实并非如此。它是REGISTER{},因为您的输入包含两个语句

Ply生成的LALR(1)解析器可以使用下一个令牌来验证可能的缩减操作。[注意1]如果下一个令牌不能跟随缩减的非终端,则会发出错误信号。这个错误是在减少之前还是之后发出信号取决于解析器生成器的特定性质。一些解析器生成器,比如Bison,积极地优化了lookahead,如果lookahead令牌不是绝对必要的话,它们的解析器甚至不会读取它。但大多数解析器生成器(包括Ply)都会生成解析器,这些解析器在决定下一个操作之前总是先读取先行标记。[注2]

如果希望解析器处理语句序列,则需要一个扩展为语句序列的开始符号,例如program: | program statement。您可能还希望if语句的主体包含一系列语句,而不仅仅是当前语法允许的单个语句


注释

  1. “缩减操作”是解析器在到达非终端的末尾时所做的操作,并将对应于该非终端的序列“缩减”为单个非终端。作为简化操作的一部分,解析器执行简化操作;在Ply的情况下,这意味着调用与正在减少的生产相关联的p_函数

  2. 仅仅因为解析器已经读取了lookahead标记,并不意味着它必须在进行缩减之前查阅它。许多解析器使用压缩表,这些表可能会将错误操作与默认减少操作结合起来

相关问题 更多 >