Skip to content

Instantly share code, notes, and snippets.

@morgaine
Last active October 11, 2016 17:41
Show Gist options
  • Save morgaine/7ab859f3429872419e0e4af57b97fba5 to your computer and use it in GitHub Desktop.
Save morgaine/7ab859f3429872419e0e4af57b97fba5 to your computer and use it in GitHub Desktop.
Brief example of expression parser in Haskell with Parsec
#! /usr/bin/runhaskell
--
-- FutureLearn Haskell Course Sep-Oct 2016
-- Lessons 4.6: Parsing Text Using Higher-Order Functions
-- Section: Expression parsers
--
module Main where
import Text.Printf
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language
lexer = P.makeTokenParser emptyDef
parens = P.parens lexer
reservedOp = P.reservedOp lexer
natural = P.natural lexer
expr = buildExpressionParser optable term <?> "expression"
term = parens expr
<|> natural
<?> "simple expression"
optable =
[ [prefix "-" negate, prefix "+" id ]
, [postfix "++" (+1)]
, [binary "*" (*) AssocLeft, binary "/" (div) AssocLeft ]
, [binary "+" (+) AssocLeft, binary "-" (-) AssocLeft ]
]
binary name fun assoc = Infix (do{ reservedOp name; return fun }) assoc
prefix name fun = Prefix (do{ reservedOp name; return fun })
postfix name fun = Postfix (do{ reservedOp name; return fun })
someStrings =
[ "2"
, "(2)"
, "(2+3)"
, "(2+3)*4"
, "(2+3)/4"
, "(2 + 3) * 4"
, "2+3*4"
, "2.5"
]
parseStrings :: [String] -> IO ()
parseStrings [] = do return ()
parseStrings (x:xs) = do
printf "Parser {expr} parsing \"%-25s ---> " $ x ++ "\""
parseTest expr x
putStrLn ""
parseStrings xs
main :: IO ()
main = do
parseStrings someStrings
@morgaine
Copy link
Author

morgaine commented Oct 11, 2016

Output:

$ runhaskell expr_ok.hs
Parser {expr} parsing "2"                         ---> 2
Parser {expr} parsing "(2)"                       ---> 2
Parser {expr} parsing "(2+3)"                     ---> 5
Parser {expr} parsing "(2+3)*4"                   ---> 20
Parser {expr} parsing "(2+3)/4"                   ---> 1
Parser {expr} parsing "(2 + 3) * 4"               ---> 20
Parser {expr} parsing "2+3*4"                     ---> 14
Parser {expr} parsing "2.5"                       ---> 2

This "_ok" gist shows successful expr parsing. Failing parse input is easily added to the someStrings list. Note that the final parse is in practice an undetected failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment