在Attoparsec中解析时实现“包含”

时间:2019-02-03 10:16:56

标签: parsing haskell attoparsec

我正在写DSL,很有趣。我决定使用attoparsec,因为我对此很熟悉。

我想用这样的相对文件名实现包含的解析:

include /some/dir/file.ext

或网址:

include http://blah.com/my/file.ext

因此,在解析时,我希望读取引用的资源并解析整个内容,并将其内容附加到“外部”解析状态。

问题是,尽管这些语句的解析很容易,但是我无法在Attoparsec解析器中运行IO(据我所知)。

我如何使用Attoparsec实现这一目标?我是否使用一些字符串过滤将初始输入切碎,然后将每个“块”分别解析为parsefeed?本质上是两遍解析方法?

1 个答案:

答案 0 :(得分:4)

Attoparsec是纯净的(Data.Attoparsec.Internal.Types.Parser不是转换器,并且不包含IO),因此您是对的,不能直接在解析器中扩展包含。

将解析器分成两遍似乎是正确的方法:一遍就像C预处理程序一样,接受带有include语句与其他内容交错的文件。 “其他内容”基本上只需要在词法上是有效的,而不是您的完整解析器-就像C预处理器只关心标记和匹配的括号,而不匹配其他括号或任何语义一样。然后,您替换掉包含文件,生成一个完全扩展的文件,您可以将其提供给现有的解析器。

如果所包含的文件在某种意义上必须在语法上“独立” ,则可以首先解析整个文件,并与include交错,然后替换它们。例如:

-- Whatever items you’re parsing.
data Item

-- A reference to an included path.
data Include = Include FilePath

parse :: Parser [Either Include Item]

-- Substitute includes; also calls ‘parse’
-- recursively until no includes remain.
substituteIncludes :: [Either Include Item] -> IO [Item]

说,如果您只是使用attoparsec来进行词法标记,这些标记无论如何都无法越过文件边界,或者您正在进行完全解析,但想禁止包含文件的包含文件无与伦比的括号。


另一种选择是通过使用其他解析库(例如megaparsec)将IO直接嵌入解析器,该解析库提供了ParsecT转换器,您可以将其封装在IO周围以进行{ {1}}直接在解析器中。我可能会为原型执行此操作,但似乎尽量将解析和扩展的关注点分开。