在PLY

时间:2018-06-11 18:56:19

标签: python parsing grammar lexer ply

我使用PLY来解析自定义定义文件的命令。命令每行定义一个,每个命令应以保留关键字开头,后跟多个字符串。我已成功设法为语法编写词法分析器和解析器,但我在生产中提出SyntaxError时遇到问题。

根据PLY's documentation,只需在解析器规则的主体内抛出SyntaxError即可:

  

如有必要,生产规则可以手动强制解析器进入错误恢复。这是通过像这样引发SyntaxError异常来完成的:

def p_production(p):
    'production : some production ...'
    raise SyntaxError

我的代码在遇到无效语法时会在生产中引发SyntaxError,但是当我运行程序时,不会引发此错误。这是一个最小的工作示例:

from ply import lex, yacc

class Parser(object):
    # reserved keyword tokens
    reserved = {
        "r": "R"
    }

    # top level tokens
    tokens = [
        'CHUNK',
        'NEWLINE'
    ]

    # add reserved tokens
    tokens += reserved.values()

    # ignore spaces and tabs
    t_ignore = ' \t'

    def __init__(self):
        # lexer and parser handlers
        self.lexer = lex.lex(module=self)
        self.parser = yacc.yacc(module=self)

    def parse(self, text):
        # pass text to yacc
        self.parser.parse(text, lexer=self.lexer)

    # detect new lines
    def t_newline(self, t):
        r'\n+'
        # generate newline token
        t.type = "NEWLINE"
        return t

    def t_CHUNK(self, t):
        r'[a-zA-Z0-9_=.:]+'
        # check if chunk is a keyword
        t.type = self.reserved.get(t.value.lower(), 'CHUNK')
        return t

    def t_error(self, t):
        raise SyntaxError("token error")

    def p_instruction_list(self, p):
        '''instruction_list : instruction
                            | instruction_list instruction'''
        pass

    # match instruction on their own lines
    def p_instruction(self, p):
        '''instruction : command NEWLINE
                       | NEWLINE'''
        pass

    def p_command(self, p):
        '''command : R CHUNK CHUNK CHUNK CHUNK'''
        # parse command
        if p[2] not in ["a", "b"]:
            raise SyntaxError("invalid thing")

    def p_error(self, p):
        raise SyntaxError("parsing error")

if __name__ == "__main__":
    parser = Parser()
    parser.parse("""
    r a text text text
    r c text text text
    r b text text text
    """)

上面的示例在没有输出任何内容的情况下运行,这意味着它已成功解析了文本,即使p_command由于行r c text text text(第二个令牌{{1}而应该引发语法错误}}无效;只有ca才有效。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

您负责打印错误消息,但您没有:

  

手动设置错误的一个重要方面是在这种情况下p_error()函数将 NOT 被调用。如果您需要发出错误消息,请确保在提升SyntaxError的制作中执行此操作。

我不相信p_error()应该提出SyntaxError。它应该只打印一个适当的消息(或以其他方式记录发生错误的事实)并让错误恢复继续进行。但无论如何,在这种情况下不会被调用,如上面的引用所示。

我也不是100%相信lexer加注SyntaxError。我首选的词汇错误策略是将它们传递给解析器,从而将错误处理集中在一个地方。

如果您不关心错误恢复,请不要在任何规则中使用error令牌。该令牌仅用于错误恢复。如果您只是想在遇到错误时立即抛出异常,请在p_error中执行此操作,并在不会自动调用它的位置显式调用p_error(例如检测到令牌错误和错误)在语义行为中)。您可以抛出ValueError或从中派生的东西;我会远离SyntaxError,这对Ply和Python来说具有特殊的意义。

相关问题