3

そこで、PLY を使用してパーサーを実装しましたが、PLY のすべてのドキュメントでは、エラー メッセージを出力することで解析エラーとトークン化エラーを扱っています。致命的でないエラー報告を実装する最善の方法は、API レベルで、パーサーの呼び出し元に対してどのようなものか疑問に思っています。明らかに、「致命的ではない」制限は、例外が出ていることを意味します — そしてwarnings、解析エラーのためにモジュールを悪用しているように感じます. 提案?

4

2 に答える 2

2

PLY には t_error() 関数があり、パーサーでオーバーライドして、必要なことを行うことができます。ドキュメントで提供されている例では、エラー メッセージが出力され、問題のある文字がスキップされます。ただし、発生した解析エラーのリストを簡単に更新したり、X 回の失敗後に停止するしきい値を設定したりすることもできます。 - http://www .dabeaz.com/ply/ply.html

4.9 エラー処理

最後に、t_error() 関数を使用して、不正な文字が検出されたときに発生する字句解析エラーを処理します。この場合、t.value 属性には、トークン化されていない残りの入力文字列が含まれます。この例では、エラー関数は次のように定義されています。

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

これを利用するには、パーサーをクラスにして、その中にエラー状態を保存します。複数の MyLexer インスタンスを作成し、それらを build() してから、複数のレクサーが必要な場合は解析に使用する必要があるため、これは非常に大雑把な例です。同時に実行しています。

エラー ストレージを__hash__レクサー インスタンス自体の と結合して、ビルドを 1 回だけ行うことができます。1 つのクラス内で複数のレクサー インスタンスを実行することの詳細についてはよくわかりませんが、これは、致命的でないエラーをキャプチャして報告する方法の大まかな例を示すためのものです。

この目的のために、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'"]
于 2013-08-04T22:44:03.570 に答える