Поддержка Flex (lexer) для unicode
Мне интересно, поддерживает ли новейшая версия flex поддержку unicode?
Если да, то как использовать шаблоны в соответствии с китайскими символами?
Подробнее:
Используйте регулярное выражение для соответствия любому китайскому символу в кодировке utf-8
Ответы
Ответ 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 более чистые ИМХО и включают в себя операции с широкими символами