【问题标题】:Parser does not return anything in terminal解析器在终端中不返回任何内容
【发布时间】:2017-04-13 09:00:39
【问题描述】:

我正在尝试为 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

它编译得很好,但是当我在 ghci 中加载程序后运行诸如 `parseString "x:=1" 之类的命令时,它只是挂起并且不会向终端打印任何内容。任何想法为什么?

【问题讨论】:

    标签: haskell


    【解决方案1】:
    var = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\"" <* whitespace
    

    根据此解析器,x 似乎不是有效的变量名,因此x:=1 不是赋值。

    变量名可以改为"x"。试试parseString "\"x\":=1" 之类的东西,看看会发生什么。

    【讨论】:

    • 我在顶部给出的例子是什么应该起作用,所以我是否错误地定义了 x 以便它只能在它周围使用 "" ,所以我的 var 函数不正确?我试过parseString "\"x\":=1" 并得到错误Exception: "1:6:\nunexpected '1'\nexpecting \"Add\", \"Mult\", \"Sub\", 'N', or 'V'\n"
    • @datguywelbz 是的,您的解析器需要 x 周围的引号。还有就是需要在表达式前面加上Add等,对应上面的例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 2019-05-16
    相关资源
    最近更新 更多