packages feed

Grempa-0.1.0: examples/Ex1SimpleExpr.hs

-- | Example 1: Parsing simple expressions of the form @"x*(x+x)+x"@ with the
--              correct precedence levels.

-- Needed for recursive do notation.
{-# LANGUAGE DoRec #-}
-- Needed for deriving 'Typeable'.
{-# LANGUAGE DeriveDataTypeable #-}

module Ex1SimpleExpr where

-- First import the Grempa grammar combinators.
import Data.Parser.Grempa.Grammar
-- The result datatype must be an instance of the 'Typeable' typeclass.
-- Fortunately, it is possible to derive an instance. Using the extension
-- above.
import Data.Typeable

-- | The result data structure.
data E = Plus  E E
       | Times E E
       | Var
  deriving (Show, Eq, Typeable)

-- | The type of the 'expr' function tells us that it is a grammar for a
--   language operating on lists of 'Char's returning an 'E' if the parsing
--   is successful.
expr :: Grammar Char E
expr = do
  -- Recursive do notation is used so that a rule defined before another rule
  -- can still use that other rule. This is not strictly necessary for all
  -- grammars, but for this one, it is.
  rec
    -- Here @e@ will be the name of a new rule in the grammar (@e@ for 
    -- expression).
    -- The semantic action to take when @e@ has been found is to build a result
    -- of type 'E' using the 'Plus' constructor. Since we're using '<#' before
    -- the '+', it means that the result from parsing that will not be applied
    -- to the 'Plus' constructor.
    e <- rule [ Plus  <@> e <# '+' <#> t
              -- An @e@ can also be a @t@ (term, defined below) and then we just
              -- want to return that result, because @t@ will also have results
              -- of type @E@. So just use the identity function.
              , id    <@> t
              ]
    -- Similar to @e@ but with the multiplication sign instead, using the
    -- 'Times' constructor to construct the result.
    t <- rule [ Times <@> t <# '*' <#> f
              -- A @t@ can also be an @f@ (factor).
              , id    <@> f
              ]
    -- An @f@ can either be an expression in parentheses, or a variable
    -- (written 'x' in the language). Notice the use of '<@' and '<#' when not
    -- using a symbol when constructing the result of the production.
    f <- rule [ id  <@ '(' <#> e <# ')'
              , Var <@ 'x'
              ]
  -- Lastly, we need to return the entry rule of the grammar.
  return e