Java decrement/increment 运算符的表达式解释规则
Java expression interpretation rules of decrement/increment operators
这是一个纯理论问题,为了清楚起见,我通常不会写这段代码。
为什么这个相当模棱两可的声明是合法的
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,但还没有找到答案。
要回答这个问题,我们必须看一下 Javas operators precendence。
这个例子的重要规则是:
- 表达式从左到右求值
expr--
后缀运算符的优先级高于 a-b
附加运算符。
表达式 a-----b
将因此计算如下: ((a--)--)-b
这是 非法 .
您可以通过在语句中使用大括号来绕过这些规则:(a--)-(--b)
将是一个合法的语句。
简介
要正确理解这一点,需要认识到所有现代编译器都具有两个识别源语言的级别,词法级别和句法级别。
词法层级("lexer")将源代码拆分为tokens:文字(string/numeric/char)、运算符、标识符和其他元素词汇语法。这就是编程语言的"words"和"punctuation characters"
句法级别 ("parser") 关注将这些低级词汇标记解释为语法,通常由语法树表示。
词法分析器是需要知道令牌是 "minus" 令牌 (-
) 还是 "decrement" (--
) 令牌的级别。 (减记号是一元减号还是二元减号,或者递减记号是post还是前置递减记号在句法层面确定)
诸如优先级和从左到右与从右到左之类的东西只存在于句法层面。但是 a---b
是 a -- - b
还是 a - -- b
是在词汇层面上确定的。
回答
为什么 a---b
变成 a -- - b
在 Java Language Specification section 3.2 "Lexical Translations":
中有描述
The longest possible translation is used at each step, even if the
result does not ultimately make a correct program while another
lexical translation would.
这样最长的词法标记就形成了。
在 a---b
的情况下,它使标记 a
、--
(最长)然后是唯一可能的下一个标记 -
,然后是 b
.
在a-----b
的情况下,会被翻译成a
、--
、--
、-
、b
、这在语法上是无效的。
进一步引用:
词汇翻译过程有3个步骤,在本例中,以上适用于本例中的第3步:
A raw Unicode character stream is translated into a sequence of
tokens, using the following three lexical translation steps, which are
applied in turn:
A translation of Unicode escapes (§3.3) in the raw stream of Unicode
characters to the corresponding Unicode character. A Unicode escape of
the form \uxxxx, where xxxx is a hexadecimal value, represents the
UTF-16 code unit whose encoding is xxxx. This translation step allows
any program to be expressed using only ASCII characters.
A translation of the Unicode stream resulting from step 1 into a
stream of input characters and line terminators (§3.4).
A translation of the stream of input characters and line terminators
resulting from step 2 into a sequence of input elements (§3.5) which,
after white space (§3.6) and comments (§3.7) are discarded, comprise
the tokens (§3.5) that are the terminal symbols of the syntactic
grammar (§2.3).
("input elements" 是 "tokens")
这是一个纯理论问题,为了清楚起见,我通常不会写这段代码。
为什么这个相当模棱两可的声明是合法的
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,但还没有找到答案。
要回答这个问题,我们必须看一下 Javas operators precendence。
这个例子的重要规则是:
- 表达式从左到右求值
expr--
后缀运算符的优先级高于a-b
附加运算符。
表达式 a-----b
将因此计算如下: ((a--)--)-b
这是 非法 .
您可以通过在语句中使用大括号来绕过这些规则:(a--)-(--b)
将是一个合法的语句。
简介
要正确理解这一点,需要认识到所有现代编译器都具有两个识别源语言的级别,词法级别和句法级别。
词法层级("lexer")将源代码拆分为tokens:文字(string/numeric/char)、运算符、标识符和其他元素词汇语法。这就是编程语言的"words"和"punctuation characters"
句法级别 ("parser") 关注将这些低级词汇标记解释为语法,通常由语法树表示。
词法分析器是需要知道令牌是 "minus" 令牌 (-
) 还是 "decrement" (--
) 令牌的级别。 (减记号是一元减号还是二元减号,或者递减记号是post还是前置递减记号在句法层面确定)
诸如优先级和从左到右与从右到左之类的东西只存在于句法层面。但是 a---b
是 a -- - b
还是 a - -- b
是在词汇层面上确定的。
回答
为什么 a---b
变成 a -- - b
在 Java Language Specification section 3.2 "Lexical Translations":
The longest possible translation is used at each step, even if the result does not ultimately make a correct program while another lexical translation would.
这样最长的词法标记就形成了。
在 a---b
的情况下,它使标记 a
、--
(最长)然后是唯一可能的下一个标记 -
,然后是 b
.
在a-----b
的情况下,会被翻译成a
、--
、--
、-
、b
、这在语法上是无效的。
进一步引用:
词汇翻译过程有3个步骤,在本例中,以上适用于本例中的第3步:
A raw Unicode character stream is translated into a sequence of tokens, using the following three lexical translation steps, which are applied in turn:
A translation of Unicode escapes (§3.3) in the raw stream of Unicode characters to the corresponding Unicode character. A Unicode escape of the form \uxxxx, where xxxx is a hexadecimal value, represents the UTF-16 code unit whose encoding is xxxx. This translation step allows any program to be expressed using only ASCII characters.
A translation of the Unicode stream resulting from step 1 into a stream of input characters and line terminators (§3.4).
A translation of the stream of input characters and line terminators resulting from step 2 into a sequence of input elements (§3.5) which, after white space (§3.6) and comments (§3.7) are discarded, comprise the tokens (§3.5) that are the terminal symbols of the syntactic grammar (§2.3).
("input elements" 是 "tokens")