Java 是否有不明确的语法,需要有关标识符的更多信息?



注意:这个问题不是关于"Java没有指针">

在 C 语言中,代码identifier1 * identifier2在两个可能的含义上是模棱两可的:

  1. 如果标识符 1 是类型,则这可能是指针声明。
  2. 如果标识符 1 是一个变量,那么这可能是一个乘法语句。

问题是我在构建语法树时无法选择正确的生产。我检查了 Clang 的代码,似乎 Clang 必须将类型检查(通过使用符号表)放入解析阶段(如果我错了,请纠正我)。

然后我检查了javac(OpenJDK)的代码,似乎在解析阶段,不涉及语义分析。解析器可以几乎不使用令牌构建 AST。

所以我很好奇Java是否有同样的模棱两可的语法问题?如果解析器不知道标识符的类型,它就不能选择正确的生产?

或者更通用地说,Java 是否有语法模糊,解析器无法选择没有其他信息而不是令牌流的生产?

对于语言,标记化始终与上下文相关。但是,Java没有如此敏感的运算符。但是,您可以以这样的方式链接令牌,以产生歧义,但不仅仅是作为更大的语法语句的一部分:

A < B可以是public class A < B > { ... }if (A < B) { ... }的一部分。 第一个是泛型类定义,第二个是比较。

这只是我帽子顶部的第一个例子,但我认为还有更多。 但是,运算符通常定义得非常狭窄,并且不能(如在类似 C/C++ 的语言中)重载。此外,除了在C/C++中只有一个访问器运算符(点:.),只有一个例外(从Java 8开始,双冒号::)。 在C++有一堆,所以它不那么混乱。

关于Java是否总是在语法上可判定的具体问题: 是的。实现良好的编译器始终可以根据令牌流决定存在哪个令牌。

我不这么认为Java有这个问题,因为Java是强类型的。 此外,Java不支持指针,因此不会出现上述问题。 我希望这能回答你的问题。

您的问题不容易回答;这取决于您拥有的生产规则。你说:

there's two production:
<pointer> ::= * {<type-qualifier>}* {<pointer>}?
or
<multiplicative-expression> ::= <multiplicative-expression> * <cast-expression>

但这不是唯一可能的解析器!

用 C 看

foo * bar;

它可以是名为bar的指针,用于键入foo,也可以将foo乘以bar解析为令牌流:

identifier_or_type ASTERISK identifier_or_type SEMICOLON

剩下的就看解析器"业务逻辑"了。所以这里在解析器级别根本没有歧义,规则背后的逻辑决定了两种情况之间的差异。

foo.bar.bla.i这样的表达式不能单独使用语法以有意义的方式解析。foobarbla中的每一个都可以是包名的一部分、静态变量(这不适用于foo)或内部类的名称。

例:

public class Main {
public static void main(String[] args) {
System.out.println(foo.bar.bla.i);
}
}

package foo;
public class bar {
public static class bla {
public static int i = 42;
}
//  public static NotBla bla = new NotBla();
public static class NotBla {
public static int i = 21;
}
}

这将打印2142当静态变量bla被注释掉或不被注释掉时。

相关内容

最新更新