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++ パーサーではありません。これは、最後のステートメントを解析するためだけに作成された簡単なハックです。上記のすべての単体テストを実行できます。しかし、残念なことに、より長いスニペットでは、耐えられないほど遅くなりました。
質問は: より良いパーサーを作るには?