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

标签 java c parsing grammar

我知道 the grammars of C and C++ are context-sensitive ,特别是您需要在 C 中使用“lexer hack”。另一方面,我的印象是,尽管这两种语言之间存在相当大的相似性,但您可以仅使用 2 个前瞻标记来解析 Java。

您需要对 C 进行哪些更改以使其更易于解析?

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

foo (a);

可以使用参数 a 调用 void 函数 foo。或者,可以将 a 声明为 foo 类型的对象,但您也可以轻松摆脱括号。部分原因是因为 C grammar 的“直接声明符”产生规则实现了声明函数和变量的双重目的。

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

foo a;

那么你知道它是一个变量声明,并且 foo 可以明确地被解析为一个类型名。如果类 foo 尚未在当前范围内的某处定义,则这可能不是有效代码,但这是语义分析的工作,可以在以后的编译器传递中执行。

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

最佳答案

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

查看 SO answer discussing why C (and C++) is "hard" to parse .简短的总结是 C 和 C++ 语法 本质上是模棱两可的。他们会给你多个解析,你必须使用上下文来解决歧义。然后人们会错误地假设您必须在解析时解决歧义;不是这样,见下文。如果您在解析时坚持解决歧义,那么您的解析器会变得更加复杂并且更难构建;但这种复杂性是自找的。

IIRC,Java 1.4 的“显而易见”的 LALR(1) 语法没有歧义,因此解析起来“容易”。我不太确定现代 Java 至少没有长途本地歧义。总是存在决定“...>>”是关闭两个模板还是“右移运算符”的问题。我怀疑 modern Java does not parse with LALR(1) anymore .

但是,对于这两种语言,人们可以通过使用强解析器(或弱解析器和上下文收集黑客,如 C 和 C++ 前端现在大多使用的那样)来解决解析问题。 C 和 C++ 具有预处理器的额外复杂性。这些在实践中比看起来更复杂。一种说法是 C 和 C++ 解析器太难了,必须手工编写。 It isn't true; you can build Java and C++ parsers just fine with GLR parser generators.

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

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

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

修复 C++ 语法无济于事。

关于更改 C++ 语法:您会发现您需要修补很多地方以处理任何 C++ 语法中的各种本地和实际歧义。如果您坚持,following list might be a good starting place .我认为如果您不是 C++ 标准委员会,那么这样做是没有意义的。如果你这样做了,并使用它构建了一个编译器,那么没有理智的人会使用它。为了方便构建解析器的人,对现有 C++ 应用程序的投资太多了;此外,他们的痛苦已经结束,现有的解析器工作正常。

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

关于java - 是什么让 Java 比 C 更容易解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26330425/

相关文章:

java - 解决 javax.net.ssl.SSLHandshakeException : sun. security.validator.ValidatorException : PKIX path building failed Error?

java - RESTEasy 不会将我的 Spring bean 映射到自定义 Spring ContextLoader

c - 为什么这个 union 会删除 c 代码中数组中的第一条记录?

python - 使用 Python range 内置函数从整数向后计数,与解析树相关

java - Hibernate 数据映射到子对象

c - R base C 代码如何处理矢量化?

c - 为什么在声明堆栈上的大数组时在C中出现段错误?

java - 当我尝试使用 BufferedReader 将整数输入存储到数组中时遇到数字格式异常

json - scala js 中的 scala 解析器组合器 (json)

java - java中包含操作系统级命令的包有哪些?