我有一个项目(SCC),它有点像 C++ 的 REPL。在布什提示我可以做
scc '2+2'
或者更复杂一点:
scc 'double x = 0.5; sin(x)'
这相当于:
scc 'double x = 0.5; cout << sin(x) << endl;'
如果最后一个(也是唯一可能的)语句表达式没有以分号终止,则将其发送到std::cout
. 我的问题是关于从 C++ 代码片段中解析出最后一条语句。我很清楚 C++ 解析有多么困难。用简单的 sed 脚本通过查找 last 来解析 last 语句';'
最初对我来说已经足够了。但是现在项目比小型个人项目大,我需要一个更好的解析器。
下面是我当前 SED 解析器的迷你单元测试。您可以看到我用来进行解析的 SED 正则表达式:
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
-line之后的第一行cat
是空行。第二行是一个空格线。3rd - 不以 - 结尾的语句';'
应该被打印出来。第 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++ 解析器。这只是为了一件事而做的快速破解:解析最后一条语句。它能够完成上述所有单元测试。但不幸的是,对于较长的片段,它的速度非常慢。
问题是:如何制作更好的解析器?