减量/增量运算符的Java表达式解释规则

减量/增量运算符的Java表达式解释规则,java,syntax,lexer,decrement,interpretation,Java,Syntax,Lexer,Decrement,Interpretation,这是一个纯粹的理论问题,为了清晰起见,我不会正常编写此代码 为什么这一模棱两可的声明是合法的 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 (而且intc=a---b;不是一项法律声明) 如何在Jav

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

为什么这一模棱两可的声明是合法的

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
(而且
intc=a---b;
不是一项法律声明)


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

要回答这个问题,我们必须看看Java

本例的重要规则如下:

  • 表达式从左到右求值
  • expr--
    Postfix运算符比
    a-b
    加法运算符具有更高的优先级

因此表达式
a--b
的计算结果如下:
((a--)b
,这是非法的

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

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

词法层(“lexer”)将源代码拆分为标记:文本(string/numeric/char)、运算符、标识符和词法语法的其他元素。这些是编程语言的“单词”和“标点符号”

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

lexer是需要知道令牌是“减”令牌(
-
)还是“减量”(
-
)令牌的级别。(减号标记是一元减号还是二元减号,或者减量标记是减量后标记还是减量前标记,在语法层面上确定)

像优先权和从左到右与从右到左这样的东西只存在于句法层面。但是
a--b
a--b
还是
a--b
取决于词汇层面

答复 为什么
a--b
变为
a--b
,请参见:

在每个步骤中使用最长的可能的翻译,即使 结果不会最终生成正确的程序,而另一个 词法翻译是一种有效的翻译方法

这样就形成了最长的词汇标记

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

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

再引述一点:

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

原始Unicode字符流被转换为 标记,使用以下三个词汇翻译步骤 依次应用:

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

  • 将步骤1产生的Unicode流转换为 输入字符流和行终止符(§3.4)

  • 输入字符流和行终止符的翻译 从第2步产生的输入元素序列(§3.5),其中, 在删除空白(§3.6)和注释(§3.7)后,包括 标记(§3.5)是句法结构的终端符号 语法(§2.3)


  • (“输入元素”是“标记”)

    要搜索的神奇单词是
    java操作符优先级
    。我猜
    a--b
    解释为:
    ((a--)b--)b
    ,这是不合法的。@KlasLindbäck不,不是。神奇的单词是“lexer”,而不是解析器。lexer是识别标记(数字、标识符、运算符等)的级别。直到解析树的构建,运算符优先级才起作用。@ErwinBolwidt我站在正确的位置<代码>a---b不会compile@AndrewTobilko是的,我知道。在这篇文章中,我试图解释为什么它没有编译…运算符优先级不适用于lexer。它确保
    a-b--
    被解释为
    a-(b--)
    而不是
    (a-b--
    ),但它不能确保
    a--b
    被解释为
    a--b
    而不是
    a--b
    @ErwinBolwidt这就是为什么我提到表达式是从左到右求值的原因,Erwin。看起来我做了一个错误的假设,java编译器将尝试理解给定的表达式,而不是使用一些简单的规则来解析表达式,即使它不创建合法的语句。