Как работают escape-последовательности символов Юникода в Scala и Java при использовании в именовании - PullRequest
1 голос
/ 11 апреля 2020

Я недавно читал, что в Scala можно использовать escape-последовательности Unicode для именования.

Например:

val B\u0041\u0044 = 1

Позволяет:

scala> BAD
res0: Int = 1

Выполнить Scalafiddle

Я догадываюсь, что он работает примерно так же, как работает C #define <entity> <new_entity>, он просто заменяет escape-последовательность Юникода на визуализированный символ, который Вот почему BAD работает в приведенном выше примере.

В Java возможно то же самое. Поэтому мне интересно, имеет ли это отношение больше к Java, чем к Scala.

В Java возможно следующее:

double \u03C0 = Math.PI;

Что позволяет:

System.out.println(π)

Как это на самом деле работает под капотом?

Ответы [ 2 ]

4 голосов
/ 11 апреля 2020

Ваша путаница возникает из-за смешения двух совершенно разных уровней:

  1. escape-последовательности Unicode обрабатываются на уровне отдельных символов. Строго говоря, это происходит еще до лексического анализа. Это означает, что escape-последовательности Unicode ничего не знают о «именовании» или «именах» - когда они раскрываются, нет информации о том, что в данный момент обрабатывается: имя (идентификатор), зарезервированное ключевое слово или какая-то совершенно другая языковая конструкция. .

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

Все, что делает Scala, просто заменяет escape-последовательности \uXXXX на соответствующие символы Unicode. Например ( запустить ScalaFiddle ):

fo\u0072 (i <- 1 to 10) pri\u006Etln\u0028"hello, world\u0022)

- это совершенно правильная Scala программа, которая печатает hello, world десять раз. Итак, вы видите, что:

  1. * * * * * \u0072 расширяется до r в середине ключевого слова (for - зарезервированное ключевое слово, а не идентификатор)
  2. \u006E раскрывается в середине другого идентификатора (println)
  3. \u0028 и \u0022 заменяются на ( и " соответственно. Эти символы даже не могут быть действительными частями идентификаторов (если они не заключены в обратные знаки).

Он просто не имеет ничего общего с «именами». Все дело в отдельных символах, и это происходит до того, как появятся «имена», «строковые литералы» или «комментарии», поэтому такие загадки возникают, когда escape-последовательности Unicode используются внутри строковых литералов или комментарии, которые некорректно обрабатываются подсветкой кода.


Все это в основном не связано с тем, что происходит с макросами в препроцессоре C. Макросам, созданным с использованием #define, должно быть присвоено имя, которое является правильным идентификатором (т. Е. Состоит из символов, чисел, подчеркиваний), а если у макросов есть параметры, то препроцессор заменяет их дословно фактическими аргументами на сайте вызова. Ничего из этого невозможно с escape-последовательностями Unicode. Кроме того, C -процессор не будет разрывать токены: например, если вы #define u0072 r, препроцессор не будет go и заменяет все fou0072 -идентификаторы ключом for. Он работает совершенно по-другому и имеет совершенно другие цели.


Обновление: более подробные сведения

Если вы посмотрите на Сканеры. scala, вы можете видеть, что есть метод getUEscape , который обрабатывает escape-последовательности и помещает отдельные символы в буфер. Единственное место, где этот метод используется, - это другой вспомогательный метод getLitChar , так что все escape-последовательности Unicode всегда преобразуются в символы до того, как эти символы поступают в методы «более высокого уровня», такие как fetchToken . Это то, что я имел в виду, когда говорил, что обработка escape-последовательностей Unicode происходит еще до лексического анализа.

Как отметил Алексей Романов в комментариях ниже, побеги вскоре будут обрабатываться по-разному и расширяться в меньшем количестве контекстов. - изменения в , или , коммитах кажутся актуальными.

1 голос
/ 11 апреля 2020

Программа Java состоит из строки символов Unicode.

Нотация \ uNNNN поддерживается как способ представления отдельного символа, который нельзя ввести на конкретном устройстве ввода, которое вы используете. используя, например, все, что у вас есть, это ASCII-терминал или типичный US P C keybpard.

Java компилятор преобразует свой входной поток в стандартную форму Unicode, сначала обработав экранирование Unicode , См. спецификацию языка для подробностей.

...