从 PLY 中的解析器规则发出错误信号
Signalling an error from a parser rule in PLY
我正在使用 PLY 来解析自定义定义文件的命令。命令每行定义一个,每个命令都应以保留关键字开头,后跟一些字符串。我已经成功地为语法编写了一个词法分析器和解析器,但是我在从生产中提出 SyntaxError
时遇到了问题。
根据 PLY's documentation,这可以简单地通过从解析器规则的主体中抛出 SyntaxError
来实现:
If necessary, a production rule can manually force the parser to enter error recovery. This is done by raising the SyntaxError exception like this:
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
""")
上面的例子 运行s 没有输出任何东西,这意味着它已经成功解析了文本,即使由于行 r c text text text
应该在 p_command
中引发语法错误(第二个标记 c
无效;只有 a
或 b
有效。
我做错了什么?
您有责任打印错误消息,但您没有:
One important aspect of manually setting an error is that the p_error()
function will NOT be called in this case. If you need to issue an error message, make sure you do it in the production that raises SyntaxError
.
我认为 p_error()
不应该加注 SyntaxError
。它应该只打印一条适当的消息(或以其他方式记录发生错误的事实)并让错误恢复继续进行。但是无论如何,在这种情况下它不会被调用,如上面的引用所示。
我也不是 100% 相信让词法分析器加注 SyntaxError
。对于词法错误,我的首选策略是将它们传递给解析器,从而将错误处理集中在一个地方。
如果您不关心错误恢复,请不要在任何规则中使用 error
标记。该令牌仅用于错误恢复。如果只是想一遇到错误就抛出异常,在p_error
里做,在不会自动调用的地方显式调用p_error
(比如token错误和检测到的错误)在语义动作中)。您可以抛出 ValueError
或从中派生的东西;我会远离 SyntaxError
,这对 Ply 和 Python 通常具有特殊意义。
我正在使用 PLY 来解析自定义定义文件的命令。命令每行定义一个,每个命令都应以保留关键字开头,后跟一些字符串。我已经成功地为语法编写了一个词法分析器和解析器,但是我在从生产中提出 SyntaxError
时遇到了问题。
根据 PLY's documentation,这可以简单地通过从解析器规则的主体中抛出 SyntaxError
来实现:
If necessary, a production rule can manually force the parser to enter error recovery. This is done by raising the SyntaxError exception like this:
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
""")
上面的例子 运行s 没有输出任何东西,这意味着它已经成功解析了文本,即使由于行 r c text text text
应该在 p_command
中引发语法错误(第二个标记 c
无效;只有 a
或 b
有效。
我做错了什么?
您有责任打印错误消息,但您没有:
One important aspect of manually setting an error is that the
p_error()
function will NOT be called in this case. If you need to issue an error message, make sure you do it in the production that raisesSyntaxError
.
我认为 p_error()
不应该加注 SyntaxError
。它应该只打印一条适当的消息(或以其他方式记录发生错误的事实)并让错误恢复继续进行。但是无论如何,在这种情况下它不会被调用,如上面的引用所示。
我也不是 100% 相信让词法分析器加注 SyntaxError
。对于词法错误,我的首选策略是将它们传递给解析器,从而将错误处理集中在一个地方。
如果您不关心错误恢复,请不要在任何规则中使用 error
标记。该令牌仅用于错误恢复。如果只是想一遇到错误就抛出异常,在p_error
里做,在不会自动调用的地方显式调用p_error
(比如token错误和检测到的错误)在语义动作中)。您可以抛出 ValueError
或从中派生的东西;我会远离 SyntaxError
,这对 Ply 和 Python 通常具有特殊意义。