it-swarm.com.ru

Почему 019 не является ошибкой синтаксиса JavaScript? Или почему 019> 020

Если я наберу 019 > 020 в консоли JavaScript (протестировано как в Chrome, так и в Firefox), я получу ответ true.

Это связано с тем, что 020 интерпретируется как OctalIntegerLiteral (равно 16), тогда как 019, по-видимому, интерпретируется как DecimalLiteral (и равно 19). Поскольку 19 больше, чем 16, 019 > 020 равен true.

Меня удивляет, почему 019 интерпретируется как DecimalLiteral в первую очередь. Какое производство это? DecimalIntegerLiteral не разрешает 019:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt

OctalIntegerLiteral также не допускает 019 (так как 9 не является восьмеричной цифрой):

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

OctalDigit :: one of
    0 1 2 3 4 5 6 7

Итак, из того, что я вижу в спецификации, 019 на самом деле должен быть отклонен, я не понимаю, почему он интерпретируется как десятичное целое число.

Я предполагаю, что здесь есть какое-то правило совместимости, но мне не удалось найти формальное определение. Может ли кто-нибудь помочь мне с этим?

(Зачем мне это нужно: я разрабатываю синтаксический анализатор JavaScript/ECMAScript для Java с JavaCC и должен уделять особое внимание спецификации и ее отклонениям.)

78
lexicore

Из того, что я мог найти, кажется, что некоторые реализации JavaScript просто не следуют спецификации в этом вопросе.

С сайт MDN:

Обратите внимание, что десятичные литералы могут начинаться с нуля (0), за которым следует другая десятичная цифра, но если следующая цифра после начального 0 меньше 8, то число анализируется как восьмеричное число. Это не добавит JavaScript, смотрите ошибка 95751 . Смотрите также страницу о parseInt ().

Это по-прежнему не объясняет, почему 019 == 19, учитывая, что следующая цифра после 0 начинается с 1, и поэтому целое число должно быть проанализировано как восьмеричное. Но указанная ошибка действительно имеет отношение к вашему делу. В его описании говорится:

Следующая программа JavaScript должна выдавать ошибку:

08

Согласно спецификации, DecimalIntegerLiteral никогда не может быть 0, за которым непосредственно следует другая десятичная цифра, хотя Chrome/Opera, PrestOpera и Firefox поддерживают это.

Ошибка закрыта как WONTFIX

Однако 019 будет действительным десятичным литералом со значением, равным 19, согласно проекту следующего издания:

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-additional-syntax-numeric-literals

(Я отметил соответствующие правила)

The syntax and semantics of 11.8.3 is extended as follows except that 
this extension is not allowed for strict mode code:

[...]

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt
    NonOctalDecimalIntegerLiteral                         // (1)

NonOctalDecimalIntegerLiteral ::
    0 NonOctalDigit
    LegacyOctalLikeDecimalIntegerLiteral NonOctalDigit    // (2)
    NonOctalDecimalIntegerLiteral DecimalDigit

LegacyOctalLikeDecimalIntegerLiteral ::
    0 OctalDigit                                          // (3)
    LegacyOctalLikeDecimalIntegerLiteral OctalDigit

Таким образом, 01 является LegacyOctalLikeDecimalIntegerLiteral (3). Тогда 019 является NonOctalDecimalIntegerLiteral (2), который, в свою очередь, является DecimalIntegerLiteral (1).

52
abl