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