我正在尝试为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代码如下:
module SecondAttempt where
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)
--- Proc definition
-- 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 | ε
--- Types
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
data Bexp = TRUE
| FALSE
| Neg Bexp
| And Bexp Bexp
| Le Aexp Aexp
| Eq Aexp Aexp
data Stm = Skip
| Ass Var Aexp
| Comp Stm Stm
| If Bexp Stm Stm
| While Bexp Stm
| Block DecV DecP Stm
| Call Pname
--- 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 ()
--- 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 = Ass <$ tok "Ass" <*> var <* tok ":=" <*> aexp
<|> Comp <$ tok "Comp" <*> stm <* tok ";" <*> stm
<|> Skip <$ tok "Skip"
<|> If <$ tok "If" <*> bexp <* tok "then" <*> stm <* tok "else" <*> stm
<|> While <$ tok "While" <*> bexp <* tok "do" <*> stm
<|> Block <$ tok "begin" <*> decv <*> decp <*> stm <* tok "end"
<|> Call <$ tok "call" <*> pname
num :: Parser Num
num = (some (oneOf ['0' .. '9']) >>= return . read) <* whitespace
var :: Parser Var
var = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\""
decv :: Parser DecV
decv = var <* tok ":=" <*> aexp <* tok ";" <*> decv
decp :: Parser DecP
decp = pname <* tok "is" <*> stm <* tok ";" <*> decp
pname :: Parser Pname
pname = tok "\"" *> some (noneOf ("\n\r\"")) <* tok "\""
true :: Bool
true = True
false :: Bool
false = False
我收到两个类型错误,每个错误都与我的decv和decp函数有关:
Couldn't match type ‘[Char]’ with ‘Aexp -> DecV -> DecV’
Expected type: ParsecT
Dec String Data.Functor.Identity.Identity (Aexp -> `DecV -> DecV)
Actual type: Parser Var
In the first argument of ‘(<*)’, namely ‘var’
In the first argument of ‘(<*>)’, namely ‘var <* tok ":="’
Couldn't match type ‘[Char]’ with ‘Stm -> DecP -> DecP’
Expected type: ParsecT
Dec String Data.Functor.Identity.Identity (Stm -> DecP -> DecP)
Actual type: Parser Pname
In the first argument of ‘(<*)’, namely ‘pname’
In the first argument of ‘(<*>)’, namely ‘pname <* tok "is"’
真的不知道怎么解决这个问题!
答案 0 :(得分:1)
问题是您没有正确地为列表(DecV
和DecP
)创建解析器。
对于DecV
,您需要先将var
和aexp
成对,然后再将其列为清单。
而不是:
decv :: Parser DecV
decv = var <* tok ":=" <*> aexp <* tok ";" <*> decv
decp :: Parser DecP
decp = pname <* tok "is" <*> stm <* tok ";" <*> decp
怎么样:
decv :: Parser DecV
decv = many ((,) <$> var <* tok ":=" <*> aexp <* tok ";")
decp :: Parser DecP
decp = many ((,) <$> pname <* tok "is" <*> stm <* tok ";")