我正在使用F#的FsLex来生成lexer。我很难理解课本上的以下两句话。为什么换行符(\n(与空白处不同?特别地;lexbuf。EndPos<-lexbuf。EndPos.NextLine";与";标记lexbuf"?
rule Tokenize = parse
| [' ' 't' 'r'] { Tokenize lexbuf }
| 'n' { lexbuf.EndPos <- lexbuf.EndPos.NextLine; Tokenize lexbuf }
rule
本质上是一个以lexer缓冲区为参数的函数。规则左侧的每个大小写都与输入中的给定字符(例如'n'
(或字符类([' ' 't' 'r']
(匹配。大括号{ ... }
内规则大小合适的表达式定义了操作。粘贴的定义的目的似乎是标记化器。
表达式Tokenize lexbuf
是对Tokenize
规则的递归调用。本质上,这个规则忽略了空白字符。为什么?因为标记化器的目的是简化输入。空白在编程语言中通常没有意义,所以这个规则会过滤掉它。标记化的输入通常会使以后编写解析器变得更简单。您最终会希望在Tokenize
规则中添加其他事例(例如,关键字、赋值语句和其他表达式(,以生成完整的lexer定义。
第二条规则,即与n
匹配的规则,也会忽略空白,但正如您正确指出的那样,它会做一些不同的事情。它所做的是在再次递归调用Tokenize
之前,用下一行的末尾(lexbuf.EndPos.NextLine
(的位置更新行末尾的位置(lexbuf.EndPos
(。为什么?大概是为了在下一次递归调用中结束位置是正确的。
由于这里只显示了一个lexer片段,我只能猜测lexbug.EndPos
的用途,但出于诊断目的保留这些信息是很常见的。