我有一个项目(SCC),有点像REPL for C ++。在丛林提示我可以做
scc '2+2'
或者稍微复杂一点:
scc 'double x = 0.5; sin(x)'
相当于:
scc 'double x = 0.5; cout << sin(x) << endl;'
如果last-only(仅可能)语句表达式未以分号结束,则会将其发送到std::cout
。
我的问题是从C ++代码片段中解析出最后一个语句。
我很清楚C ++解析是多么困难。只需查找最后';'
,用简单的sed脚本解析最后一个语句最初对我来说已经足够了。
但现在项目比小型个人项目更大,我需要一个更好的解析器。
下面是我当前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
cat
之后的第一行 - 换行为空行。第二行是一个空行。
第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 ++ 解析器。这只是一个快速的黑客只做一件事:解析最后的声明。它是 能够进行以上所有单元测试。但不幸的是,对于更长的片段而言 无法忍受的慢。
问题是:如何制作更好的解析器?
答案 0 :(得分:1)
正确的方法可能是使用真正的解析器(来自 像CLANG这样的东西)但我有点担心复杂性 这项努力
不太高。简单的事实是C ++就像HTML一样 - 你需要一个真正的库才能做到这一点,所以除非你想花费数年时间开发自己的,否则几乎唯一的方法就是使用现有的C ++解析器。 Clang是这方面唯一的选择。无论你找到它多么复杂,你别无选择。