当使用像 Parsec 这样的解析器组合器库时,我应该使用词法分析器吗?

2024-03-19

当在像 Haskell 的 Parsec 这样的解析器组合器库中编写解析器时,您通常有 2 个选择:

  • 编写一个词法分析器来分割你的String输入token,然后进行解析[Token]
  • 直接编写解析器组合器String

第一种方法通常似乎是有意义的,因为许多解析输入可以理解为由空格分隔的标记。

在其他地方,我看到人们建议不要标记化(或scanning or lexing,有些人这么称呼它),简单性被认为是主要原因。

进行词法分析和不进行词法分析之间的一般权衡是什么?


最重要的区别是 lexing 将翻译您的输入域.

A nice结果是

  • 您不必再考虑空白。在直接(非词法分析)解析器中,您必须撒上space在所有允许空格的地方都有解析器,这很容易忘记,并且如果必须分隔空格,它会使您的代码变得混乱all无论如何你的代币。

  • 您可以逐段思考您的输入,这对人类来说很容易。

但是,如果您执行词法分析,您会得到problems that

  • 您不能使用通用解析器String不再 - 例如用于使用库函数解析数字parseFloat :: Parsec String s Float(在字符串输入流上运行),你必须做类似的事情takeNextToken :: TokenParser String and execute the parseFloat解析器,检查解析结果(通常Either ErrorMessage a)。这写起来很混乱并且限制了可组合性。

  • 您已调整所有错误消息。如果您的标记解析器在第 20 个标记处失败,那么该标记位于输入字符串的哪个位置?您必须手动将错误位置映射回输入字符串,这很乏味(在秒差距中,这意味着调整所有SourcePos值)。

  • 错误报告通常更糟糕。跑步string "hello" *> space *> float输入错误,例如"hello4"会准确地告诉您,在hello,而词法分析器只会声称找到了"invalid token".

  • 很多事情都是人们所期望的原子单位和被词法分析器分开实际上对于词法分析器来说“太难”识别。以字符串文字为例 - 突然"hello world"不是两个令牌"hello and world"不再(但是only,当然,如果引号没有转义,比如\") - 虽然这对于解析器来说是非常自然的,但对于词法分析器来说这意味着复杂的规则和特殊情况。

  • 您也不能在标记上重复使用解析器。如果您定义如何解析双精度型String,出口它,世界其他地方都可以使用它;他们无法首先运行您的(专用)标记器。

  • 你被它困住了。当您开发要解析的语言时,使用词法分析器可能会导致您做出早期决定,修复您之后可能想要更改的内容。例如,假设您定义了一种语言,其中包含一些Float令牌。在某些时候,您想引入负数文字(-3.4 and - 3.4) - 这可能是不可能的,因为词法分析器将空格解释为标记分隔符。使用仅解析器的方法,您可以保持更加灵活,从而更轻松地更改语言。这并不奇怪,因为解析器是一种更复杂的工具,它本质上编码rules.

总而言之,我建议在大多数情况下编写无词法分析器的解析器。

最后,词法分析器只是一个“简化的”*解析器 - 如果您无论如何都需要一个解析器,请将它们组合成一个。


* From computing theory, we know that all regular languages are also context-free languages http://en.wikipedia.org/wiki/Chomsky_hierarchy#The_hierarchy; lexers are usually regular, parsers context-free or even context-sensitve (monadic parsers like Parsec can express context-sensitiveness).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当使用像 Parsec 这样的解析器组合器库时,我应该使用词法分析器吗? 的相关文章

  • 在 Haskell 中将 Maybe Int 转换为 Int

    我正在编写以下代码 并希望找到框字符串中数字的索引 所以我用了findIndex但它返回Maybe Int值 而我只想要Int value 我怎样才能转换Maybe Int to Int值或者有什么方法可以提取Int from Maybe
  • 在 Haskell 中阅读 GraphML

    我正在尝试将包含单个有向图的 GraphML 文件读入 HaskellData Graph http hackage haskell org package containers 0 2 0 1 docs Data Graph html为了
  • 我应该在哪里划清词法分析器和解析器之间的界限?

    我正在为 IMAP 协议编写一个词法分析器 用于教育目的 但我很困惑应该在词法分析器和解析器之间划清界限 以 IMAP 服务器响应为例 FLAGS Answered Deleted 该响应的正式语法定义如下 mailbox data FLA
  • 使用 cabal new-install 重新安装相同版本的软件包

    我正在开发 Haskell 包 我还没有上传到Hackage 版本号是0 1 0 0 我正在使用新风格的 Cabal 命令 为了在我处理包的同时测试它 使库可用于测试项目 我运行cabal new install lib构建包后 然而 我注
  • GHC 可以为 monad 转换器派生 Functor 和 Applicative 实例吗?

    我正在尝试实施MaybeT本着mtl图书馆 使用这个非编译解决方案 LANGUAGE FlexibleInstances MultiParamTypeClasses UndecidableInstances import Control M
  • 函数式编程是否需要新的命名约定?

    我最近开始使用 Haskell 学习函数式编程 并在 Haskell 官方 wiki 上发现了这篇文章 如何阅读哈斯克尔 http www haskell org haskellwiki How to read Haskell What t
  • Haskell 中美元符号 ($) 和 id 函数之间有关系吗?

    这几天我正在读一篇评论莫纳德挑战 http mightybyte github io monad challenges 我强烈推荐给像我这样的 Haskell 初学者 我最终得到了这个线程 https news ycombinator co
  • 如何使用 Haskell 中的 thyme 库从 Int 值创建 UTCTime?

    我有年 月 日 小时和分钟值 所有这些都是类型Int 我怎样才能将它们转换为UTCTime or UniversalTime 需要导入以下内容 import Control Lens import Data Thyme Clock impo
  • 整数转浮点数

    这段代码的工作原理 posToXY Float gt Float gt Integer posToXY a b do let y a b round y 但这不起作用 posToXY Integer gt Integer gt Intege
  • 类 GADT 类型变量的未来角色?

    A 昨天的问题 https stackoverflow com q 41135212 3072788有一个定义HList 来自HList https hackage haskell org package HList 0 4 1 0 doc
  • Haskell:找不到模块“Data.List.Split”

    我正在尝试在 Haskell 中拆分列表 据我所知 最简单的方法是splitOn 但是这个函数需要Data List Split 所以我尝试运行import Data List Split在前奏曲中 但是 我收到以下错误 Could not
  • 为什么 Parsec 的 sepBy 停止并且不解析所有元素?

    我正在尝试解析一些逗号分隔的字符串 该字符串可能包含也可能不包含具有图像尺寸的字符串 例如 hello world 300x300 good bye world 我写了下面的小程序 import Text Parsec import qua
  • Haskell 中的实例声明

    我有这两个功能 primes sieve 2 where sieve p xs p sieve x x lt xs x mod p gt 0 isPrime number number 1 null x x lt takeWhile x g
  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • 在依赖类型的函数式编程语言中,扁平化列表是否更容易?

    在 haskell 中寻找一个可以展平任意深度嵌套列表的函数时 即应用的函数concat递归并在最后一次迭代时停止 使用非嵌套列表 我注意到这需要有一个更灵活的类型系统 因为随着列表深度的变化 输入类型也会变化 确实 有几个 stackov
  • Haskell 中的中缀运算符优先级

    对于以下 Haskell 表达式 返回 a gt gt f 应该读作 返回a gt gt f or 返回 a gt gt f 这里的相关规则是什么 规则始终是函数应用程序的优先级高于任何运算符 因此 return a gt gt f 被解析
  • Traversable 类型类的用途

    有人可以向我解释一下类型类的目的是什么吗Traversable 类型类定义是 class Functor t Foldable t gt Traversable t gt where So Traversable is a Functor
  • 用于遇到 [...] 的 Haskell Parsec 解析器

    我正在尝试使用 Parsec 在 Haskell 中编写一个解析器 目前我有一个可以解析的程序 test x 1 2 3 end 执行此操作的代码如下 testParser do reserved test v lt identifier
  • 如何在haskell中获取变量名称

    我来到 haskell 时有一些 c 背景知识 想知道是否有类似的 define print a printf s d n a a int a 5 print a 应该打印 a 5 这是 augustss 提到的 TH 解决方案 LANGU

随机推荐