我正在嘗試編寫簡單語言的解析器;基本上現在它有文字,ifs,功能應用程序,而不是其他。Parsec不會解析這個表達式,我不知道爲什麼
下面是我得到了代碼:
import Text.ParserCombinators.Parsec
import Control.Monad (liftM)
data Expr = Term Term
| Apply Expr Expr
| If Expr Expr Expr
deriving (Show)
data Term = Bool Bool
| Num Double
| String String
| Identifier String
| Parens Expr
deriving (Show)
sstring s = spaces >> string s
schar c = spaces >> char c
keyword k = do
kw <- try (sstring k)
notFollowedBy alphaNum
return kw
pBool :: Parser Bool
pBool = do
bool <- keyword "True" <|> keyword "False"
case bool of
"True" -> return True
"False" -> return False
pDouble :: Parser Double
pDouble = do
ds <- many1 digit
dot <- optionMaybe $ char '.'
case dot of
Nothing -> return $ read ds
_ -> do
ds' <- many1 digit
return $ read (ds ++ "." ++ ds')
pString :: Parser String
pString = do
char '"'
str <- many1 $ noneOf "\""
char '"'
return str
pIdentifier :: Parser String
pIdentifier = spaces >> many1 letter
pParens :: Parser Expr
pParens = do
schar '('
expr <- pExpr
schar ')'
return expr
pTerm :: Parser Term
pTerm = try (liftM Bool pBool)
<|> try (liftM Num pDouble)
<|> try (liftM String pString)
<|> try (liftM Identifier pIdentifier)
<|> try (liftM Parens pParens)
-- TODO: make this left-associative
pApply :: Parser Expr
pApply = do
term <- pTerm'
mApp <- spaces >> optionMaybe pApply
return $ case mApp of
Just app -> Apply term app
Nothing -> term
-- pulls "parens" expressions out of terms
pTerm' :: Parser Expr
pTerm' = do
term <- pTerm
case term of
Parens expr -> return expr
otherwise -> return $ Term term
pIf :: Parser Expr
pIf = do
keyword "if"
cond <- pExpr
keyword "then"
ifTrue <- pExpr
keyword "else"
ifFalse <- pExpr
return $ If cond ifTrue ifFalse
pExpr :: Parser Expr
pExpr = try pIf <|> pApply
test parser = parse parser ""
現在,如果我嘗試在ghci中解析一個單一的數字表達,一切都很好:
> test pExpr "1"
Right (Term (Num 1.0))
太好了!和許多其他的事情工作太:
> test pExpr "1.234"
Right (Term (Num 1.234))
> test pApply "neg 1"
Right (Apply (Term (Identifier "neg")) (Term (Num 1.0)))
> test pExpr "f g 1"
Right (Apply (Term (Identifier "f")) (Apply (Term (Identifier "g")) (Term (Num 1.0))))
但現在,如果我嘗試解析if
聲明,我得到一個錯誤:
> test pIf "if 1 then 2 else 3"
Left (line 1, column 4):
unexpected "1"
expecting space, "if", "True", "False", letter or "("
這沒有道理給我!我們來看看解析if語句的規則:
我們解析了一個"if"
關鍵字(沒問題)。然後對於下一個解析(1
),我們需要解析pExpr
,它本身可以是pIf
或pApply
。那麼這不是一個如果,所以我們嘗試應用,其本身嘗試pTerm'
,其中嘗試pTerm
,其中嘗試pBool
,失敗,然後pNum
,成功!然後pTerm
成功與Num 1.0
,所以pTerm'
成功與Term (Num 1.0)
,這意味着pExpr
成功與Term (Num 1.0)
,並且得到傳遞到cond
變量......對吧?好吧,顯然不是,因爲它失敗了!我不明白爲什麼它會在這裏失敗。
棒極了!這真是個壞蛋。我對這種應用風格很陌生;我得看看更多。 –