Haskell 解析器是否应该允许数字文字中的 Unicode 数字?
Should a Haskell parser allow Unicode digits in numeric literals?
作为练习,我正在从头开始为 Haskell 编写解析器。在制作词法分析器时,我注意到 Haskell 2010 Report:
上的以下规则
digit → ascDigit | uniDigit
ascDigit → 0
| 1
| … | 9
uniDigit → any Unicode decimal digit
octit → 0
| 1
| … | 7
hexit → digit | A
| … | F
| a
| … | f
decimal → digit{digit}
octal → octit{octit}
hexadecimal → hexit{hexit}
integer → decimal | 0o
octal | 0O
octal | 0x
hexadecimal | 0X
hexadecimal
float → decimal .
decimal [exponent] | decimal exponent
exponent → (e
| E
) [+
| -
] decimal
十进制和十六进制文字,以及浮点文字,都基于 digit,它接受任何 Unicode 十进制数字,而不是 ascDigit],它只接受 ASCII 中的基本数字 0-9。奇怪的是,octal 基于 octit,它只接受 ASCII 数字 0-7。我猜想这些 "Unicode decimal digit" 是具有 "Nd" 通用类别的任何 Unicode 代码点。但是,这包括全角数字 0-9 和梵文数字 ०-९ 等字符。我明白为什么在标识符中允许这些可能是可取的,但我看不出允许为文字 90
.
编写 ९0
有任何好处
GHC 似乎同意我的观点。当我尝试编译这个文件时,
module DigitTest where
x1 = 1
它吐出这个错误。
digitTest1.hs:2:6: error: lexical error at character '297'
|
2 | x1 = 1
| ^
但是,这个文件
module DigitTest where
x1 = 1
编译得很好。我是否错误地阅读了语言规范? GHC 的(明智的)行为实际上是正确的,还是在技术上违反了报告中的规范?我在任何地方都找不到这件事。
在GHC源代码文件compiler/parser/Lexer.x
中,可以找到如下代码:
ascdigit = 0-9
$unidigit = \x03 -- Trick Alex into handling Unicode. See [Unicode in Alex].
$decdigit = $ascdigit -- for now, should really be $digit (ToDo)
$digit = [$ascdigit $unidigit]
...
$binit = 0-1
$octit = 0-7
$hexit = [$decdigit A-F a-f]
...
@numspc = _* -- numeric spacer (#14473)
@decimal = $decdigit(@numspc $decdigit)*
@binary = $binit(@numspc $binit)*
@octal = $octit(@numspc $octit)*
@hexadecimal = $hexit(@numspc $hexit)*
@exponent = @numspc [eE] [\-\+]? @decimal
@bin_exponent = @numspc [pP] [\-\+]? @decimal
这里,$decdigit
用于解析十进制和十六进制文字(及其浮点变体),而 $digit
用于字母数字标识符的 "numeric" 部分。 "ToDo" 说明清楚地表明这是 GHC 与语言标准的公认偏差。
所以,您没有正确阅读规范,而 GHC 是半故意违反规范的。有一个 open ticket 建议至少记录偏差,但我认为没有人表示有兴趣修复它。
作为练习,我正在从头开始为 Haskell 编写解析器。在制作词法分析器时,我注意到 Haskell 2010 Report:
上的以下规则digit → ascDigit | uniDigit
ascDigit →0
|1
| … |9
uniDigit → any Unicode decimal digit
octit →0
|1
| … |7
hexit → digit |A
| … |F
|a
| … |f
decimal → digit{digit}
octal → octit{octit}
hexadecimal → hexit{hexit}integer → decimal |
0o
octal |0O
octal |0x
hexadecimal |0X
hexadecimal
float → decimal.
decimal [exponent] | decimal exponent
exponent → (e
|E
) [+
|-
] decimal
十进制和十六进制文字,以及浮点文字,都基于 digit,它接受任何 Unicode 十进制数字,而不是 ascDigit],它只接受 ASCII 中的基本数字 0-9。奇怪的是,octal 基于 octit,它只接受 ASCII 数字 0-7。我猜想这些 "Unicode decimal digit" 是具有 "Nd" 通用类别的任何 Unicode 代码点。但是,这包括全角数字 0-9 和梵文数字 ०-९ 等字符。我明白为什么在标识符中允许这些可能是可取的,但我看不出允许为文字 90
.
९0
有任何好处
GHC 似乎同意我的观点。当我尝试编译这个文件时,
module DigitTest where
x1 = 1
它吐出这个错误。
digitTest1.hs:2:6: error: lexical error at character '297'
|
2 | x1 = 1
| ^
但是,这个文件
module DigitTest where
x1 = 1
编译得很好。我是否错误地阅读了语言规范? GHC 的(明智的)行为实际上是正确的,还是在技术上违反了报告中的规范?我在任何地方都找不到这件事。
在GHC源代码文件compiler/parser/Lexer.x
中,可以找到如下代码:
ascdigit = 0-9
$unidigit = \x03 -- Trick Alex into handling Unicode. See [Unicode in Alex].
$decdigit = $ascdigit -- for now, should really be $digit (ToDo)
$digit = [$ascdigit $unidigit]
...
$binit = 0-1
$octit = 0-7
$hexit = [$decdigit A-F a-f]
...
@numspc = _* -- numeric spacer (#14473)
@decimal = $decdigit(@numspc $decdigit)*
@binary = $binit(@numspc $binit)*
@octal = $octit(@numspc $octit)*
@hexadecimal = $hexit(@numspc $hexit)*
@exponent = @numspc [eE] [\-\+]? @decimal
@bin_exponent = @numspc [pP] [\-\+]? @decimal
这里,$decdigit
用于解析十进制和十六进制文字(及其浮点变体),而 $digit
用于字母数字标识符的 "numeric" 部分。 "ToDo" 说明清楚地表明这是 GHC 与语言标准的公认偏差。
所以,您没有正确阅读规范,而 GHC 是半故意违反规范的。有一个 open ticket 建议至少记录偏差,但我认为没有人表示有兴趣修复它。