标签解析C++

大家好,我叫Thierry Miceli,是Visual C++编译器前端开发人员。虽然我们的团队以编写和维护C++编译器的一部分而闻名,它分析了源代码并从中建立了一个内部表示,但是我们在过去几年中的大量努力已经被定向到服务IDE和改善智能感知体验(刷新)。 在这里 , 在这里 ,和 在这里 ).

null

今天 ,我 我将要编写一个新的解析器,专门用来创建从C++源代码中提取信息的快速和可伸缩的方法。这个解析器是我们对VisualStudio2010的新添加之一,我们称之为“标记解析器”。

标记解析器在VisualStudio2010中用于填充取代NCB文件的SQL数据库。VC++的所有浏览特性都在某种程度上依赖于标记解析器提供的结果。其中包括类视图、调用层次结构、转到定义/声明、获取所有引用、快速搜索、导航栏和VCCodeModel。

模糊分析器

它是一个模糊解析器,这意味着,它不是试图严格地识别和验证完整的C++语法(我们有一个优秀的编译器前端来完成),它懒惰地匹配令牌的输入流和一些模式。此解析器在解析期间不填充符号表,除了内置的类型之外,它没有类型的概念,它不构建完整的宏上下文,其转换单元是单个文件(即,它不遵循贯穿的#include指令)。但是,解析器能够处理所有的C++、C++、CLI和IDL。

对不完整代码和错误的高容忍度 .

标记解析器不会试图理解源代码中的每个符号或标识符。它将满足于能够识别声明的不同部分及其在源文件中的位置。如果声明的类型规范中的名称不能由C++编译器解决,这将无法防止标签分析器识别声明,并且它将在类视图中显示。

标记解析器在某种程度上类似于源代码的人类读者,他们只查看一个唯一的声明,而不了解项目的其他部分。他可能不知道大多数标识符实际上代表什么,但他可以高度自信地说出声明是什么,并找到其子部分。

除了对“语义”错误代码的容忍(这是模糊解析器的一个特性)之外,标记解析器还具有基于启发式的错误恢复功能,用于在编辑过程中最常见的错误代码原因。例如,它将尝试检测不完整的声明或未关闭的函数体定义。

处理预处理器条件指令 .

标记解析器的主要作用是从源代码中提取信息,然后由IDE浏览特性使用这些信息。因为浏览特性与编辑体验密切相关,所以标记解析器生成编辑器中显示的完整源代码的结构化表示,而不是在特定项目配置下编译的代码的表示,更有用。

标记解析器以一种特殊的方式处理预处理器条件指令(#if,#ifdef,#ifndef,#else,#elif,#endif)。它在预处理器条件指令的每个分支中包含完整的代码,但仍然只解析完整的声明。例如,非活动分支和活动分支都会被解析,类视图会显示这两个函数声明。

标记解析器还能够处理声明被一个或多个预处理器条件指令中断的更复杂的情况。例如,可以由两个分支诱导的两个声明都被解析和报告。

更快、可扩展

标记解析可以扩展,因为它是增量的—在头文件更改后,它不需要重新解析数百(或数千)个编译单元,这在实际构建中是经常发生的。 它也比一个完整的编译器快(尽管它是启发式的),因为它没有宏扩展和完整的语义解析的负担。 因此,即使是最大的项目,它也非常适合捕捉实时信息。

没有内置的语义解析

由于标记解析器严格按照每个文件进行操作,因此某些语义解析将留给其客户机。例如,由于函数声明和定义通常出现在单独的文件中,因此标记解析器单独报告函数声明及其定义,而不包含任何绑定信息。因此,类视图必须匹配函数声明及其定义,以便它们在类视图树中显示为单个条目。

标记解析器是轻量级的,并且它对解析器结果的使用者负有一定的责任。这里的好处是,客户机只需承担构建所需语义知识的成本,现在就可以使用SQL挖掘数据了。

提示文件

我们试图使标记解析器尽可能独立。它不需要知道任何类型的项目配置(包括路径、编译器开关等)。在许多情况下,可以使用源文件名作为其唯一参数来调用标记解析器,它在提取有关该文件中代码的详细信息方面做得非常出色。唯一的警告是预处理宏,它干扰C++语法,严重地使模糊分析和错误恢复试探无法从代码中理解。这种宏的一个例子是STDMETHOD,当扩展它时,它将从以下内容生成成员函数签名:

标准方法(OnDocWindowActivate)(BOOL fActivate)

如果您不知道STDMETHOD是什么,您将很难猜出上面这行的含义。由于标记解析器不遵循#include指令,也不在符号数据库*中执行SQL查找,因此它无法自行发现宏定义。然而,它的宏状态可以预先配置为我们所说的“提示文件”。提示文件只包含宏分析器的定义,这些标记在标记宏语法的基础上,正确地识别源代码,从而在根本上干扰C++语法。

如果您安装了Beta1,您将在visualstudio2010安装目录的vcvcpackages下找到一个“cpp.hint”文件,这是VC和SDK库头的提示文件。通常情况下,标记解析器只处理这个预设的提示文件就可以了。然而,如果你的代码 您使用的第三方库代码包含篡改C++语法的宏,可能需要设置自己的提示文件。IDE将在源文件所在的目录和所有父目录中查找名为“cpp.hint”的文件,直到找到名为“cpp.stop”的文件为止。在实际解析文件之前,所有找到的提示文件都将被预处理以构建宏上下文。我现在不会详细介绍提示文件,但可以随时提问,顺便说一句,它们将在MSDN上完整地记录下来。

如果这个机器看起来很复杂,不要太担心,大多数时候你不必定义自己的提示文件,或者只需要在项目或解决方案目录中放置一个包含一些宏定义的“cpp.hint”文件。

在未来,我们计划开发一些工具,帮助您确定需要提示文件的位置,并可能为您生成它们。我们还将致力于使标记解析器在存在宏的情况下更加智能,从而减少需要添加到提示文件中的提示。

* 理论上,当需要额外的信息来识别或消除声明的歧义时,标记解析器可以查询数据库中的宏定义,但符号查找的可靠实现(即使它只针对宏)会将标记解析器推向轻量级、独立的相反方向,增量和独立于项目配置。

这篇文章于2013年3月25日更新,以删除丢失图像的断开链接,以及博客文章中对这些图像的引用。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享