Выбор кодировки для компилятора (ссылка на статью)
Комментарии:
2021-01-17 alextretyak
Если в язык добавляем поддержку кириллицы, то разбор уже такой:Тут наверное ошибка — имеется в виду «добавляем поддержку русского алфавита», а не кириллицы.
[Причём «русского алфавита без буквы ё» :)(:.]
Как я предполагаю ПЕРВЫЙ СИМВОЛ ИДЕНТИФИКАТОРА это константа 1, а СЛЕДУЮЩИЙ СИМВОЛ ИДЕНТИФИКАТОРА — это константа 2.if (! (массив признаков [символ] && ПЕРВЫЙ СИМВОЛ ИДЕНТИФИКАТОРА )) ... if (! (массив признаков [символ] && СЛЕДУЮЩИЙ СИМВОЛ ИДЕНТИФИКАТОРА ))
Но в таком случае следует использовать поразрядное И (&), а не логическое (&&).
Признаю целесообразность ограничиться только поддержкой базовой плоскости Юникода (первые 65536 символов), тогда реализация в виде простого массива из 65536 элементов почти оптимальна. Но если поразмышлять на этот счёт...
Если посмотреть в документацию MSVC, то там приводятся конкретные диапазоны символов Юникода, которые можно использовать в идентификаторах. Наибольший код допустимого в идентификаторах символа составляет EFFFD, что в десятичной системе — 983037. Таким образом, потребуется массив из 983038 элементов. Но. А что, если признаки символов хранить не в одном массиве, а в разных — по одному массиву на каждый признак. И если вместо массива использовать hash-set\хэш-множество. Я написал простенькую программу, которая суммирует все диапазоны из документации MSVC и, таким образом, считает сколько символов допустимо использовать в идентификаторах в MSVC. Получилось 971380. Теперь, вместо того, чтобы хранить символы, которые допустимо использовать в идентификаторах, можно хранить только недопустимые, ведь их всего лишь 11658 (983038 - 971380)!
P.S. Вопрос автору сайта: а почему символ «|» [даже внутри блока кода] заменяется на «!» (восклицательный знак) при нажатии на «Предварительный просмотр»? {…}
2021-01-18 alextretyak
Дабы закрыть эту тему решил провести небольшое исследование.
Как я уже писал в предыдущем сообщении, в Microsoft Visual C++ используется определённый набор диапазонов кодов символов, которые разрешено использовать в идентификаторах. Оказывается, эти диапазоны прописаны в стандарте C++ (в Annex E), и они также используются например в языке Swift.
Однако, откуда взялись эти диапазоны остаётся загадкой.
В языке C# уже лучше. В том смысле, что в его спецификации не зашиты непосредственно коды символов, а указаны категории символов Юникода (а именно: ‘Lu’, ‘Ll’, ‘Lt’, ‘Lm’, ‘Lo’ и ‘Nl’), которые можно использовать в идентификаторах. (Категории всех символов Юникода указаны в файле UnicodeData.txt в 3-й колонке.)
Аналогично, в языке Go используются категории ‘Lu’, ‘Ll’, ‘Lt’, ‘Lm’ и ‘Lo’.
В Python ещё лучше — всё определение идентификатора помещается в одной строчке:
The identifier syntax is <XID_Start> <XID_Continue>*
Где
<XID_Start>и
<XID_Continue>— категории символов для идентификаторов, которые [категории] определены прямо в стандарте Unicode! {…}
[В JavaScript аналогично используются категории
ID_Startи
ID_Continue{…}.]
Но, как говорил В.: «Мы пойдём другим путём!»
Ну не хочется мне включать коды символов или их диапазоны в исходный текст лексического анализатора без крайней необходимости. И я решил разобраться с теми средствами, которые предоставляют языки Python и C++ [на которых написан или в которые транслируется лексический анализатор языка 11l].
В Python есть метод
isalpha(), который возвращает
Trueдля всех символов, принадлежащих одной из категорий ‘Lm’, ‘Lt’, ‘Lu’, ‘Ll’ или ‘Lo’. Что почти в точности совпадает с разрешёнными символами в C# (не считая редко используемую категорию ‘Nl’) и совпадает с разрешёнными символами в Go. Поэтому в Python-коде анализатора можно спокойно использовать
isalpha(). [Ещё в Python есть встроенный модуль
unicodedata, функция
unicodedata.category()которого возвращает категорию заданного символа, но считаю, что можно обойтись
isalpha().]
В C/C++ есть функция
iswalpha(), которая возвращает «не пойми что», причём ещё и в зависимости от текущей локали.
В попытке разобраться с этой функцией я составил такую табличку:
┌──────────┬────────┐ │ макс.код │ кол-во │ ┌───────────────────────────────────┼──────────┼────────┤ │ MSVC identifiers │ 983037 │ 971380 │ │ isalpha() in Python │ 195101 │ 125419 │ │ Unicode 13.0.0 Letter │ 195101 │ 125419 │ │ iswalpha() in MSVC (any locale) │ 1114076 │ 811189 │ │ iswalpha() in GCC (no setlocale) │ 122 │ 52 │ │ iswalpha() in GCC (setlocale "C") │ 122 │ 52 │ │ iswalpha() in GCC (setlocale "") │ 195101 │ 94318 │ └───────────────────────────────────┴──────────┴────────┘(Исходный код ‘для вычисления’/получения всех этих циферок доступен тут.)
Какой вывод/итог?...
...А решайте сами. :)(:
Я пока остановился на варианте «
isalpha()для Python», «
iswalpha()[с предварительным вызовом
setlocale(LC_CTYPE, "");] для C++». Теперь лексические анализаторы транспайлеров Python → 11l и 11l → C++ поддерживают кириллицу в идентификаторах, а это собственно то, ради чего это исследование и проводилось.