Parsec has no default function to parse “any symbolic” string, but it can be added simply by defining an operator new token.

    1. operator = do
    2. c <- Tok.opStart emptyDef
    3. cs <- many $ Tok.opLetter emptyDef
    4. 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.

    1. binops = [[binary "*" Ex.AssocLeft,
    2. binary "/" Ex.AssocLeft]
    3. ,[binary "+" Ex.AssocLeft,
    4. binary "-" Ex.AssocLeft]
    5. expr :: Parser Expr
    6. 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.

    1. binarydef :: Parser Expr
    2. binarydef = do
    3. reserved "def"
    4. reserved "binary"
    5. o <- op
    6. prec <- int
    7. 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.

    1. cgen (S.BinaryOp op a b) = do
    2. case Map.lookup op binops of
    3. Just f -> do
    4. ca <- cgen a
    5. cb <- cgen b
    6. f ca cb