我正在尝试为Proc语言编写解析器,这是While语言的扩展版本。完成后,它应该能够输入如下:
"/*fac_loop (p.23)*/\ny:=1;\nwhile !(x=1) do (\n y:=y*x;\n x:=x-1\n)"
并生产:
(Comp (Ass "y" (N 1)) (While (Neg (Eq (V "x") (N 1))) (Comp (Ass "y"
(Mult (V "y") (V "x"))) (Ass "x" (Sub (V "x") (N 1))))))
我已经获得了Aexp,Bexp和Stm的语法以及我无法改变的Num,Var,Pname,DecV和DecV的类型。我的Haskell代码如下:
import System.IO
import Control.Monad
{-# LANGUAGE StandaloneDeriving #-}
import Text.Megaparsec
import Text.Megaparsec.String
import Data.List (intercalate)
import Prelude hiding (Num)
import qualified Prelude (Num)
-- S ::= x:=a
-- | skip
-- |S1 ;S2
-- | if b then S1 else S2
-- | while b do S
-- | begin Dv Dv S end
-- | call p
-- Dv ::= var x := a ; DV | ε
-- Dp ::= proc p is S ; DP | ε
type Num = Integer
type Var = String
type Pname = String
type DecV = [(Var,Aexp)]
type DecP = [(Pname,Stm)]
--- Data structures -------------------------------
data Aexp = N Num
| V Var
| Mult Aexp Aexp
| Add Aexp Aexp
| Sub Aexp Aexp
deriving (Show, Eq, Read)
data Bexp = TRUE
| FALSE
| Neg Bexp
| And Bexp Bexp
| Le Aexp Aexp
| Eq Aexp Aexp
deriving (Show, Eq, Read)
data Stm = Skip
| Ass Var Aexp
| Comp Stm Stm
| If Bexp Stm Stm
| While Bexp Stm
| Block DecV DecP Stm
| Call Pname
deriving (Show, Eq, Read)
--- Parser Preliminaries ----------------------------------------
cr :: Parser [Char]
cr = many (oneOf "\r\n")
tok :: String -> Parser String
tok t = string t <* whitespace
whitespace :: Parser ()
whitespace = many (oneOf " \t") *> pure ()
whileParser :: Parser Stm
whileParser = whitespace >> stm
--- Parser
aexp :: Parser Aexp
aexp = N <$ tok "N" <*> num
<|> V <$ tok "V" <*> var
<|> Mult <$ tok "Mult" <*> aexp <* tok "*" <*> aexp
<|> Add <$ tok "Add" <*> aexp <* tok "+" <*> aexp
<|> Sub <$ tok "Sub" <*> aexp <* tok "-" <*> aexp
bexp :: Parser Bexp
bexp = TRUE <$ tok "TRUE"
<|> FALSE <$ tok "FALSE"
<|> Neg <$ tok "Neg" <* tok "!" <*> bexp
<|> And <$ tok "And" <*> bexp <* tok "&" <*> bexp
<|> Le <$ tok "Le" <*> aexp <* tok "<=" <*> aexp
<|> Eq <$ tok "Eq" <*> aexp <* tok "=" <*> aexp
stm :: Parser Stm
stm = ifStm
<|> whileStm
<|> skipStm
<|> assStm
<|> compStm
<|> blockStm
<|> callStm
ifStm :: Parser Stm
ifStm =
do tok "if"
cond <- bexp
tok "then"
stm1 <- stm
tok "else"
stm2 <- stm
return $ If cond stm1 stm2
whileStm :: Parser Stm
whileStm =
do tok "while"
cond <- bexp
tok "do"
stm <- stm
return $ While cond stm
assStm :: Parser Stm
assStm =
do var <- var
tok ":="
expr <- aexp
return $ Ass var expr
skipStm :: Parser Stm
skipStm = tok "skip" >> return Skip
compStm :: Parser Stm
compStm =
do stm1 <- stm
tok ";"
stm2 <- stm
return $ Comp stm1 stm2
blockStm :: Parser Stm
blockStm =
do tok "begin"
decv <- decv
decp <- decp
stm <- stm
tok "end"
return $ Block decv decp stm
callStm :: Parser Stm
callStm =
do tok "call"
pname <- pname
return $ Call pname
num :: Parser Num
num = (some (oneOf ['0' .. '9']) >>= return . read) <* whitespace
var :: Parser Var
var = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\"" <* whitespace
decv :: Parser DecV
decv = many ((,) <$> var <* tok ":=" <*> aexp <* tok ";")
decp :: Parser DecP
decp = many ((,) <$> pname <* tok "is" <*> stm <* tok ";")
pname :: Parser Pname
pname = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\""
true :: Bool
true = True
false :: Bool
false = False
parseString :: String -> Stm
parseString str =
case parse whileParser "" str of
Left e -> error $ show (parseErrorPretty e)
Right r -> r
它编译得很好但是当我运行一个命令,如`parseString“x:= 1”一旦程序加载到ghci中,它就会挂起并且不会向终端打印任何内容。有什么想法吗?
答案 0 :(得分:0)
var = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\"" <* whitespace
根据此解析器,x
看起来好像不是有效的变量名,因此x:=1
不是赋值。
变量名称可以是"x"
。尝试类似parseString "\"x\":=1"
的内容,看看会发生什么。