出于好奇,我想知道有关解析C ++的“理论”结果。
假设我的项目大小为n(以LOC为例,但由于我们将处理大O,因此这不是非常重要)
- C ++的解析复杂度是否为O(n)?如果不是,那么它的复杂度是什么?
- C(或Java或任何语法上更简单的语言)是否以O(n)解析?
- C ++ 1x会引入新功能,使得解析更加困难吗?
非常感谢提供参考资料!
出于好奇,我想知道有关解析C ++的“理论”结果。
假设我的项目大小为n(以LOC为例,但由于我们将处理大O,因此这不是非常重要)
非常感谢提供参考资料!
我认为,“解析”这个术语在不同的人群中被用于不同的问题,因此有不同的解释。
从狭义的技术角度来看,解析仅是验证源代码是否符合语法(或者甚至是构建一棵树)。
有一个相当普遍的流言说你无法解析C ++(以这种方式),因为你必须解决某些符号的含义才能解析。这个流言是完全错误的。
它源于使用“弱”(LALR或回溯递归下降)解析器,如果它们在本地模糊的部分文本的若干可能的子解析中做出了错误的选择(这个SO线程讨论了一个例子),则由于偶尔做出这种选择而完全失败。使用这样的解析器的人解决这个困境的方式是在解析过程中收集符号表数据并将额外的检查揉入到解析过程中,以强制解析器在遇到这种选择时做出正确的选择。这样做的代价是将名称和类型解析与解析混淆在一起,使构建这样的解析器变得非常困难。但是,至少对于传统的GCC,他们使用的是LALR,其在解析时是线性时间的,如果包括解析器所做的名称/类型捕获,则我认为代价不会更高(因为我认为他们没有做完所有操作)。
至少有两个使用“纯”GLR解析技术实现的C ++解析器,它简单地承认解析可能是本地模糊的,并在没有注释或重大开销的情况下捕获多个解析结果。当没有本地模糊性时,GLR解析器的速度是线性时间的。在模糊区域,它们的成本更高,但实际上,标准C++程序中的大部分源文本都属于“线性时间”部分。因此,即使捕获了模糊性,有效速率也是线性的。这两个已实现的解析器都在解析后执行名称和类型解析,并利用不一致性来消除不正确的模糊解析结果。这两个实现是Elsa和我们(SD)的C++前端。我不清楚Elsa的当前功能(我认为它已经多年没有更新了),但我们的实现可以处理所有C++11 [编辑于2015年1月:现在完全支持C++14 编辑于2017年10月:现在完全支持C++17],包括GCC和Microsoft变体。
如果你采取计算机科学中的严格定义,即将一种语言作为任意字符串集合进行外延定义(语法应该是编码内涵意义的简洁方式),并将解析处理视为“检查程序的语法是否正确”,则对于C ++,您需要扩展模板以验证每个模板是否完全展开。在模板中隐藏着一个图灵机,因此理论上检查C ++程序是否有效是不可能的(没有时间限制)。真正的编译器(遵循标准)对模板展开的数量施加固定约束,而真正的内存也是如此,因此在实践中,C ++编译器会完成这个过程。 但是在这个意义上,“解析”程序可能需要任意长的时间。我认为这是大多数人关心的答案。
实际上,我猜测大多数模板实际上是相当简单的,因此C ++编译器的平均完成时间与其他编译器一样快。只有那些在模板中编写图灵机的疯子才会付出严重的代价。(个人观点:代价真正的是将复杂事物硬生生地塞入模板的概念成本,而不是编译器执行成本。)
bool b = (A<B>::C == D<E>::F);
与 bool b = (A<B>::C == D<E >::F);
。如果我没记错的话,这两者都有有效的解析树。哪一个是可行的需要语义信息来确定。 - BCS视你如何理解“parsed”,如果你的解析包含模板实例化,那么通常情况下不行:
[如果你想避免阅读示例的话,这里有个快捷方式 - 模板提供了足够丰富的计算模型,因此实例化它们通常是一种停机式问题]
template<int N>
struct Triangle {
static const int value = Triangle<N-1>::value + N;
};
template<>
struct Triangle<0> {
static const int value = 0;
};
int main() {
return Triangle<127>::value;
}
O(N + 1000)
仍然只是O(N)
。 - Damon>>
用于关闭嵌套模板参数列表和其他一些内容,这些都使得 C++ 更难解析。 - sbi