"simple" C++ 解析器

"simple" parser for c++

本文关键字:C++ simple      更新时间:2023-10-16

我有一个项目(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脚本解析最后一条语句,只需查找最后一个';',对我来说一开始就足够了。但现在这个项目比个人的小项目更大,我需要一个更好的解析器。

下面是我当前SED解析器的小型单元测试。您可以看到我用来进行解析的SED正则表达式:

    cat  <<EOF  | sed    's/$//;s/[ t]*$//;s/(.*[;}])*([^;}]+$)/    ==>>  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/expressive编写一个解析器http://github.com/lvv/scc/blob/master/sccpp.h。当然不是真的C++解析器。这只是一个快速破解,只为一件事:解析出最后一条语句。是的能够完成以上所有单元测试。但不幸的是,对于较长的片段来说慢得令人无法忍受。

问题是:如何制作一个更好的解析器?

正确的方法可能是使用真正的解析器(来自有点像CLANG),但我有点担心复杂性

过高。简单的事实是,C++就像HTML一样——你需要一个真正的库来完成它,所以除非你想花数年时间开发自己的库,否则几乎唯一的方法就是使用现有的C++解析器。Clang是这方面的唯一选择。因此,无论你觉得它多么复杂,你都别无选择。