文法


10

缶誰かが私に制作しようとバックトラックと理由を再帰下降構文解析啓発S A(この順番では)文法によって形成された言語認識していないS A S Aを| ASaSaSaaSaSa | aa

言語からの単語を解析するだけのようです{a2n | n1}

たとえば、このABNFパーサージェネレーターをプロダクションルールとともに使用してそのようなパーサーを生成しましたがS = "a" S "a" / "aa"、パーサーはを認識しませんaaaaaa

パースツリーの左端からのノードの連結が7で始まるまでは、プロダクションを使用し、その後、ツリーが見えるまでプロダクションS a aを選択して、パースツリーを上に移動することを期待します。このような:SaSaaSaa

   S 
 / | \
a  S  a
 / | \
a  S  a
  / \
 a   a

2
なぜこの単語を解析できないと思いますか?
Yuval Filmus 14年

@ユヴァル、それはそれを解析するべきだと思うので、何かが欠けているに違いない。
メリボルド2014年

ああ、今の質問はもっと理にかなっています。編集ありがとうございます!あなたが書いたことが真実なら(私はチェックしませんでした)、ジェネレーターにバグがあるようです。(または、それはあなたの文法のために指定されていない。私は、文法は基本的かつ明確であるので、これはそうだと思う。
ラファエル

@Raphael、私はもう一度質問を編集しました(できれば意味を変えずに)。実際、そのようなパーサーが単語を認識しない理由を説明する必要がありaaaaaaます。
メリボルド2014年

その木はどこで手に入れたのですか。私はそのABNFパーサージェネレーターから多くを得ることができません。あなたが与える木はあまり意味がありません。しかし、文字列aaaaaaは解析する必要があり、解析しません。しかしaaaa解析はします。あなたは明らかに2の累乗について正しいです。でのみ解析さaaS = "aa" / "a" [S] "a"ます。パーサーの機能を追跡できますか?
babou 2014年

回答:


6

これは答えの多くではありませんが、解析ツリーは通常のコメントに適合しません。

SaSa | aaaaaaaa

ただし、解析ツリーの形式は次のとおりです。

      S 
     /|\
    / S \
   / /|\ \
  / / S \ \
 / / / \ \ \
a a a   a a a

または、このプレゼンテーションを希望する場合は、端末を別の回線に置きます

     S 
   / | \
  a  S  a
   / | \
  a  S  a
    / \
   a   a

ABNFパーサージェネレーターが機能していないように見えることを確認しましたが、その機能を追跡する方法がわかりません。

{a2n | n1}

バギーパーサーの周りにこのような手の込んだサイトがあることは少し驚くべきことです。バグのあるパーサーは、まったく興味のない解析手法をさらに使用しています。


それをさらに調べた後:

問題の原因が1つ見つかったと思います。角括弧はオプションを意味し ます

だからあなたの文法は、いずれかの記述する必要があります S = "a" S "a" / "aa"S = "a" [S] "a"。その後、正しく動作するようです。

しかし、異なる形式で同じルールを2倍にすると、システムは明らかに失われます。理由はわかりません。

文法を指定するためのこれらの構文上の問題を説明するページは見つかりませんでした。

私はまだそのバギーを考慮します。


1
痛い。うん。その解析ツリーを書いたときに何を考えていたのかわかりません。私の質問を編集して、あなたの質問を貼り付けます。
メリボルド2014年

私はオンラインデモでパーサジェネレータをバックトラック、別の再帰下降を見つけたここに、それは、このルールで同じ動作を示していますS ::= 'a'<S>'a' | 'a''a'
meribold

それはまだ解析しませんaaaaaa使用している場合S = "a" S "a" / "aa"がありますが、かっこについて右であるように見えます。
meribold 2014年

再帰的下降、バックトラックパーサーを探索するポイントはわかりません。
バブー2014年

あなたは正しいですS = "a" S "a" / "aa"...私はテストが速すぎて、解析の代わりに生成をクリックしました。
バブー2014年

3

s1()SaSatrues()s2()Saa

単語をaaaaaaもう一度解析することを検討してください。ある時点で、解析ツリーは次のようになります。

   S 
 / | \
a  S  a
 / | \
a  S  a    <--
 / | \
a  S  a
  / \
 a   a

s()trueSSaa

   S 
 / | \
a  S  a
  / \
 a   a

私はこれを私の実装の問題と考える傾向がありますが、一般的には、再帰的降下パーサーのバックトラックではありません。

#include <iostream>

char* next;    
bool term(char token) {
    if (*next != '\0')
        return *next++ == token;
    else
        return false;
}

bool s();    
bool s1() {
    return term('a') && s() && term('a');
}    
bool s2() {
    return term('a') && term('a');
}    
bool s() {
    auto save = next;
    return s1() or (next = save, s2());
}    

int main(int argc, char* argv[]) {
    next = "aaaaaa";
    if (s() && *next == '\0') {
        std::cout << "match";
    }
    else
        std::cout << "no match";
}

2

バグではなく機能です

バックトラッキングが発生するタイミングと場所を詳しく確認します。

     1.           2.          3.          4.          5.          6.          7.          8.          9.          10.         11.         12.

     S            S           S           S           S           S           S           S           S           S           S           S      
   / | \        / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
  a  S  a      a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
               a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                            / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
                           a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                                        / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
                                       a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                    / | \       / | \       / | \       / | \       / | \       /   \
                                                   a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                                / | \       / | \       / | \       /   \   
                                                               a  S  a     a  S  a     a  S  a     a     a
                                                                            / | \       /   \
                                                                           a  S  a     a     a



w[] = 'aaaaaa'  //input
l[] = ''        //current tree leafs


 1. tree:   The parser starts with the start symbol S and tries first alternative S->aSa:       Result: w[0]  = l[0]     w = aaaaaa    l = aSa
 |          -- S->aSa works                                                                         | |     | | 
 6. tree:   The parser matches a after a:                                                       Result: w[6]  = l[6]     w = aaaaaa    l = aaaaaaSaaaaaa
 7. tree:   The parser tries S->aSa again but there is no match!                                Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaSaaaaaaa 
 8. tree:   The parser tries S->aa but there is still no match!                                 Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaaaa
 9. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaa
10. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaa
11. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaa
12. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaa

ここでの重要なポイントは、最後に一致する文字が見つかった位置の後にパーサーが戻ることです。 そのため、l [7]でS-> aaを使用して、l = aaaaaaaaのツリー11からl = aaaaの 12番目のツリーに「ジャンプ」します。


ようやく編集する時間ができました!;)
Sebbas 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.