module AEParser where

import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Token 
import Text.ParserCombinators.Parsec.Language  
import Char

run :: Show a => Parser a -> String -> IO ()
run p input
        = let pp = do {r <- p; eof; return r}
          in case (parse pp "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x


-- -----------------------------------------------------------
--  Arithmetic Expression Parser in Parsec
-- -----------------------------------------------------------

-- E -> TH 
expr :: Parser [Int]
expr = do lt <- term
          le <- hexpr
          return (1:(lt++le))

-- H -> +TH | eps           
hexpr = do char '+'        
           lt <- term   
           le <- hexpr 
           return (2:lt++le)
        <|> return [3]

-- T -> FG
term = do lf <- factor   
          lt <- hterm               
          return (4:lf++lt)
       

-- G -> *FG | eps
hterm =  do char '*'    
            lf <- factor              
            lt <- hterm                
            return (5:lf++lt) 
         <|> return [6]

-- F -> (E) | a 
factor =  do char '('    
             le <- expr               
             char ')'      
             return (7:le) 
          <|> 
          do char 'a'     
             return [8]

-- ----------------------------------------------------
-- production of syntax tree
-- ----------------------------------------------------

data Expr = Plus Expr Expr | Mult Expr Expr | Factor
            | Empty 
            deriving Show
           
empty :: Expr -> Bool           
empty Empty = True
empty _     = False 

-- auxiliary function 
buildExpr :: (Expr -> Expr -> Expr) -> [Expr] -> Expr
buildExpr op []  = Empty
buildExpr op [e] = e
buildExpr op (e1:e2:es) = buildExpr op ((op e1 e2):es)


-- E -> TH 
expr3 :: Parser Expr
expr3 = do lt <- term3                  
           le <- hexpr3                
           return (buildExpr Plus (lt:le))

-- H -> +TH | eps
hexpr3 :: Parser [Expr] 
hexpr3 = (do c  <- char '+'  
             lt <- term3 
             le <- hexpr3  
             return (lt:le))
        <|>    
        return []

-- T -> FG
term3 :: Parser Expr
term3 = do lf <- factor3  
           lt <- hterm3 
           return (buildExpr Mult (lf:lt))


-- G -> *FG | eps
hterm3 :: Parser [Expr] 
hterm3 =  (do c  <- char '*'
              lf <- factor3                
              lt <- hterm3               
              return (lf:lt)) 
              <|> return []
            
-- F -> (E) | a 
factor3 :: Parser Expr
factor3 =   (do c  <- char '('  
                le <- expr3            
                c  <- char ')' 
                return le) <|> 
            (do c <- char 'a' 
                return Factor)



-- -----------------------------------------------------------
--  Using Parsec Expression Parser
-- -----------------------------------------------------------

lang    = makeTokenParser haskellStyle

aExpr :: Parser Expr
aExpr = buildExpressionParser operators factors


operators =
    [ [ op "*"  AssocLeft ]
    , [ op "+"  AssocLeft ]
    ]
    where
      op s assoc
             = Infix (do{ symbol lang s; return (\x y -> makeExpr s x y)} 
                         <?> "operator") assoc

makeExpr :: String -> Expr -> Expr -> Expr
makeExpr "+" x y = Plus x y
makeExpr "*" x y = Mult x y 
makeExpr _ _ _   = Empty

factors = choice [ parens lang aExpr
                  , variable
                 ]

variable = do{ char 'a'
             ; return Factor
             }
