目前,flex 仅生成 8 位扫描仪,这基本上限制了您使用 UTF-8。所以如果你有一个模式:
肖晗 { printf ("xiaohan\n"); }
它将按预期工作,因为模式和输入中的字节序列将相同。更困难的是字符类。如果你想匹配肖或瀚,你不能写:
[肖晗] { printf ("xiaohan/2\n"); }
因为这将匹配六个字节 0xe8、0x82、0x96、0xe6、0x99 和 0x97 中的每一个,这实际上意味着如果您提供
肖晗
作为输入,该模式将匹配六次。因此,在这个简单的情况下,您必须将模式重写为 (肖|晗)
。
对于范围,Hans Aberg 在 Haskell 中编写了一个工具,可以将它们转换为 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
这不太漂亮,但应该可以。
Flex 不支持 Unicode。然而,Flex 支持“8 位干净”二进制输入。因此,您可以编写与 UTF-8 匹配的词汇模式。您可以在输入语言的特定词汇区域使用这些模式,例如标识符、注释或字符串文字。
这对于典型的编程语言非常有效,您可以向实现的用户断言源语言是用 ASCII/UTF-8 编写的(并且不支持其他编码,句号)。
如果您的扫描仪必须处理可以采用任何编码的文本,则此方法将不起作用。如果您需要专门针对 Unicode 元素表达词汇规则,它也不会(很好)工作。 IE。您需要扫描仪本身中的 Unicode 字符和 Unicode 正则表达式。
这个想法是,您可以使用 lex 规则识别包含 UTF-8 字节的模式(然后可能采用
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 字符。这对于编写需要排除某些特定 ASCII 字符(不仅仅是换行符)但所有扩展字符都可以的 lex 规则很有用。
免责声明:请注意,扫描仪的规则使用名为
的函数将utf8_dup_from
转换为包含 Unicode 代码点的宽字符串。该功能很强大;它可以检测超长序列和无效字节等问题并正确处理它们。 IE。这个程序并不依赖这些lex规则来进行验证和转换,只是做基本的词法识别。这些规则会将超长形式(例如使用多个字节编码的 ASCII 代码)识别为有效语法,但转换函数会正确处理它们。无论如何,我不希望程序源代码中出现与 UTF-8 相关的安全问题,因为无论如何您都必须信任源代码才能运行它(但程序处理的数据可能不可信!)编写不受信任的 UTF-8 数据扫描器,小心!yytext