0

次のようなテキストを解析するために、倹約家 (python PEG パーサー ライブラリ) を使用しています。

text = """
block block_name_0
{
    foo
}

block block_name_1
{
    bar
}

"""

これは、テキスト全体を構成する単純な本文要件 (英数字でなければならない) を持つ一連のブロックです。文法は次のとおりです。

grammar = Grammar(r"""
file = block+
block = _ "block" _ alphanum _ start_brace _ block_body _ end_brace _
block_body = alphanum+
alphanum = ~"[_A-z0-9]+"
_ = ~"[\\n\\s]*"
start_brace = "{"
end_brace = "}"
""")

print (grammar.parse(text)) 

私が抱えている問題は、最初のブロックの後のブロックに解析エラーがあると、役に立たないエラー メッセージが表示されることです。例として、次のテキストを考えてみましょう。

text = """
block block_name_0
{
    !foo
}

block block_name_1
{
    bar
}

"""

これにより、有用なエラー メッセージが表示されます。

[omitted stack trace]
  File "/lib/parsimonious/expressions.py", line 127, in match
    raise error
parsimonious.exceptions.ParseError: Rule 'block_body' didn't match at '!foo
}

ただし、次のテキストがある場合:

text = """
block block_name_0
{
    foo
}

block block_name_1
{
    !bar
}

"""

次のエラーが表示されます。

  File "/lib/parsimonious/expressions.py", line 112, in parse
    raise IncompleteParseError(text, node.end, self)
parsimonious.exceptions.IncompleteParseError: Rule 'file' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with 'block block_name_1
{' (line 7, column 1).

シーケンスの最初のインスタンス (最初のブロック) と一致するように見えますが、2 番目のブロックで失敗した場合、すべてを失敗とは見なしません。ブロック 0 と同様のエラーが表示されるようにして、ブロック全体を解析できなかっただけでなく、ブロックの何が問題だったのかを正確に知ることができるようにします。

どんな助けでも大歓迎です!

4

1 に答える 1

0

節約のための答えではありませんが、優れたエラー報告サポートのために、textXまたはその基礎となる PEG パーサーArpeggioを直接試すことをお勧めします(免責事項: 私はこれらのライブラリの作成者です)。

textX の使用:

from textx.metamodel import metamodel_from_str

grammar = """
Program: blocks+=Block ;

Block:
 'block' name=ID '{'
     body=Body
 '}'
;

Body: ID+ ;
"""

text = """
block block_name_0
{
    foo
}

block block_name_1
{
    !bar
}

"""

mm = metamodel_from_str(grammar)
program = mm.model_from_str(text)

textX/Arpeggio は可能な限り解析し、エラーの正確な場所を特定します。

textx.exceptions.TextXSyntaxError:
   Expected ID at position (9, 5) => 'e_1 {     *!bar }  '.

textX を使用すると、無料で AST も取得できるため、たとえば次のことができます。

for block in program.blocks:
    print(block.name, ':', block.body)

また、デバッグ/調査の目的で、文法とモデルの優れた視覚化もあります。

于 2016-11-29T10:59:08.457 に答える