4

私は buildExpressionParser を使用して言語を解析しようとしてきましたが、ほとんどそれを持っています。Parsec.Exprのおかげで、私の大きな問題の 1 つを解決するためにサポートされていない 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]]

,,0これは、..0.,0.0*0、およびを正常に (そして正しく) 解析し,0*0ます。ただし、解析することはできませ,.0.0*.0。これらの 2 つが解析されない理由はわかりますが、パーサーを変更して、成功したものを変更せず、2 つの失敗を解析する方法がわかりません。

これを「解決」する 1 つの方法は、 に変更(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')
4

1 に答える 1

5

取得するため '。' および ',' を一緒に扱うことができるレベルで:

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

編集、これは以前の明らかに不十分な試みでした

 table =
   [  [prefix $ (char ',' >> return A1) <|> (char '.' >> return A2)]
   , [Infix   (char '*' >> return B) AssocNone]
   ]
于 2012-06-24T04:36:54.577 に答える