Подтвердить что ты не робот

Поддержка Flex (lexer) для unicode

Мне интересно, поддерживает ли новейшая версия flex поддержку unicode?

Если да, то как использовать шаблоны в соответствии с китайскими символами?

Подробнее: Используйте регулярное выражение для соответствия любому китайскому символу в кодировке utf-8

4b9b3361

Ответ 1

В настоящий момент flex только генерирует 8-битные сканеры, которые в основном ограничивают использование UTF-8. Поэтому, если у вас есть шаблон:

肖晗   { printf ("xiaohan\n"); }

он будет работать, как ожидалось, поскольку последовательность байтов в шаблоне и на входе будет одинаковой. Что еще сложнее - классы персонажей. Если вы хотите совместить символ 肖 или 晗, вы не можете писать:

[肖晗]   { printf ("xiaohan/2\n"); }

потому что это будет соответствовать каждому из шести байтов 0xe8, 0x82, 0x96, 0xe6, 0x99 и 0x97, что на практике означает, что если вы введете 肖晗 в качестве ввода, шаблон будет соответствовать шесть раз. Поэтому в этом простом случае вам нужно переписать шаблон на (肖|晗).

Для диапазонов Ханс Аберг написал инструмент , который преобразует их в 8-битные шаблоны:

Unicode> urToRegU8 0 0xFFFF
[\0-\x7F]|[\xC2-\xDF][\x80-\xBF]|(\xE0[\xA0-\xBF]|[\xE1-\xEF][\x80-\xBF])[\x80-\xBF]
Unicode> urToRegU32 0x00010000 0x001FFFFF
\0[\x01-\x1F][\0-\xFF][\0-\xFF]
Unicode> urToRegU32L 0x00010000 0x001FFFFF
[\x01-\x1F][\0-\xFF][\0-\xFF]\0

Это не очень, но он должен работать.

Ответ 2

Flex не поддерживает Unicode. Однако Flex поддерживает двоичный вход "8 бит чистый". Поэтому вы можете писать лексические шаблоны, которые соответствуют UTF-8. Вы можете использовать эти шаблоны в определенных лексических областях языка ввода, например, идентификаторы, комментарии или строковые литералы.

Это будет хорошо работать для типичных языков программирования, где вы сможете заявить пользователям своей реализации, что исходный язык написан в ASCII/UTF-8 (и никакая другая кодировка не поддерживается, период).

Этот подход не будет работать, если ваш сканер должен обрабатывать текст, который может быть в любой кодировке. Он также не будет работать (очень хорошо), если вам нужно выразить лексические правила специально для элементов Unicode. То есть вам нужны символы Unicode и регулярные выражения Unicode в самом сканере.

Идея состоит в том, что вы можете распознать шаблон, который включает байты UTF-8, используя правило lex (а затем, возможно, взять yytext и преобразовать его из UTF-8 или хотя бы проверить его.)

Для рабочего примера см. исходный код языка TXR, в частности этот файл: http://www.kylheku.com/cgit/txr/tree/parser.l

Прокрутите вниз до этого раздела:

ASC     [\x00-\x7f]
ASCN    [\x00-\t\v-\x7f]
U       [\x80-\xbf]
U2      [\xc2-\xdf]
U3      [\xe0-\xef]
U4      [\xf0-\xf4]

UANY    {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
UANYN   {ASCN}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} 
UONLY   {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}

Как вы можете видеть, мы можем определить шаблоны для соответствия символам ASCII, а также начальным и последующим байтам UTF-8. UTF-8 - лексическая нотация, и это генератор лексического анализатора, поэтому... нет проблем!

Некоторые объяснения: UANY означает соответствие любому символу, однобайтовому ASCII или многобайтовому UTF-8. UANYN означает UANY, но не соответствует новой строке. Это полезно для токенов, которые не ломаются между строками, например, комментарий от # до конца строки, содержащий международный текст. UONLY означает соответствие только расширенному символу UTF-8, а не ASCII. Это полезно для написания правила lex, которое должно исключать некоторые определенные символы ASCII (а не только новую строку), но все расширенные символы в порядке.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Обратите внимание, что в правилах сканера используется функция utf8_dup_from для преобразования строк yytext в широкие символы, содержащие кодовые обозначения Unicode. Эта функция надежна; он обнаруживает такие проблемы, как чересстрочные последовательности и недопустимые байты, и правильно обрабатывает их. То есть эта программа не полагается на эти правила lex для проверки и преобразования, просто для того, чтобы выполнить базовое лексическое распознавание. Эти правила будут распознавать перекрывающуюся форму (например, код ASCII, закодированную с использованием нескольких байтов) в качестве действительного синтаксиса, но функция преобразования будет обрабатывать их должным образом. В любом случае, я не ожидаю, что проблемы безопасности, связанные с UTF-8, в исходном коде программы, так как вы должны доверять исходному коду, который будет запускать его в любом случае (но данные, обрабатываемые программой, могут не доверять!) Если вы записывая сканер для ненадежных данных UTF-8, будьте осторожны!

Ответ 3

  Мне интересно, поддерживает ли новейшая версия flex юникод?

Если да, то как использовать шаблоны для сопоставления китайских иероглифов?

Чтобы сопоставить шаблоны с китайскими символами и другими кодовыми точками Unicode с помощью Flex-совместимого лексического анализатора, вы можете использовать RE/flex lexical analyzer для C++.

RE/flex безопасно поддерживает полный стандарт Unicode 12 и принимает входные файлы UTF-8, UTF-16 и UTF-32, не требуя взломов UTF-8, которые даже не поддерживают ввод UTF-16/32.

Кроме того, хаки UTF-8 с Flex не позволяют писать регулярные выражения Unicode, такие как [肖晗], которые полностью поддерживаются в RE/flex.

Он работает без проблем с Bison для создания лексеров и парсеров.

Фактически, с помощью RE/flex мы можем записывать любые шаблоны Unicode в виде регулярных выражений на основе UTF-8 в спецификациях lexer .l, таких как:

%option flex unicode
%%
[肖晗]   { printf ("xiaohan/2\n"); }
%%

При этом генерируется лексер, который автоматически сканирует файлы UTF-8, UTF-16 и UTF-32. Согласно стандартизации UTF, для ввода UTF-16/32 на входе ожидается спецификация UTF, в то время как спецификация UTF-8 является дополнительной.

Мы можем использовать глобальный %option unicode для включения Unicode и %option flex для определения спецификаций Flex. Локальный модификатор (?u:) можно использовать для ограничения Unicode одним шаблоном (так что все остальное по-прежнему ASCII/8-битное, как в Flex):

%option flex
%%
(?u:[肖晗])   { printf ("xiaohan/2\n"); }
(?u:\p{Han})  { printf ("Han character %s\n", yytext); }
.             { printf ("8-bit character %d\n", yytext[0]); }
%%

Опция flex обеспечивает совместимость с Flex, поэтому вы можете использовать yytext, yyleng, ECHO и т.д. Без опции flex RE/flex ожидает вызовов методов Lexer: text() (или str() и wstr() для std::string и std::wstring), size() (или wsize() для широкой длины символа), и echo(). Вызовы методов RE/flex более чистые ИМХО и включают в себя операции с широкими символами