【问题标题】:Parsing a C++ source file after preprocessing预处理后解析 C++ 源文件
【发布时间】:2011-05-03 03:59:56
【问题描述】:

我正在尝试使用我的定制解析器(以c++ 编写)分析c++ 文件。在开始解析之前,我想摆脱所有#define。我希望源文件在预处理后可以编译。所以最好的方法是在文件上运行C Preprocessor

cpp myfile.cpp temp.cpp
// or
g++ -E myfile.cpp > templ.cpp

[欢迎提出新建议。]

但是由于这个原因,原始行及其行号将丢失,因为文件还将包含所有标题信息,我想保留行号。所以我决定的出路是,

  1. 在前面添加一个特殊符号 源文件中的每一行(预处理器除外)
  2. 运行预处理器
  3. 提取带有特殊字符的行 符号并分析它们

例如,典型的源文件如下所示:

#include<iostream>
#include"xyz.h"
int x;    
#define SOME value
/*
**  This is a test file
*/
typedef char* cp;

void myFunc (int* i, ABC<int, X<double> > o)
{
  //...
}

class B {
};

添加符号后会是这样,

#include<iostream>
#include"xyz.h"
@3@int x;    
#define SOME value
@5@/*
@6@**  This is a test file
@7@*/
@8@typedef char* cp;
@9@
@10@void myFunc (int* i, ABC<int, X<double> > o)
@11@{
@12@  //...
@13@}
@14@
@15@class B {
@16@};

一旦所有的宏和 cmets 被删除,我将留下数千行,其中几百行将是原始源代码。

这种方法正确吗?我错过了任何角落案例吗?

【问题讨论】:

  • 你想完成什么?
  • @Michael,我想从源文件中删除宏(即#define),然后再开始使用解析器分析它们。
  • 我也不知道你的最终目标是什么。出于学术目的,您可能想看看 Clang 前端 (clang.llvm.org),它采用模块化设计,您可以将其集成到其他应用程序/工具中。
  • @Julio,不用于学术目的。解析完成后,我将以某种方式修改源代码。但是,解释所有内容将是太多了。我希望至少我的问题是解释性的。如果我遗漏了什么,请告诉我。
  • @iammilind:除非这是出于学术目的,否则我认为尝试编写自己的 C++ 前端有点疯狂。大量的东西,比如模板实例化和依赖于参数的查找,要正确实现可能非常复杂,并且至少有两个优秀且免费可用的 C++ 前端可供您使用(g++ 和 LLVM 的clang),每个其中有 数百万 小时的开发时间,并且仍然经常包含严重的错误。

标签: c++ c parsing


【解决方案1】:

您意识到 g++ -E 在其输出中添加了一些自己的行,这些行表示原始文件中的行号?你会发现像

这样的行
# 2 "foo.cc" 2

这表明您正在查看文件 foo.cc 的第 2 行。只要常规的行序列被打乱,就会插入这些行。

【讨论】:

  • 我猜这些行只是为标题添加的。对于一般代码,它不是。
  • @iammilind:不,它们是在每次文件更改后添加的。你可以从中推断出实际的行号。
  • @Mat,但是我可以提取原始文件源代码吗?如果我已经预处理了“x.cpp”,那么我只对分析“x.cpp”源感兴趣。通常,它们与许多其他 namespacesfunction declarations 杂乱无章,我对此不感兴趣。
  • @iammilind:在每个 # n "foo.cpp" x 之后,您知道以下几行(直到下一个 # q "file.x" y)来自 foo.cpp 第 n 行及以下。所以是的,你一直都知道自己在哪里。
  • @Mat,你是对的。这将为我节省很多工作。唯一的事情是我必须使用数字nx 继续跟踪"foo.cpp"。大多数情况下,这出现在预处理文件的开头和结尾。从来没有正确地注意到它。
【解决方案2】:

过去与 X11 源一起提供的 imake 程序使用了一个略微相似的系统,用 @@ 标记行尾,以便它可以正确地对它们进行后处理。

gcc -E 的输出通常包含#line 指令;您也许可以使用这些来代替您的符号。

【讨论】:

  • 有趣。但我不喜欢使用#,因为它也在其他地方使用。问题中提到的当前方法是否正确?
  • @iammilind:GCC 的输出将包括#line 指令,可能是Ernest 提到的没有关键字line 的缩写形式。您可以使用@99@ 标记行的开头。我引用了一个使用@@的历史先例;诚然,这是在行尾而不是开头,但@ 符号是更好的选择之一(可见,C 不使用其他方式)。
猜你喜欢
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2010-09-22
  • 1970-01-01
相关资源
最近更新 更多