报告从PLY到解析器调用者的解析错误

时间:2013-08-04 19:10:21

标签: python ply

所以我使用PLY实现了一个解析器 - 但所有PLY文档都通过打印错误消息来处理解析和标记化错误。我想知道在API级别实现非致命错误报告的最佳方法是解析器的调用者。显然,“非致命”限制意味着异常已经完成 - 而且我觉得我会误解warnings模块的解析错误。建议?

2 个答案:

答案 0 :(得分:2)

PLY有一个t_error()函数,您可以在解析器中覆盖该函数以执行任何操作。文档中提供的示例打印出错误消息并跳过有问题的字符 - 但您可以轻松更新遇到的解析失败列表,在X次失败后停止阈值等等 - http://www.dabeaz.com/ply/ply.html

  

4.9错误处理

     

最后,t_error()函数用于处理lexing错误   检测到非法字符时发生。在这种情况下,t.value   attribute包含尚未输入的其余输入字符串   符号化。在该示例中,错误函数定义如下:

# Error handling rule
def t_error(t):
    print "Illegal character '%s'" % t.value[0]
    t.lexer.skip(1)

你可以通过使你的解析器成为一个类并在其中存储错误状态来利用它 - 这是一个非常粗糙的例子,因为你必须创建多个MyLexer实例,然后构建()它们,然后利用它们进行解析,如果你希望同时运行多个词法分析器。

您可以将错误存储结合到词法分析器实例本身的__hash__,只需构建一次。我对在一个类中运行多个词法分析器实例的细节感到茫然,但实际上这只是为了给出一个如何捕获和报告非致命错误的粗略示例。

为此,我从Ply的文档中修改了简单的计算器类示例。

#!/usr/bin/python

import ply.lex as lex

class MyLexer:

    errors = []

    # List of token names.   This is always required
    tokens = (
       'NUMBER',
       'PLUS',
       'MINUS',
       'TIMES',
       'DIVIDE',
       'LPAREN',
       'RPAREN',
    )

    # Regular expression rules for simple tokens
    t_PLUS    = r'\+'
    t_MINUS   = r'-'
    t_TIMES   = r'\*'
    t_DIVIDE  = r'/'
    t_LPAREN  = r'\('
    t_RPAREN  = r'\)'

    # A regular expression rule with some action code
    # Note addition of self parameter since we're in a class
    def t_NUMBER(self,t):
        r'\d+'
        t.value = int(t.value)
        return t

    # Define a rule so we can track line numbers
    def t_newline(self,t):
        r'\n+'
        t.lexer.lineno += len(t.value)

    # A string containing ignored characters (spaces and tabs)
    t_ignore  = ' \t'

    # Error handling rule
    def t_error(self,t):
        self.errors.append("Illegal character '%s'" % t.value[0])
        t.lexer.skip(1)

    # Build the lexer
    def build(self,**kwargs):
        self.errors = []
        self.lexer = lex.lex(module=self, **kwargs)

    # Test it output
    def test(self,data):
        self.errors = []
        self.lexer.input(data)
        while True:
             tok = self.lexer.token()
             if not tok: break
             print tok

    def report(self):
        return self.errors

用法:

# Build the lexer and try it out
m = MyLexer()
m.build()           # Build the lexer
m.test("3 + 4 + 5")     # Test it
print m.report()
m.test("3 + A + B")
print m.report()

输出:

LexToken(NUMBER,3,1,0)
LexToken(PLUS,'+',1,2)
LexToken(NUMBER,4,1,4)
LexToken(PLUS,'+',1,6)
LexToken(NUMBER,5,1,8)
[]
LexToken(NUMBER,3,1,0)
LexToken(PLUS,'+',1,2)
LexToken(PLUS,'+',1,6)
["Illegal character 'A'", "Illegal character 'B'"]

答案 1 :(得分:0)

结帐section 9.2

“9.2运行时调试

要启用解析器的运行时调试,请使用debug选项进行解析。此选项可以是整数(只是打开或关闭调试)或记录器对象的实例。例如:

log = logging.getLogger()
parser.parse(input,debug=log)

如果传递了日志记录对象,则可以使用其过滤级别来控制生成的输出量。 INFO级别用于生成有关规则缩减的信息。 DEBUG级别将显示有关解析堆栈,令牌转换和其他详细信息的信息。 ERROR级别显示与解析错误相关的信息。“

标准库的logging module是在开发大小项目期间处理和过滤日志信息的“规范”方式。