14

私は自分が設計している言語の基本的な骨組みを作ろうとしており、 Parsimoniousを使用して構文解析を実行しようとしています。現時点では、次の文法を宣言しています。

grammar = Grammar(
    """
    program = expr*
    expr    = _ "{" lvalue (rvalue / expr)* "}" _
    lvalue  = _ ~"[a-z0-9\\-]+" _
    rvalue  = _ ~".+" _
    _       = ~"[\\n\\s]*"
    """
)

次のような単純な入力文字列の結果の AST を出力しようとすると"{ do-something some-argument }":

print(grammar.parse("{ do-something some-argument }"))

倹約家はそれを完全に拒否することを決定し、次のやや不可解なエラーを表示します。

Traceback (most recent call last):
  File "tests.py", line 13, in <module>
    print(grammar.parse("{ do-something some-argument }"))
  File "/usr/local/lib/python2.7/dist-packages/parsimonious/grammar.py", line 112, in parse
    return self.default_rule.parse(text, pos=pos)
  File "/usr/local/lib/python2.7/dist-packages/parsimonious/expressions.py", line 109, in parse
    raise IncompleteParseError(text, node.end, self)
parsimonious.exceptions.IncompleteParseError: Rule 'program' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with '{ do-something some-' (line 1, column 1).

最初は、これは空白ルールに関連する問題かもしれないと思っていまし_たが、特定の場所で空白ルールを削除しようとして何度か失敗した後も、同じエラーが発生していました。

オンラインで検索してみましたが、関連性が低いと思われるのはこの質問だけで、何の役にも立ちませんでした。

文法に何か問題がありますか? 入力を正しい方法で解析していませんか? 誰かがこれに対する可能な解決策を持っているなら、それは大歓迎です。

4

1 に答える 1

6

私は倹約家の専門家とはかけ離れていますが、問題は~".+"入力文字列の残りの部分全体を貪欲に照合し、残りの部分と一致するものを何も残さないことだと思います。rvalue最初に、正規表現をに変更して、そのアイデアをテストしました。~"[a-z0-9\\-]+"これは、 の場合と同じですlvaluelvalueこれで解析し、(驚くほど) 2 つのまったく同じように定義されたトークンとをコンテキストで区別しますrvalue

from parsimonious.grammar import Grammar

grammar = Grammar(
    """
    program = expr*
    expr    = _ "{" lvalue (rvalue / expr)* "}" _
    lvalue  = _ ~"[a-z0-9\\-]+" _
    rvalue  = _ ~"[a-z0-9\\-]+" _
    _       = ~"[\\n\\s]*"
    """
)

print(grammar.parse( "{ do-something some-argument }"))

rvalue非空白文字の任意のシーケンスに一致することを意味する場合は、次のようなものが必要です。

rvalue = _ ~"[^\\s\\n]+" _

しかし、おっと!

{ foo bar }

"}"は右中括弧ですが、1 つ以上の非空白文字のシーケンスでもあります。"}"それとも?rvalue_ 文法によると、次のトークンはそれらのいずれかになります。これらの解釈の 1 つは解析可能で、もう 1 つは解析可能ではありません。構文解析の専門家が、あいまいさを解決するための正当な方法 (たとえば、そのような文法は、両方が構文解析する 2 つの可能な解釈を持つケースになる可能性がある) と見なすかどうか、またはそれを実装することがどれほど実用的かはわかりません。いずれにせよ、倹約家はその電話をかけません。

したがって、中かっこの問題で寄宿生を撃退する必要があります。この文法はあなたが望むことをすると思います:

from parsimonious.grammar import Grammar

grammar = Grammar(
    """
    program = expr*
    expr    = _ "{" lvalue (expr / rvalue)* "}" _
    lvalue  = _ ~"[a-z0-9\\-]+" _
    rvalue  = _ ~"[^{}\\n\\s]+" _
    _       = ~"[\\n\\s]*"
    """
)

print(grammar.match( "{ do-something some-argument 23423 {foo bar} &^%$ }"))

この文字列がどのようにトークン化されると予想されるので、開き中かっこも除外しました。

{foo bar{baz poo}}

私は期待するだろう

"{" "foo" "bar" "{" "baz" "poo" "}" "}"

... if"poo}"は としてトークン化することが期待され"poo" "}""{foo"はとしてトークン化することが期待されているため、 orとして"{" "foo"扱うことは直観に反します。bar{baz"bar{baz""bar{" "baz"

yacc に対する私の激しい憎しみが、私を yacc への執着へと駆り立てたことを今でも覚えています。

于 2015-10-29T20:01:53.980 に答える