我如何使用Text.Parsec.Expr中的buildExpressionParser来解析这种语言? [英] How can I use buildExpressionParser from Text.Parsec.Expr to parse this language?

查看:153
本文介绍了我如何使用Text.Parsec.Expr中的buildExpressionParser来解析这种语言?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图使用buildExpressionParser来解析一种语言,而我几乎拥有它。感谢不支持Parsec.Expr重复的Prefix / Postfix操作符,以解决我的一个重大问题。

I've been trying to use buildExpressionParser to parse a language, and I almost have it. Thanks to Parsec.Expr repeated Prefix/Postfix operator not supported for solving one of my big problems.

这段代码展示了我最后一次遇到的难题:

This code snippet illustrates (what I hope to be) my last difficulty:

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]]

成功(并正确)解析 ,, 0 .. 0 。,0 .0 * 0 ,0 * 0 ;但它不能解析,。0 .0 * .0 。我可以看到为什么这两个不解析,但我不明白我可以如何更改解析器,以便没有任何成功更改,并解析两个失败。

This successfully (and correctly) parses ,,0, ..0, .,0, .0*0, and ,0*0; it cannot, however, parse ,.0 or .0*.0. I can see why those two don't parse, but I don't see how I can change the parser so that none of the successes change and the two failures parse.

解决这个问题的方法之一是将(fmap Lit digit)改成(fmap Lit Digit< |> expr) code>,但解析器会循环而不是错误。

One way of "solving" this would be to change (fmap Lit digit) to (fmap Lit Digit <|> expr), but then the parser would loop instead of erroring.

建议欢迎。

编辑:以下解析是关键:

The following parses are key:

> parseTest expr ".0*0"
A2 (B (Lit '0') (Lit '0'))

> parseTest expr ",0*0"
B (A1 (Lit '0')) (Lit '0')


推荐答案

要在一个关卡上获得'。'和',',您可以将它们一起对待:

To get '.' and ',' on a level you could treat them together:

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'))

编辑,这是以前显然不足的尝试

Edit, this was the earlier obviously inadequate attempt

 table =
   [  [prefix $ (char ',' >> return A1) <|> (char '.' >> return A2)]
   , [Infix   (char '*' >> return B) AssocNone]
   ]

这篇关于我如何使用Text.Parsec.Expr中的buildExpressionParser来解析这种语言?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆