Parsec has no default function to parse “any symbolic” string, but it can be added simply by defining an operator new token.
operator = do
c <- Tok.opStart emptyDef
cs <- many $ Tok.opLetter emptyDef
return (c:cs)
Using the expression parser we can extend our table of operators with the “binop” class of custom operators. Note that this will match any and all operators even at parse-time, even if there is no corresponding definition.
binops = [[binary "*" Ex.AssocLeft,
binary "/" Ex.AssocLeft]
,[binary "+" Ex.AssocLeft,
binary "-" Ex.AssocLeft]
expr :: Parser Expr
expr = Ex.buildExpressionParser (binops ++ [[binop]]) factor
The parser extension is straightforward and essentially a function definition with a few slight changes. Note that we capture the string value of the operator as given to us by the parser.
binarydef :: Parser Expr
binarydef = do
reserved "def"
reserved "binary"
o <- op
prec <- int
return $ BinaryDef o args body
Now for our binary operator, instead of failing with the presence of a binary operator not declared in our binops
list, we instead create a call to a named “binary” function with the operator name.
cgen (S.BinaryOp op a b) = do
case Map.lookup op binops of
Just f -> do
ca <- cgen a
cb <- cgen b
f ca cb