注意:这个问题不是关于“Java没有指针”
在C语言中,代码identifier1 * identifier2
对于两个可能的含义是不明确的:
问题是我在构建语法树时无法选择正确的产品。我检查了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不支持指针,因此不存在上述问题。我希望这能回答你的问题。
像foo.bar.bla.i
这样的表达式不能仅使用语法以有意义的方式解析。 foo
,bar
和bla
中的每一个都可以是包名称的一部分,一个静态变量(这个不适用于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;
}
}
当静态变量21
被注释掉时,这将打印42
或bla
。
你的问题不容易回答;这取决于您的生产规则。你说:
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
其余的由解析器“业务逻辑”决定。因此,解析器级别根本没有歧义,规则背后的逻辑使得两种情况之间存在差异。