1
필자는 While 언어의 확장 버전 인 Proc 언어에 대한 파서를 작성하려고합니다.파서는 터미널에서 아무것도 반환하지 않습니다.
"/*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의 문법을 주어졌다, Pname, DecV 및 DecV는 변경할 수 없습니다. 내 하스켈 코드는 다음과 같습니다 :
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에로드되면, 그냥 달려과에 아무것도 출력하지 않습니다 터미널. 어떤 아이디어? x
이 파서에 따른 유효한 변수 이름이없는 것처럼
내가 맨 위에서 준 예제는 작동해야하는 것이므로, x를 잘못 정의하여 ""주위에서 만 작동하므로 내'var' 함수가 올바르지 않습니까? "parseString"\ "x \": = 1 "'을 시도하고 'Exception : 1 : 6 : \ n 예기치 않은'1 '\ n 추가 \"추가 \ ","Mult \ ", \"Sub \ ","N "또는 'V'\ n"' –
@datguywelbz 예, 파서는 x 주위에 따옴표가 필요합니다. 또한 상단에있는 예제와 대응하는 표현식 앞에 Add 등이 필요합니다. – chi