如果您的意思是Text.Parsec.Token
identifier
,我不認爲這會很容易。 identifier
使用lexeme
定義:
identifier =
lexeme $ try $
do{ name <- ident
; if (isReservedName name)
then unexpected ("reserved word " ++ show name)
else return name
}
和lexeme
消耗空白:
lexeme p
= do{ x <- p; whiteSpace; return x }
這意味着由你從identifier
結果的時間,識別符的結束位置都將丟失。
我不認爲有一個優雅的解決方案。難看是的makeTokenParser
定義從Text.Parsec.Token
複製和更改其lexeme
定義,以便它不跳過空白。然後你就可以有這樣的:
myMakeTokenParser :: (Stream s m Char)
=> GenLanguageDef s u m -> GenTokenParser s u m
myMakeTokenParser languageDef
= TokenParser{ identifier = identifier
, reserved = reserved
...
lexeme p = p
...
}
lexer = myMakeTokenParser haskellDef
identifier' = identifier lexer
test = do
start <- getPosition
result <- identifier'
end <- getPosition
return (result, (start, end))
main = parseTest test "abc def "
> :main
("abc",((line 1, column 1),(line 1, column 4)))
當然,現在你必須要小心,因爲解析器不會空白跳過了。另一種方法是,使lexeme
記錄內解析器(例如identifier
)作爲「用戶狀態」的部分的端部的位置,然後跳過空白如常。然後您可以從用戶狀態中檢索結束位置。
不只是'start'加上'result'的長度? –
那麼,在這種情況下,是的。但是在更復雜的情況下(多行字符串或函數定義),計算結束位置將更加困難。 – antoyo