1

C++ の REPL のようなプロジェクト (SCC) があります。ブッシュプロンプトでできること

scc '2+2'

またはもう少し複雑:

scc  'double x = 0.5;  sin(x)'

これは次と同等です:

scc  'double x = 0.5;  cout << sin(x) << endl;'

最後の (可能な限り) statement-expression がセミコロンで終了していない場合、それは に送信されstd::coutます。私の質問は、C++ コード スニペットから最後のステートメントを解析することです。C++ の構文解析がいかに難しいかはよくわかっています。最後を探すだけで単純な sed スクリプトを使用して最後のステートメントを解析すること';'は、最初は十分でした。しかし、現在、プロジェクトは小さな個人プロジェクトよりも大きく、より優れたパーサーが必要です。

以下は、現在の SED パーサーのミニ ユニット テストです。解析に使用する SED regex を確認できます。

    cat  <<EOF  | sed    's/$//;s/[ \t]*$//;s/\(.*[;}]\)*\([^;}]\+$\)/\0    ==>>  \1   PRINT(\2);/'


    print
    no-print;
    OK;  print
    OK;  no-print;
    OK;  no-print;  print
    FAIL;   while(a){b;}  no-print
    FAIL;   while(a)  no-print
    OK;     for(a;b;c) {no-print}
    FAIL;   for(a;b;c) no-print
    OK;     {}
    OK;     {no-print-code-block;}
    FAIL;  print_rvalue_t{1}
    FAIL;   f(int{1})
    FAIL;   f(";")
    FAIL;   f(';')
    FAIL;   f("}")
    EOF

cat-lineの後の最初の行は空行です。2 行目はスペース行 1 行です。3 番目 - で終わらないステートメント';'- を出力する必要があります。4 番目 - 2 ステートメントのスニペット。等々。-がある場合FAIL、パーサーはこの行で失敗します。出力は次のようになります。

    print   ==>>     PRINT(print);
    no-print;
    OK;  print      ==>>  OK;   PRINT(  print);
    OK;  no-print;
    OK;  no-print;  print   ==>>  OK;  no-print;   PRINT(  print);
    FAIL;     while(a){b;}  print     ==>>  OK;       while(a){b;}   PRINT(  no-print);
    FAIL;   while(a)  no-print      ==>>  FAIL;   PRINT(    while(a)  no-print);
    OK;     for(a;b;c) {no-print}
    FAIL;   for(a;b;c) no-print     ==>>  FAIL;     for(a;b;   PRINT(c) no-print);
    OK;     {}
    OK;     {no-print-code-block;}
    FAIL;  print_rvalue_t{1}
    FAIL;   f(int{1})       ==>>  FAIL;     f(int{1}   PRINT());
    FAIL;   f(";")  ==>>  FAIL;     f(";   PRINT("));
    FAIL;   f(';')  ==>>  FAIL;     f(';   PRINT('));
    FAIL;   f("}")  ==>>  FAIL;     f("}   PRINT("));

マーカーのない==>>行は、変更なしでパーサーを通過する行です。マーカーがスニペットに変換された後、最後のステートメントが でラップされPRINT( )ます。ご覧のとおり、現在の SED パーサーはあまり良くありません。

だからもっと良いものを探しています。解析時に100%正しくなくても回答を受け付けます。さらに優れた SED スクリプトで十分です。それを行う正しい方法は、おそらく実際のパーサー (CLANG のようなものから) を使用することですが、私はこの努力の複雑さを少し心配しています。

boost/xpressive でパーサーを作成しようとしました - http://github.com/lvv/scc/blob/master/sccpp.h。原因は、実際の C++ パーサーではありません。これは、最後のステートメントを解析するためだけに作成された簡単なハックです。上記のすべての単体テストを実行できます。しかし、残念なことに、より長いスニペットでは、耐えられないほど遅くなりました。

質問は: より良いパーサーを作るには?

4

1 に答える 1

1

それを行う正しい方法は、おそらく本物のパーサー(CLANGのようなものから)を使用することですが、私はこの努力の複雑さを少し心配しています

高すぎない。単純な事実として、C++ は HTML のようなものです。これを行うには実際のライブラリが必要です。そのため、独自の開発に何年も費やしたくない場合は、既存の C++ パーサーを使用するしかありません。これに関しては、Clang が唯一の選択肢です。したがって、どのように複雑であっても、他に選択肢はありません。

于 2012-09-13T10:41:41.110 に答える