是什么让Java比C更容易解析?

2022-08-31 11:24:37

我熟悉这样一个事实,即C和C++的语法是上下文相关的,特别是你需要一个C中的“词法分析器黑客”。另一方面,我的印象是,你可以只用2个前瞻标记来解析Java,尽管这两种语言之间有相当大的相似性。

关于 C,你必须改变什么才能使它更易于解析?

我之所以问这个问题,是因为我所看到的所有关于C的上下文敏感性的例子在技术上都是允许的,但非常奇怪。例如

foo (a);

可以调用带有参数的 void 函数。或者,它可以声明为类型的对象,但你可以很容易地摆脱参数。在某种程度上,这种奇怪的发生是因为C语法的“直接声明器”生产规则实现了声明函数和变量的双重目的。fooaafoo

另一方面,Java 语法具有用于变量声明和函数声明的单独生产规则。如果你写

foo a;

然后你知道它是一个变量声明,可以明确地解析为类型名称。如果尚未在当前作用域中的某个位置定义类,则这可能不是有效的代码,但这是一项语义分析工作,可以在以后的编译器传递中执行。foofoo

我看到有人说C很难解析,因为typedef,但你也可以在Java中声明自己的类型。此外,哪些 C 语法规则有问题?direct_declarator


答案 1

解析C++变得越来越困难。解析Java也变得同样困难。

请参阅此SO答案,讨论为什么C(和C++)“难以”解析。简短的总结是,C和C++语法本质上是模棱两可的;它们将为您提供多个解析,您必须使用上下文来解决歧义。然后,人们会错误地认为您必须在解析时解决歧义;不是这样,见下文。如果你坚持在解析时解决歧义,你的解析器会变得更加复杂,更难构建;但这种复杂性是自我造成的伤害。

IIRC, Java 1.4 的“明显”LALR(1) 语法并不模棱两可,因此解析起来“容易”。我不太确定现代Java是否至少有长距离局部歧义;总是存在决定“...>>“关闭两个模板或是”右移位操作员”。我怀疑现代Java不再使用LALR(1)进行解析

但是,对于这两种语言,可以通过使用强解析器(或弱解析器和上下文收集黑客,就像C和C++前端现在大多所做的那样)来克服解析问题。C和C++具有具有预处理器的额外复杂性;这些在实践中比看起来更复杂。一种说法是,C和C++解析器非常难,必须手动编写。事实并非如此;你可以用GLR解析器生成器构建Java和C++解析器。

但解析并不是问题的真正所在。

解析后,您将需要对AST/解析树执行某些操作。在实践中,对于每个标识符,您需要知道它的定义是什么以及它在哪里使用(“名称和类型解析”,草率地构建符号表)。事实证明,这比获得正确的解析器要多得多,再加上继承,接口,重载和模板,以及混淆了所有这些的语义是用非正式的自然语言编写的,分布在数十到数百页的语言标准中。C++在这里真的很糟糕。从这个角度来看,Java 7和8变得非常糟糕。(符号表并不是你所需要的全部;请参阅我的简历,了解一篇关于“解析后的生活”的长篇文章)。

大多数人都在纯粹的解析部分(通常永远不会完成;检查SO本身,以获取有关如何为真实语言构建工作解析器的许多问题),因此他们永远不会在解析后看到生命。然后我们得到关于什么很难解析的民间定理,并且没有关于该阶段之后会发生什么的信号。

修复C++语法不会让你得到任何东西。

关于更改C++语法:您会发现您需要修补很多地方来处理任何C++语法中的各种本地和实际歧义。如果您坚持,以下列表可能是一个很好的起点。我认为,如果你不是C++标准委员会,那么这样做是没有意义的。如果你这样做了,并用它来构建一个编译器,没有人会使用它。在现有的C++应用程序上投入了太多,为了方便构建解析器而切换;此外,他们的痛苦已经结束,现有的解析器工作正常。

您可能希望编写自己的解析器。好吧,没关系;只是不要指望社区的其他人让你改变他们必须使用的语言,让你更容易。他们都希望它对他们来说更容易,那就是使用记录和实现的语言。


答案 2

推荐