检测开始&没有完整的C解析器的C声明的结尾

时间:2012-11-26 18:46:44

标签: c parsing

我想部分解析C声明和/或函数定义列表。

也就是说,我想将其拆分为子串,每个子串包含一个声明或函数定义。

然后将每个声明(单独)传递给另一个模块( 包含完整的C解析器,但我无法直接调用。)

显然我可以通过在我的程序中包含另一个完整的C解析器来实现这一点,但我希望避免这种情况。

到目前为止,我遇到的棘手案件涉及'}'是否终止声明/定义的问题。例如在

int main(int ac, char **av) {return 0;}

...... '}'是终结者,而在

typedef struct foo {int bar;} *pfoo;

不是。可能还有像这样的病态代码片段:

struct {int bar;} *getFooPtr(...) { /* code... */ }

备注

  • 请假设在我的函数看到之前C代码已经完全预处理。 (实际上它没有,但我们有一个解决方法。)
  • 我的解析器可能会在Lua中使用LPeg
  • 实现

3 个答案:

答案 0 :(得分:1)

据我所知,以下解决方案仅适用于声明(即,必须将函数定义保留在本节之外,或者在它们之后添加分号可能是一种解决方法:)< / p>

  1. 检查当前位置的字符
  2. 如果是;,我们已经找到了声明的结尾。
  3. 如果是"',请跳转到匹配的引号,必要时跳过转义序列。
  4. 如果是([{,请跳转到匹配的)]}(跳过嵌套的括号和必要时递归字符串)
  5. 否则,前进到下一个输入字符并转到步骤1.
  6. 如果这被证明是不能令人满意的,我将切换到 clang 解析器。

答案 1 :(得分:1)

要在处理函数定义的答案中扩展状态机,请添加以下步骤:

  1. 将fun / var state设置为'unknown'
  2. 检查当前位置的字符
  3. 如果它是;,我们找到了声明的结尾,而不是函数定义(尽管可能是函数声明)。
  4. 如果是"',请跳转到匹配的引号,必要时跳过转义序列。
  5. 如果是([{,请跳转到匹配的)]}(跳过嵌套的括号和必要时递归字符串)
  6. 如果fun / var state是'function'而我们刚刚跳过{ .. },我们已经找到了声明的结尾,以及它的函数定义
  7. 如果fun / var状态为“未知”且我们刚刚跳过( .. ),请将fun / var状态设置为“function”。
  8. 如果当前字符为=,,请将fun / var状态设置为'not-function`。
  9. 前进到下一个输入字符,然后返回2.
  10. 当然,这只适用于预处理后的代码 - 如果你的宏有各种奇怪的东西尚未扩展,那么所有的赌注都会关闭。

答案 2 :(得分:0)

您最好的选择是提取与声明相关的C语法部分,并为该语法或缩写版本构建解析器。同样,你想要函数体的语法,以类似的方式缩写,所以你可以跳过它们。

这可能会为声明生成一个相对值得信赖的解析器。

不幸的是,你不太可能得到一个值得信赖的C语法; ANSI标准中的那个不是编译器实际使用的那个。每个供应商都为其编译器添加了好东西和复杂功能(例如,MS C的de​​clspecs等)。

预处理器运行的假设很有意思。您将在哪里获得预处理器配置? (例如,编译器命令行定义,包括路径,编译指示设置等)?这比看起来更难,因为每个开发环境都定义了设置预处理器条件的不同方法。

如果您愿意接受偶然的错误,那么任何启发式算法都是有效的候选者, 以多少方式模拟重要客户端代码的错误。这也意味着您可以处理未经处理的代码,完全避免预处理器问题。