Reputation: 21
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
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