高阶的Parser:可变运算优先级
如果需要更flex的运算优先级可咋整?
怕是要把这个标注运算优先级的Optable当做参数,一级一级的传下去了。。。
module ParserImpl where
import AST
import Text.ParserCombinators.ReadP as P
import Data.Char
import Control.Applicative
-- do not change the type!
parseStringTerm :: OpTable -> String -> Either ErrMsg Term
parseStringTerm table str = let flist = tabterms table []
fstTerm = head flist
term = pTerm fstTerm
result = parsefTerms term str
in result
parseStringCmds :: OpTable -> String -> Either ErrMsg [Cmd]
parseStringCmds table str = let flist = tabterms table []
term = head flist
cmds = pCmds (pTerm term)
result = parsefCmds cmds str
in result
-- start parser --
opCollect :: [FName] -> ReadP (Term -> Term -> Term)
opCollect [fname] = do
_ <- symbol fname
return (\expr1 expr2 -> TFun fname [expr1,expr2])
opCollect (fname:flist) = let
a = opCollect [fname]
b = opCollect flist
in (a +++ b)
tabterms :: OpTable -> [ReadP Term] -> [ReadP Term]
tabterms (OpTable [(fix,flist)]) topTerm =
let fOterm = opCollect flist
in case fix of
FRight -> case topTerm of
[] -> let a = (chainr1 basicTerm fOterm)
b = pbasicTerm a
c = (chainr1 b fOterm)
d = pbasicTerm c
in [d]
[tt] -> let a = (chainr1 tt fOterm)
b = pbasicTerm a
c = (chainr1 b fOterm)
d = pbasicTerm c
in [d]
_ -> case topTerm of
[] -> let a = (chainl1 basicTerm fOterm)
b = pbasicTerm a
c = (chainl1 b fOterm)
d = pbasicTerm c
in [d]
[tt] -> let a = (chainl1 tt fOterm)
b = pbasicTerm a
c = (chainl1 b fOterm)
d = pbasicTerm c
in [d]
tabterms (OpTable ((fix,fnlist) : flist)) topTerm =
case topTerm of
[] -> let fOterm = opCollect fnlist
alist = (tabterms (OpTable flist) [])
atop = head alist
blist = (tabterms (OpTable flist) [pbasicTerm atop])
btop = pTerm (head blist)
ct = pTerm (chainr1 btop fOterm)
in case fix of
FRight -> [pTerm (chainr1 ct fOterm)] ++ blist
_ -> [pTerm (chainl1 ct fOterm)] ++ blist
[tt] -> let fOterm = opCollect fnlist
alist = (tabterms (OpTable flist) [tt])
atop = pTerm (head alist)
in case fix of
FRight -> [pTerm (chainr1 atop fOterm)] ++ alist
_ -> [pTerm (chainl1 atop fOterm)] ++ alist
parsefTerms :: ReadP Term -> String -> Either ErrMsg Term
parsefTerms fterm str =
case null (readP_to_S fterm str) of
True -> Left (show (readP_to_S fterm str))
False -> case [x | x <- readP_to_S fterm str,snd x == ""] of
[] -> Left (show (readP_to_S fterm str))
legalstr -> Right (fst (head legalstr))
parsefCmds :: ReadP [Cmd] -> String -> Either ErrMsg [Cmd]
parsefCmds cmds str =
case null (readP_to_S cmds str) of
True -> Left (show (readP_to_S cmds str))
False -> case [x | x <- readP_to_S cmds str,snd x == ""] of
[] -> Left (show (readP_to_S cmds str))
legalstr -> Right (fst (head legalstr))
symbol :: String -> ReadP String
symbol s = token $ string s
token :: ReadP a -> ReadP a
token p = do
skipSpaces
a <- p
skipSpaces
return a
pVName :: ReadP Term
pVName = do
fist <- satisfy isLetter
send <- munch (\x -> isLetter x || isDigit x)
return (TVar (fist : send))
pFName :: ReadP FName
pFName = do
fist <- satisfy isLetter
send <- munch (\x -> isLetter x || isDigit x)
return (fist : send)
pPName :: ReadP PName
pPName = do
fist <- satisfy isLetter
send <- munch (\x -> isLetter x || isDigit x)
return (fist : send)
pNumber :: ReadP Term
pNumber = do
sym <- option ' ' (char '~')
number <- munch1 isDigit
case sym of
'~' -> return (TNum (read ('-' : number)))
_ -> return(TNum (read number))
pFun :: ReadP Term -> ReadP Term
pFun term = (do
fname <- token pFName
_ <- symbol "("
terms <- token (pTerms term)
_ <- symbol ")"
return (TFun fname terms))
<|> (do
fname <- token pFName
_ <- symbol "("
_ <- symbol ")"
return (TFun fname []))
pbasicTerm :: ReadP Term -> ReadP Term
pbasicTerm term = (do
_ <- symbol "("
a <- token term
_ <- symbol ")"
return a) <|> (pFun term) <|> term <|> basicTerm
pTerm :: ReadP Term -> ReadP Term
pTerm term = (do
_ <- symbol "("
a <- token term
_ <- symbol ")"
return a) <|> (pFun term) <|> term
basicTerm :: ReadP Term
basicTerm = token pNumber
<|> token pVName
pTerms :: ReadP Term -> ReadP [Term]
pTerms term = (pCommaTerm term)
<|> (do
a <- token term
return [a])
pCommaTerm :: ReadP Term -> ReadP [Term]
pCommaTerm term = do
a <- token term
com <- token (pComTerHelper term)
return (a : com)
pComTerHelper :: ReadP Term -> ReadP [Term]
pComTerHelper term = (do
_ <- symbol ","
pCommaTerm term) <|>
(do
_ <- symbol ","
a <- token term
return [a])
pCond :: ReadP Term -> ReadP Cond
pCond term = (do -- one termz empty
name <- token pPName
_ <- symbol "("
_ <- symbol ")"
return (Cond name [] []))
<|> (do -- one termz not empty
name <- token pPName
_ <- symbol "("
terms <- token (pTerms term)
_ <- symbol ")"
return (Cond name terms []))
<|> (do -- two termz(empty) and terms
name <- token pPName
_ <- symbol "("
_ <- symbol ";"
terms <- token (pTerms term)
_ <- symbol ")"
return (Cond name [] terms))
<|> (do -- two termz(not empty) and terms
name <- token pPName
_ <- symbol "("
term1 <- token (pTerms term)
_ <- symbol ";"
term2 <- token (pTerms term)
_ <- symbol ")"
return (Cond name term1 term2))
pConds :: ReadP Term -> ReadP [Cond]
pConds term = (pCommaConds term)
<|> (do
a <- token (pCond term)
return [a])
pCommaConds :: ReadP Term -> ReadP [Cond]
pCommaConds term = do
a <- token (pCond term)
com <- token (pComConHelper term)
return (a : com)
pComConHelper :: ReadP Term -> ReadP [Cond]
pComConHelper term = (do
_ <- symbol ","
pCommaConds term) <|>
(do
_ <- symbol ","
a <- token (pCond term)
return [a])
pRule :: ReadP Term -> ReadP Rule
pRule term = (do
term1 <- token term
_ <- symbol "="
term2 <- token term
_ <- symbol "."
return (Rule term1 term2 []))
<|> (do
term1 <- token term
_ <- symbol "="
term2 <- token term
_ <- symbol "|"
cons <- token (pConds term)
_ <- symbol "."
return (Rule term1 term2 cons))
pCmd :: ReadP Term -> ReadP Cmd
pCmd term = (do
rule <- token (pRule term)
return (CRule rule))
<|> (do
t <- token term
_ <- symbol "?"
return (CQuery t False))
<|> (do
t <- token term
_ <- symbol "??"
return (CQuery t True))
pCmds :: ReadP Term -> ReadP [Cmd]
pCmds term = (do
a <- token (pCmd term)
as <- token (pCmds term)
return (a : as))
<|> (do
a <- token (pCmd term)
return [a])

浙公网安备 33010602011771号