2009-10-03 34 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