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



我知道C和C++的语法是上下文敏感的,尤其是你需要在C中使用"lexer hack"。

为了使C更易于解析,您需要对其进行哪些更改

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

foo (a);

可能正在使用参数a调用void函数foo。或者,它可以将a声明为foo类型的对象,但也可以很容易地消除这些偏执狂。在某种程度上,之所以会出现这种奇怪的情况,是因为C语法的"直接声明器"生成规则实现了声明函数和变量的双重目的。

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

foo a;

那么您就知道它是一个变量声明,并且foo可以明确地被解析为类型名。如果foo类没有在当前作用域中的某个地方定义,那么这可能不是有效的代码,但这是一项语义分析工作,可以在以后的编译器过程中执行

我看到有人说,由于typedef,C很难解析,但您也可以在Java中声明自己的类型。除了direct_declarator之外,还有哪些C语法规则有错?

解析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++在这里真的很糟糕。从这个角度来看,Java7和8变得相当糟糕。(符号表并不是你所需要的全部;请参阅我的简历,了解一篇关于"解析后的生活"的长文)。

大多数人都很难完成纯解析部分(通常永远不会完成;请查看SO本身,了解关于如何为真正的语言构建可工作的解析器的许多问题),所以他们永远看不到解析后的生活。然后我们得到了关于什么是难以解析的民间定理,而没有关于那个阶段之后会发生什么的信号。

修复C++语法不会有任何进展

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

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