我一直在尝试使用buildExpressionParser来解析一种语言,而我几乎拥有它.感谢Parsec.Expr重复的Prefix/Postfix运算符不支持解决我的一个大问题.
这段代码片段说明了(我希望是什么)我的最后一个难题:
import Text.Parsec.Expr
import Text.Parsec
data Expr = Lit Char | A1 Expr | A2 Expr | B Expr Expr
deriving (Show)
expr :: Parsec String () Expr
expr = buildExpressionParser table (fmap Lit digit)
prefix p = Prefix . chainl1 p $ return (.)
table =
[ [prefix $ char ',' >> return A1]
, [Infix (char '*' >> return B) AssocNone]
, [prefix $ char '.' >> return A2]]
Run Code Online (Sandbox Code Playgroud)
这成功地(并正确)解析,,0
,..0
,.,0
,.0*0
,和,0*0
; 但它不能解析,.0
或.0*.0
.我可以看到为什么这两个不解析,但我不知道如何更改解析器,以便没有任何成功改变,两个失败解析.
解决这个问题的一种方法是更改(fmap Lit digit)
为(fmap Lit Digit <|> expr)
,但解析器将循环而不是错误.
建议欢迎.
编辑:以下解析是关键:
> parseTest expr ".0*0"
A2 (B (Lit '0') (Lit '0'))
> parseTest expr ",0*0"
B (A1 (Lit '0')) (Lit '0')
Run Code Online (Sandbox Code Playgroud)
要得到 '.' 和','在一个级别上你可以一起对待它们:
import Text.Parsec.Expr
import Text.Parsec
data Expr = Lit Char | A1 Expr | A2 Expr | B Expr Expr
deriving (Show)
expr :: Parsec String () Expr
expr = buildExpressionParser table (fmap Lit digit)
prefix p = Prefix . chainl1 p $ return (.)
table =
[ [prefix $ (char ',' >> return A1) <|> (char '.' >> return A2)]
, [Infix (char '*' >> return B) AssocNone]
, [prefix $ (char ',' >> return A1)]
]
-- *Main> let f = parseTest expr
-- *Main> f ".,0"
-- A2 (A1 (Lit '0'))
-- *Main> f ".0*.0"
-- B (A2 (Lit '0')) (A2 (Lit '0'))
-- *Main> f ".0*,.0"
-- B (A2 (Lit '0')) (A1 (A2 (Lit '0')))
-- *Main> f ".,.0"
-- A2 (A1 (A2 (Lit '0')))
-- *Main> f ",.0"
-- A1 (A2 (Lit '0'))
Run Code Online (Sandbox Code Playgroud)
编辑,这是早先明显不足的尝试
table =
[ [prefix $ (char ',' >> return A1) <|> (char '.' >> return A2)]
, [Infix (char '*' >> return B) AssocNone]
]
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1376 次 |
最近记录: |