6

这是一个纯粹的理论问题,为了清楚起见,我通常不会编写此代码。

为什么这个相当模棱两可的声明是合法的

int a = 1, b = 2;
int c = a---b; // a=0, b=2, c=-1

(它被解释为a-- -b

而这个不是?

int c = a-----b;

第一个语句可以解释为a- --b,而第二个语句显然只有一个逻辑解释,即a-- - --b.

还有一个好奇的:

int c = a--- -b; // a=0, b=2, c=3

(并且int c = a----b; 不是法律声明)

Java中的表达式解释是如何定义的?我尝试搜索 JLS,但没有找到答案。

4

2 回答 2

4

介绍

要正确理解这一点,需要认识到所有现代编译器都具有两个级别的源语言识别,即词汇级别和句法级别。

词汇级别(“词法分析器”)将源代码拆分为标记:文字(字符串/数字/字符)、运算符、标识符和词汇语法的其他元素。这些是编程语言的“单词”和“标点符号”。

句法级别(“解析器”)负责将这些低级词汇标记解释为句法,通常由句法树表示。

词法分析器是需要知道标记是“减”标记(-)还是“减量”(--)标记的级别。(减号是一元减号还是二元减号,减量记号是后减记号还是前减记号在句法级别确定)

诸如优先级和从左到右与从右到左之类的东西只存在于句法级别。但是否a---ba -- - b或是a - -- b在词汇层面决定的。

回答

为什么a---ba -- - bJava 语言规范第 3.2 节“词法翻译”中描述:

每一步都使用尽可能的翻译,即使结果最终不会产生正确的程序,而另一个词汇翻译会。

这样就形成了可能最长的词法标记。

在 的情况下a---b,它使标记a, --(最长)然后是唯一可能的下一个标记-, 然后b

在 的情况下a-----b,它将被翻译成a, --, --, -, b, 这在语法上是无效的。

进一步引用:

词法翻译过程有 3 个步骤,在本例中,上述适用于本例中的第 3 步:

使用以下三个词汇翻译步骤将原始 Unicode 字符流翻译成一系列标记,依次应用:

  1. 将 Unicode 字符的原始流中的 Unicode 转义(第 3.3 节)翻译成相应的 Unicode 字符。\uxxxx 形式的 Unicode 转义,其中 xxxx 是十六进制值,表示编码为 xxxx 的 UTF-16 代码单元。此转换步骤允许任何程序仅使用 ASCII 字符来表示。

  2. 将步骤 1 产生的 Unicode 流转换为输入字符和行终止符流(第 3.4 节)。

  3. 将步骤 2 产生的输入字符流和行终止符转换为输入元素序列(第 3.5 节),在丢弃空格(第 3.6 节)和注释(第 3.7 节)之后,这些元素组成了标记(第 3.5 节)它们是句法文法的终结符号(第 2.3 节)。

(“输入元素”是“令牌”)

于 2016-03-17T13:17:00.677 回答
2

要回答这个问题,我们必须看一下 Java运算符的优先级。

此示例的重要规则是:

  • 表达式从左到右计算
  • 后缀运算符的expr--优先级高于a-b加法运算符。

因此,该表达式a-----b将按如下方式计算:((a--)--)-b这是非法的。

您可以通过在语句中使用大括号来绕过这些规则:(a--)-(--b)将是一个法律声明。

于 2016-03-17T13:10:23.433 回答