Выбор кодировки для компилятора (ссылка на статью)


Комментарии:

2021-01-17 alextretyak

Если в язык добавляем поддержку кириллицы, то разбор уже такой:
Тут наверное ошибка — имеется в виду «добавляем поддержку русского алфавита», а не кириллицы.
[Причём «русского алфавита без буквы ё» :)(:.]

    if (! (массив признаков [символ] && ПЕРВЫЙ СИМВОЛ ИДЕНТИФИКАТОРА ))
    ...
        if (! (массив признаков [символ] && СЛЕДУЮЩИЙ СИМВОЛ ИДЕНТИФИКАТОРА ))
Как я предполагаю ПЕРВЫЙ СИМВОЛ ИДЕНТИФИКАТОРА это константа 1, а СЛЕДУЮЩИЙ СИМВОЛ ИДЕНТИФИКАТОРА — это константа 2.
Но в таком случае следует использовать поразрядное И (&), а не логическое (&&).


Признаю целесообразность ограничиться только поддержкой базовой плоскости Юникода (первые 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++ поддерживают кириллицу в идентификаторах, а это собственно то, ради чего это исследование и проводилось.