解析器不会在终端返回任何内容

时间:2017-04-13 09:00:40

标签: haskell

我正在尝试为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中,它就会挂起并且不会向终端打印任何内容。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

var = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\"" <* whitespace

根据此解析器,x看起来好像不是有效的变量名,因此x:=1不是赋值。

变量名称可以是"x"。尝试类似parseString "\"x\":=1"的内容,看看会发生什么。