f# - 为什么在词法分析器规范中对换行符和空格的处理不同?
问题描述
我正在使用 F# 的 FsLex 来生成词法分析器。我很难从教科书中理解以下两行。为什么换行符 (\n) 的处理方式与空格不同?特别是,“lexbuf.EndPos <- lexbuf.EndPos.NextLine”与“Tokenize lexbuf”有何不同?
rule Tokenize = parse
| [' ' '\t' '\r'] { Tokenize lexbuf }
| '\n' { lexbuf.EndPos <- lexbuf.EndPos.NextLine; Tokenize lexbuf }
解决方案
Arule
本质上是一个将词法分析器缓冲区作为参数的函数。规则左侧的每个大小写都与输入中的给定字符(例如'\n'
)或字符类别 ( ) 匹配[' ' '\t' '\r']
。花括号内的规则大小右侧的表达式{ ... }
定义了一个动作。您粘贴的定义的目的似乎是tokenizer。
该表达式Tokenize lexbuf
是对Tokenize
规则的递归调用。本质上,该规则忽略了空白字符。为什么?因为分词器旨在简化输入。空格在编程语言中通常没有意义,因此这条规则将其过滤掉。标记化输入通常会使以后编写解析器更简单。您最终会希望将其他情况添加到您的Tokenize
规则中(例如,用于关键字、赋值语句和其他表达式)以生成完整的词法分析器定义。
第二条规则,即匹配的规则\n
,也忽略了空格,但正如您正确指出的那样,它做了一些不同的事情。它所做的是在再次递归调用之前将行尾的位置 ( ) 更新为下一行的结束( )lexbuf.EndPos
的位置。为什么?大概是为了在下一次递归调用中结束位置是正确的。lexbuf.EndPos.NextLine
Tokenize
由于您在这里只显示一个词法分析器片段,我只能猜测lexbug.EndPos
它的用途,但为了诊断目的而保留这些信息是很常见的。
推荐阅读
- r - 使用 cut() 的离散箱
- php - 如何在 Laravel 中实现数组类型路由?
- node.js - userId 是全局唯一标识符吗?
- ios - 如何强制将值分配给常量?
- jquery - 如何从我的 ajax 将数据推送到系列折线图导致 highchart
- reactjs - 更改选择器模式 material-ui-pickers 中的显示值
- hibernate - 尝试在使用 @Transactional 注释的 Spring @Service 类中的同一方法中检索子实体时出现 LazyInitializationException
- javascript - 从另一个 JS 文件和节点目录结构中调用函数
- cross-browser - 如何在 webgl 上下文中使用 alpha blendmode 修复跨浏览器问题?
- java - 如何在每个事务开始时运行自定义查询?