2009-10-03 37 views
6

我正在为Haskell的Alex写一个小型语言的词法分析器。如何使用alex/haskell做python式缩进/缩进标记?

该语言被指定为具有pythonesque重要缩进,并且每当缩进级别更改时都会发出INDENT标记或DEDENT标记。

在像C这样的传统命令式语言中,您会在词法分析器中保留一个全局,并使用每行的缩进级别对其进行更新。

这在Alex/Haskell中不起作用,因为我不能用Haskell在任何地方存储任何全局数据,也不能将所有的lexing规则放在任何monad或任何东西中。

那么,我该怎么做呢?它甚至有可能吗?或者我将不得不写我自己的词法分析器,并避免使用alex?

回答

11

请注意,在其他空白敏感语言(如Haskell)中,布局处理确实是在词法分析器中完成的。 GHC实际上在Alex中实现了布局处理。这里的源:

https://github.com/ghc/ghc/blob/master/compiler/parser/Lexer.x

有你的问题有些严重的错误,你引入歧途,因为jrockway指出。 “我无法在Haskell的任何地方存储任何全球数据”处于错误的轨道上。首先,你可以有全局状态,其次,你不应该在这里使用全局状态,当亚历克斯完全支持规则中的状态转换以安全的方式。

看看Alex提供的AlexState结构,让您通过词法分析器监视状态。然后,看看在GHC的布局实现中如何使用状态来实现缩进/取消缩进布局规则。 (在GHC的词法分析器中搜索“ - 布局处理”以查看状态是如何被推入和弹出的)。

+0

不错。我最终和Alex玩了一下,发现它在某些方面比PArrows更清洁(这通常是我所能达到的)。感谢您的信息:) – jrockway

+0

啊,谢谢你。我也问过#haskell,发现了用于alex的UserState包装器。虽然没有太多的文件,但必须做一些源搜索。 我知道国家单体,但我不确定穿过亚历克斯的词法分析器穿线状态。 感谢您的帮助。 – kamatsu

5

我不能在任何地方存储任何全局数据哈斯克尔

这是不正确的;在大多数情况下,像State monad就足够了,但也有ST monad

但是,您不需要全局状态来执行此任务。编写解析器由两部分组成;词法分析和语法分析。词法分析只是将一串字符变成一串有意义的记号。语法分析将令牌转化为AST;这是你应该处理缩进的地方。

在解释缩进时,随着缩进级别的改变,你会调用一个处理函数 - 当它增加(嵌套)时,你调用你的处理函数(也许增加一个arg,如果你想跟踪缩进水平);当级别降低时,您只需从函数返回相关的AST部分。

(顺便说一下,使用全局变量对于我来说不会出现在命令式语言中 - 如果有的话,它是一个实例变量,State monad在概念上与此非常相似。)

最后,我认为“我不能把我所有的规则放在任何monad中”这句话表示对monad的某种误解。如果我需要分析和保持全局状态,我的代码看起来像:

data AST = ... 
type Step = State Int AST 

parseFunction :: Stream -> Step 
parseFunction s = do 
    level <- get 
    ... 
    if anotherFunction then put (level + 1) >> parseFunction ... 
    else parseWhatever 
    ... 
    return node 

parse :: Stream -> Step 
parse s = do 
    if looksLikeFunction then parseFunction ... 

main = runState parse 0 -- initial nesting of 0 

相反功能的应用与(.)($)结合,你(>>=)(>>)将它们结合起来。除此之外,算法是相同的。 (有没有 “单子” 是 “内部”。)

最后,你可能会喜欢的应用性函子:

eval :: Environment -> Node -> Evaluated 
eval e (Constant x) = Evaluated x 
eval e (Variable x) = Evaluated (lookup e x) 
eval e (Function f x y) = (f <$> (`eval` x) <*> (`eval` y)) e 

(或

eval e (Function f x y) = ((`eval` f) <*> (`eval` x) <*> (`eval` y)) e 

,如果你有类似 “funcall” ...但我离题了。)

有大量关于应用函子,monads和箭头解析的文献;所有这些都有可能解决您的问题。阅读这些内容,看看你得到了什么。

+0

我对编程语言设计非常熟悉,对haskell和alex不太熟悉。感谢您提供的信息,但我已经知道所有这些。通过“不放全局状态”我的意思是不把它放入状态monad,而是有一些可变的状态。而且,“不要把我的词汇规则放入monad中”我的意思是我无法通过Alex的规则编写一个状态单元,事实证明,这实际上是可以实现的。你说的大部分内容对我来说都有点帮助,但是我仍然可以在#haskell的帮助下解决问题。无论如何感谢 – kamatsu

+1

布局几乎总是在词法分析器中完成,Python和haskell都是这样做的。 – kamatsu

+0

状态monad不是“可变状态”吗?尽管技术上不可变,但在读取(>> =)的源代码之前,您一定不会注意到这一点。 – jrockway