我对Haskell相对较新,主要编程背景来自OO语言。我正在尝试用解析器编写一个解释器来编写简单的编程语言。到目前为止,我的翻译处于一个我感到满意的状态,但我正在与解析器稍微挣扎。在Haskell中解析一个简单的解释器
下面是一段代码,我有问题
data IntExp
= IVar Var
| ICon Int
| Add IntExp IntExp
deriving (Read, Show)
whitespace = many1 (char ' ')
parseICon :: Parser IntExp
parseICon =
do x <- many (digit)
return (ICon (read x :: Int))
parseIVar :: Parser IntExp
parseIVar =
do x <- many (letter)
prime <- string "'" <|> string ""
return (IVar (x ++ prime))
parseIntExp :: Parser IntExp
parseIntExp =
do x <- try(parseICon)<|>try(parseIVar)<|>parseAdd
return x
parseAdd :: Parser IntExp
parseAdd =
do x <- parseIntExp
whitespace
string "+"
whitespace
y <- parseIntExp
return (Add x y)
runP :: Show a => Parser a -> String -> IO()
runP p input
= case parse p "" input of
Left err ->
do putStr "parse error at "
print err
Right x -> print x
语言稍微复杂一些,但这足以说明我的问题。
所以在IntExp类型中,ICon是一个常量,而IVar是一个变量,但现在出现问题。例如,这成功运行
runP parseAdd “5 + 5”
其给出(添加(图标5)(图标5)),这是预期的结果。高德使用时出现问题,而不是图标,例如
runP parseAdd“N + M”
这将导致程序出错了说有一个意外的“N”,其中数字预期。这导致我相信parseIntExp没有按照我的意图工作。我的意图是,它会尝试解析一个ICon,如果失败了,那么试着解析一个IVar等等。
因此,我认为问题存在于parseIntExp中,或者我缺少parseIVar和parseICon中的某些内容。
我希望我已经提供了足够的有关我的问题的信息,我已经清楚了。
感谢您给我的任何帮助!
camccann的回答非常好。一些更进一步的技巧...“Lexing”和空白处理通常通过Parsec.Token和Parsec.Language模块完成。这些词法分析器的风格是相当习惯的 - 如果你从http://legacy.cs.uu.nl/daan/parsec.html得到Parsec源代码,有一些简单的例子,例如Henk的代码,你可以从中复制代码。令牌模块还为您提供了更好的数字解析器,因此您可以避免使用许多数字然后读取。此外,适用于Parsec以获取(<$>)&(<*>)符号的实例仅适用于版本3.0和更高版本。 – 2010-11-06 09:04:51
非常感谢您的回答和建议。看起来它会解决我的问题,我应该能够改善我的编码风格。干杯! – Josh 2010-11-06 10:59:14
在'parseICon'示例中,我更喜欢'ICon。阅读=“多位数”选择,因为它更清晰。 – fuz 2010-11-07 11:43:25