4

C 是严格按顺序解析的,即一切都必须在使用前声明;特别是,类型必须在这些类型的变量之前声明。这是有道理的,因为如果您不知道类型的名称是什么,而类型的名称不是什么,则语法将是模棱两可的,例如a * b取决于是否a命名了一个类型。

另一方面,一些 C 系列语言具有放松这种限制的理想特性(从而消除了对头文件的手动处理)。我正在为 C 超集语言编写一个解析器,该语言旨在同样放松该限制,所以现在我需要弄清楚如何去做。

我想到的一种方法是做两次传球。第一遍遍历所有内容,利用顶层的所有内容都必须是声明而不是声明的事实,并选择所有类型。在这个阶段,函数体没有被检查,只是作为由匹配的大括号分隔的标记流被拾取。第二遍解析函数体。函数中的局部声明必须是有序的,但这并不是真正的问题。

这种方法有没有我没有想到的绊脚石?

C++、Java、C# 等的编译器通常如何处理那些不需要按顺序声明的语言部分?

4

3 回答 3

2

您不必在解析时进行名称解析。首先,如果您正在设计一种“类 C”语言(而不是新的 C 实现),您可以定义您的语法,以便声明、表达式、方法等在语法中都是明确的。然后解析顺序无关紧要。(这也可以通过将预处理器以结构化的方式集成到语言中来解决预处理器疾病)。

如果您坚持使用类似 C 的语法,您可以使用能够容忍歧义的解析器,例如,乐于处理 "x*y;" 并将其作为表达式和声明保存,直到它获得更多数据。在极端情况下,只需将此视为基于约束的解决方案。C 和 C++ 坚持首先知道定义,因为最初编译器的内存空间非常有限,您不能只保留所有内容;这不再是真的。解析时不必坚持知道答案。

我们在 DMS Software Reengineering Toolkit 中为此使用 GLR 解析器,并且非常高兴能够很好地解析 C 和 C++11。我们解析做名称解析;这隔离了解析和名称解析,使前端更清洁、更易于管理。

于 2013-02-05T16:45:08.100 回答
1

C++确实需要按顺序声明。

请记住,C 和 C++ 是完全不同的球赛。他们正在使用非常古老的链接器技术(C 因为它古老的,C++ 因为它几乎和 C 链接器一样古老并且兼容)。两者都导致直接在 CPU 上运行的二进制文件,没有运行时支持可言。

Java 和 C# 有很多改进的链接器可以依赖,并且有一个庞大的运行时支持系统可以使用。

两者各有利弊。C/C++ 方法的缺点之一是必须在编译时解决所有问题,因为在运行时应用程序是独立的。优点是一切都在编译时解决,因此在运行时应用程序可以不理会。

于 2013-02-05T14:49:29.753 回答
0

几乎所有的编译器都会做两遍。另一种方法是允许在语法本身中声明变量,这会使语法更难手动解析,但无需第二遍。

于 2013-02-05T14:47:28.973 回答