Wazed
Wazed

Reputation: 21

Expression parser for unary operator

I was trying to make an expression parser for two operators out of which only ^ is postfix unary, so with an operand it would look like R^.

The problem is that whenever the operator ^ is encountered somewhere other than the end, it just stops there and returns whatever parsed successfully. It means "R;S;T^" parses successfully, but "R^;S;T^" stops at R. However, "(R^);S;T^" just works fine.

I took help from an online post which he used for unary minus but that is a prefix operator (for example -X). His original solution was giving errors at reservedOp2, so I modified it to reservedOp2 name = try (string name >> notFollowedBy (oneOf opChar)) and it produces the output mentioned above. I need it to work with or without parenthesis.

import Control.Applicative
import Text.ParserCombinators.Parsec hiding (many,optinal,(<|>))
import Text.ParserCombinators.Parsec.Expr
import Text.Parsec.Language (haskell)
import qualified Text.Parsec.Token as P
import Text.Parsec.String (Parser)

data RT = Comp RT RT        
        | Conv RT           
        | Var String
        deriving (Show)

whiteSpace = P.whiteSpace haskell
word = P.identifier haskell
parens = P.parens haskell
opChar = "^;"

reservedOp2 :: String -> CharParser st ()
reservedOp2 name = try (string name >> notFollowedBy (oneOf opChar) >> whiteSpace)


term = parens relexpr
       <|> Var <$> word
       <?> "term"

table = [ [postfix "^" Conv]
        , [binary ";" Comp AssocLeft]
        ]

prefix  name fun = Prefix  $ reservedOp2 name >> return fun
binary  name fun = Infix   $ reservedOp2 name >> return fun
postfix name fun = Postfix $ reservedOp2 name >> return fun

relexpr :: Parser RT
relexpr = buildExpressionParser table term <?> "expression"

Upvotes: 1

Views: 870

Answers (1)

Cactus
Cactus

Reputation: 27636

It fails to parse e.g. "R^;S" because postfix "^" Conv fails on notFollowedBy (oneOf opChar) (since '^' is followed by ';'). The fix is to remove ';' from opChar:

opChar = "^"

Or, even easier if you can just use reservedOp from haskell:

reservedOp2 = P.reservedOp haskell

Either of these changes fixes the parsing of your examples.

Upvotes: 1

Related Questions