我工作的公司 Semantic Designs Inc. 提供的工具包含用于分析和转换程序的通用基础架构以及用于各种编程语言的特定分析组件。这些统称为 DMS。对于 C++,DMS 包括针对 GCC3、GCC4、ISO14882c1998 (ANSI)、Visual C++ 6.0 和非托管 Visual Studio 2005 C++ 中的每一个的集成词法分析器、预处理器、解析器以及名称和类型解析组件。对于 C 的各种方言,还存在控制流分析、副作用分析器和符号依赖性分析器,其中已实现指针检查器、非活动代码删除器、函数分析器和程序切片器等工具。
名称和类型解析组件提供了完整的符号表信息和查找功能,因此对标识符的引用可以很容易地与其类型和其他声明性信息相关联。该信息类似于编译器捕获和使用的信息,但与抽象语法树一起以适合任何包含该组件的工具自适应重用的形式保留。
Semantic Designs 最近构建了一个自定义工具,该工具专门与循环声明中的索引变量类型相关,例如在您的示例中。在这种情况下,问题是升级使用 -fno-for-scope 编译器开关的 GCC2 代码,该开关为后来的 GCC 方言中不支持的循环变量提供了范围解析规则。该工具必须转换循环,将循环变量的声明移动到保留 -fno-for-scope 范围规则的外部上下文中。如果不需要进行此类更改,则不进行更改。
因此,该工具必须识别与循环变量的每个引用关联的类型,在屏蔽范围的情况下进行区分,并重新构建代码,以便 GCC3 和 GCC4 名称解析将产生与带有 -fno 的 GCC2 相同的语义解释- 范围。这需要能够访问与每个变量引用关联的符号表信息,并且在代码被移动的情况下,为声明被移动的任何变量重建类型声明的正确语法。DMS C++ 名称和类型解析组件提供的符号表和标识符引用表包含所有必需的信息,以及用于重构规定类型语法的模块,允许合成正确的新类型声明。
例如,考虑以下示例:
// loop variable hides variable in global scope
// will change meaning without -fno-for-scope
// fix: move decl. of cnt before for-loop
// optionally rename globcnt loop variable
float globcnt = 0.0;
int Foo::foo3() {
for (int globcnt = 0; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
GCC2 -fno-for-scope 语义表明循环外对 globcnt 的引用是对循环变量的引用,即使 GCC3 会认为循环变量超出范围并解析对全局变量的引用。该工具将此代码转换为:
float globcnt = 0.0;
int Foo::foo3() {
int globcnt = 0;
for (; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
如果代码没有被转换,GCC4 总是会从 Foo:foo3 返回值 1。但是,转换后的值会受到最初为 GCC2 设计的循环迭代的影响。该工具必须认识到对 globcnt 的最终引用是对 int 类型的局部变量,而不是对 float 类型的全局变量,它可以通过符号表查找来完成,并采取相应的行动。
另一方面,该工具在以下代码中识别出循环外没有对 i 的引用,因此可以接受(并且首选)保持循环变量声明不变。
int Foo::foo0() {
for (int i = 0; i < 10; i++) {
globalInt += i*i;
}
return 0;
}