F# 为什么在lexer规范中对换行符和空格的处理不同?

F# 为什么在lexer规范中对换行符和空格的处理不同?,f#,lexer,fslex,F#,Lexer,Fslex,我正在使用F#的FsLex生成一个lexer。我很难理解教科书中的以下两行。为什么换行符(\n)的处理方式与空白区不同?特别是,“lexbuf.EndPosA规则本质上是一个以lexer缓冲区为参数的函数。规则左侧的每个大小写都与给定的字符(例如,'\n')或字符类([''\t'\r'])匹配在您的输入中。在大括号{…}内,规则大小正确的表达式定义了一个操作。您粘贴的定义的目的似乎是一个标记器 表达式Tokenize lexbuf是对Tokenize规则的递归调用。本质上,此规则忽略空白字符。为

我正在使用F#的FsLex生成一个lexer。我很难理解教科书中的以下两行。为什么换行符(\n)的处理方式与空白区不同?特别是,“lexbuf.EndPosA
规则
本质上是一个以lexer缓冲区为参数的函数。规则左侧的每个大小写都与给定的字符(例如,
'\n'
)或字符类(
[''\t'\r']
)匹配在您的输入中。在大括号
{…}
内,规则大小正确的表达式定义了一个操作。您粘贴的定义的目的似乎是一个标记器

表达式
Tokenize lexbuf
是对
Tokenize
规则的递归调用。本质上,此规则忽略空白字符。为什么?因为标记化程序旨在简化输入。空白在编程语言中通常没有意义,因此此规则将其过滤掉。标记化输入通常会使编写pa变得困难rser稍后会更简单。您最终会希望将其他案例添加到
Tokenize
规则中(例如,对于关键字、赋值语句和其他表达式),以生成完整的lexer定义

第二条规则,即与
\n
匹配的规则,也会忽略空格,但正如您正确指出的,它会做一些不同的事情。它所做的是用下一行的结束位置(
lexbuf.EndPos.NextLine
)更新行结束位置(
lexbuf.EndPos.NextLine
)在再次递归调用
标记化之前。为什么?大概是为了在下次递归调用时结束位置正确


因为这里只显示了一个lexer片段,我只能猜测lexbug.EndPos的用途,但是为了诊断的目的保留这些信息是很常见的。

a
rule
本质上是一个函数,它将lexer缓冲区作为参数。规则左侧的每个案例都匹配一个给定值输入中的n个字符(例如,
'\n'
)或字符类(
['''\t'\r']
)。规则大小正确的表达式,在大括号
{…}
内,定义了一个操作。粘贴的定义的目的似乎是标记器

表达式
Tokenize lexbuf
是对
Tokenize
规则的递归调用。本质上,此规则忽略空白字符。为什么?因为标记化程序旨在简化输入。空白在编程语言中通常没有意义,因此此规则将其过滤掉。标记化输入通常会使编写pa变得困难rser稍后会更简单。您最终会希望将其他案例添加到
Tokenize
规则中(例如,对于关键字、赋值语句和其他表达式),以生成完整的lexer定义

第二条规则,即与
\n
匹配的规则,也会忽略空格,但正如您正确指出的,它会做一些不同的事情。它所做的是用下一行的结束位置(
lexbuf.EndPos.NextLine
)更新行结束位置(
lexbuf.EndPos.NextLine
)在再次递归调用
标记化之前。为什么?大概是为了在下次递归调用时结束位置正确

因为这里只显示了一个lexer片段,所以我只能猜测lexbug.EndPos是用来做什么的,但是为了诊断的目的保留这些信息是很常见的

rule Tokenize = parse
  | [' ' '\t' '\r'] { Tokenize lexbuf }
  | '\n'            { lexbuf.EndPos <- lexbuf.EndPos.NextLine; Tokenize lexbuf }