flex 中的 Unicode 字符?

Unicode Character in flex?

我有一个关于两个 unicode 字符的简单问题,我想在我的编程语言中使用它们。对于作业,我想使用旧的 APL 符号 ← 以及 →。

我的弹性文件 (snazzle.l) 如下所示:

/** phi@gress.ly 2017                     **/
/** parser for omni programming language. **/
%{
#include <iostream>
using namespace std;
#define YY_DECL extern "C" int yylex()
int linenum = 0;
%}

%%
[\n]           {++linenum;}

[ \t]           ;
[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?  { cout << linenum << ". Found a floating-point number: " << yytext << endl; }
\"[^\"]*\"      { cout << linenum << ". Found string: " << yytext << endl; }
[0-9]+          { cout << linenum << ". Found an integer: " << yytext << endl; }
[a-zA-Z0-9]+    { cout << linenum << ". Found an identifier: "   << yytext << endl; }
([\←])|([\→])|(:=)|(=:)  { cout << linenum << ". Found assignment operator: " << yytext <<endl; }
[\;]            { cout << linenum << ". Found statement delimiter: " << yytext <<endl; }
[\[\]\(\)\{\}]  { cout << linenum << ". Found parantheses: " << yytext << endl; }

%%
main() {
    // lex through the input:
    yylex();
}

当我"snazzle"输入以下内容时:

x →  y;

我得到赋值字符 a) 错误和 b) 三 (3) 次:

0. Found an identifier: x
0. Found assignment operator: �
0. Found assignment operator: �
0. Found assignment operator: �
0. Found an identifier: y
0. Found statement delimiter: ;

如何添加 ← 和 → 尽可能灵活的字符?

Flex 生产八位清洁扫描仪;也就是说,它可以处理由任意八位字节组成的任何输入。它对 UTF-8 或 Unicode 代码点一无所知,但这并不能阻止它将 Unicode 输入字符识别为八位字节的 序列 (not 单个字符)。哪个序列取决于您使用的 Unicode 编码,但假设您的文件是 UTF-8,→ 将是三个字节 e2 86 92 和 ← 将是 e2 86 90.

然而,您实际上不必知道这一点;您可以将 UTF-8 序列放入您的 flex 模式中。您甚至不需要引用它,尽管这可能是个好主意,因为如果您最终使用正则表达式运算符,它会证明不那么混乱。这里我的意思是引用它,如"←"\← 不会做你期望的,因为 \ 只适用于下一个 octet (正如我所说,flex 对Unicode 编码),它只是该符号中三个字节中的第一个。换句话说,"←"? 真正意味着 "an optional left-arrow",而 \←? 意味着 "the two octets \xE2 \x86 optionally followed by \x90"。我希望这很清楚。

Flex 字符 classes 对 Unicode 序列(或任何其他多字符序列)没有用,因为字符 class 是一组八位字节。因此,如果您写 [←],flex 会将其解释为 "one of the octets \xE2, \x86 or \x90"。 [注1]

备注

  1. 很少需要在 flex 字符 classes 中对字符进行反斜杠转义;唯一必须反斜杠转义的字符是反斜杠本身。转义不需要转义的字符不是错误,因此 flex 不会抱怨它,但它会使字符 classes 难以让人阅读(至少,对于这个人来说是这样) .所以 [\←][←] 的意思完全一样,你可以把 [\[\]\(\)\{\}] 写成 [][)(}{]。 (如果字符 class 是 class 中的第一个字符,] 不会关闭字符 class,因此通常写括号 "face-to-face")。

  2. 也没有必要在备选项中用括号括起字符序列,因此您可以将 ([\←])|([\→])|(:=)|(=:) 写成 ←|→|:=|=:。或者,如果您愿意,"←"|"→"|":="|"=:"。当然,您通常不会那样做,因为扫描器通常会通知解析器有关每个单独运算符的信息。如果您的目的是使 ← 成为 := 的同义词,那么您可能会得到:

    ←|:=    { return LEFT_ARROW; }
    →|=:    { return RIGHT_ARROW; }
    
  3. 与其在扫描仪规范中插入 printf 操作,不如让 flex 将扫描仪置于调试模式会更好。这就像在构建扫描仪时将 -d 添加到 flex 命令行一样简单。有关详细信息,请参阅 flex manual section on debugging