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


90

我熟悉C和C ++的语法对上下文敏感的事实,特别是您需要在C中使用“ lexer hack”。另一方面,我的印象是您可以仅用尽管这两种语言之间有相当大的相似性,但它们还是2个前瞻标记。

为了使C解析起来更容易处理,您需要更改什么?

我之所以问是因为,我所见过的有关C的上下文敏感度的所有示例在技术上都是允许的,但非常奇怪。例如,

foo (a);

可能正在foo通过参数调用void函数a。或者,它可能声明a是type的对象foo,但您也可以轻松摆脱寄生。在某种程度上,这种怪异之所以会发生是因为C语法的“直接声明符”生成规则满足了声明函数和变量的双重目的。

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

foo a;

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

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


7
很酷的问题。不过可能范围太广或主要是自以为是。
asteri 2014年

37
这是一个关于解析器的有效问题,对此的广泛了解或唯一见解是最后几句话(可能应该删除或更改)。以接近的票数退出。
R .. GitHub停止帮助ICE,2014年

1
我相应地编辑了问题,感谢@R ..的反馈。
korrok 2014年

3
几乎每种(标准)计算机语言都是上下文相关的;您不能声明一种类型的变量,并且会在大多数语言中滥用该变量。这与“ 语言的所有语法 ”是上下文敏感的不同;大多数构建解析器的人会构建一个无上下文(甚至更具限制性)的解析器,然后使用解析器外部的黑客检查无上下文的属性。
艾拉·巴克斯特2014年

1
@IraBaxter我不会称其为“ hacks”。将问题一分为二似乎是一件合理的事,因为解析上下文相关的语言无法高效完成(事实上,即使解析上下文无关的语言也不是很有效,这就是为什么我们通常限制为上下文无关的子集) 。一个无上下文解析+静态分析以仅检查AST上的上下文相关属性是一件合理的事情。
Bakuriu 2014年

Answers:


76

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

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

IIRC,Java 1.4的“明显” LALR(1)语法不明确,因此解析起来“容易”。我不太确定现代Java是否至少没有长距离的本地歧义。总是存在决定“ ... >>”是关闭两个模板还是“右移运算符”的问题。我怀疑现代Java不再使用LALR(1)进行解析

但是对于这两种语言,都可以通过使用强大的解析器(或像C和C ++前端现在大多使用的弱解析器和上下文收集hack)来克服解析问题。C和C ++具有预处理器的额外复杂性。在实践中,这些比看起来要复杂。一种说法是,C和C ++解析器太难了,必须手工编写。 这不是真的 您可以使用GLR解析器生成器来构建Java和C ++解析器。

但是解析并不是问题所在。

解析后,您将需要对AST /解析树进行操作。实际上,对于每个标识符,您需要知道其定义以及定义的用途(“名称和类型解析”,草率地构建符号表)。事实证明,这比完成正确的解析器要花很多功夫,再加上继承,接口,重载和模板,而且所有这些语义都是以非正式的自然语言编写的,这分散了数十到数百个页面语言标准。C ++在这里真的很糟糕。从这个角度来看,Java 7和8变得非常糟糕。(而且符号表并不是您所需要的;请参阅我的简历,以获取有关“解析后的生活”的更长的文章)。

大多数人都在为纯解析部分而苦苦挣扎(通常永不完结;请检查SO本身是否有很多有关如何为实际语言构建解析器的问题),因此他们永远都看不到解析后的生命。然后,我们得到了关于难以解析的东西的民间定理,而没有信号说明该阶段之后发生了什么。

修复C ++语法无法助您一臂之力。

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

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


好答案。另请参阅D和C +,它们试图解决其中的一些问题。s / content / contend /
david.pfx 2014年

3
我之前读过《解析后的生活》,发现它确实使人大开眼界。这让我很清楚,语义分析(名称/类型解析,...)比解析中要做的工作更多。我没有尝试更改任何语言的语法。我确实想了解一种语言的属性,在该语言中可以先进行语法分析,然后再进行语义分析。C不是这种语言(需要lexer hack);我一直以为Java是,我想知道为什么。
2014年

1
@Korrok:请阅读我有关使用GLR解析器构建Java / C ++的答案。 您不需要任何lexer hack。因此,区别在于使用错误的解析技术的人们。...的确,建立一个完整的C ++前端(尤其是C ++ 14,我们已经完成)比做Java8困难,但是它们都非常困难(就工作量和对细节的关注而言)和解析是最简单的部分。
Ira Baxter 2014年

1
我同意您的“解析后的生活”:例如,C#中的重载分辨率可以编码任何3-SAT问题,因此是NP难的。
约尔格W¯¯米塔格

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.