--------------------------------------------------------------
-- Parsing arithmetic expressions using parser combinators  --
--------------------------------------------------------------

module AE_Parser where

infixr 6 &&&
infixr 4 |||

-- a = Tokentyp, b= Ergebnistyp
type Parser a b = [a] -> [(b,[a])]

-- basic parsers

result       :: b -> Parser a b
result x s    = [(x,s)]

zero         :: Parser a b
zero  s       = []

item         :: Parser a a
item  []      = []   -- failure
item  (a:as)  = [(a,as)]


-- parser combinators

bind         :: Parser a b -> (b-> Parser a c) -> Parser a c
bind p f s    = concat [f v inp | (v,inp) <- p s]

plus         :: Parser a b -> Parser a b -> Parser a b
plus p q s    = p s ++ q s

many         :: Parser a b -> Parser a [b]
many p        = (p &&& \x ->
                (many p) &&& \xs -> 
                result (x:xs)) ||| result []

option       :: Parser a b -> Parser a [b]
option  p     = (p &&& \x -> result [x]) ||| result []

-- as infix operators
(&&&) = bind
(|||) = plus



-- simple combinator parsers

sat          :: (a -> Bool) -> Parser a a
sat p         = item &&& (\ x -> if p x then result x else zero)

digit        :: Parser Char Char
digit         = sat isDigit 

lower        :: Parser Char Char
lower         = sat (\ x -> x >= 'a' && x <= 'z')

upper        :: Parser Char Char
upper         = sat (\ x -> x >= 'A' && x <= 'Z')

twolower     :: Parser Char String
twolower      = lower &&& \x ->
                lower &&& \y ->
                result [x,y]
                
letter       :: Parser Char Char
letter        = lower ||| upper

alphanum     :: Parser Char Char
alphanum      = letter ||| digit

tok          :: Eq a => [a] -> Parser a [a]
tok s cs      = loop s cs
                where loop []     cs            = [(s,cs)]
                      loop (s:ss) (c:cs) | s==c = loop ss cs
                      loop _      _             = []

----------------------------------------------------------
-- Translation of Grammar Rules into Parser Functions   --
----------------------------------------------------------

-- E -> TH 
expr :: Parser Char [Int]
expr = term                 &&& \lt -> 
       hexpr                &&& \le ->
       result (1:lt++le)

-- H -> +TH | eps 
hexpr = ((tok "+")            &&& \c -> 
         term                 &&& \lt -> 
         hexpr                &&& \le ->
         result (2:lt++le)) ||| result [3]

-- T -> FG
term = factor               &&& \lf -> 
       hterm                &&& \lt ->
       result (4:lf++lt)


-- G -> *FG | eps
hterm =  ((tok "*") &&& \c -> 
         factor               &&& \lf -> 
         hterm                &&& \lt ->
         result (5:lf++lt)) ||| result [6]

-- F -> (E) | a 
factor =   ((tok "(") &&& \c -> 
           expr      &&& \le -> 
           (tok ")") &&& \c ->
           result (7:le)) ||| (tok "a" &&& \ c -> result [8])


parseRD :: String -> [Int]
parseRD s = case expr s of
                 ((l,""):xs) -> l
                 _ -> error "syntax error in expression"



--------------------------------------------------------------
-- integration of look ahead sets improves error detection  --
--------------------------------------------------------------

lacontrol :: [String] -> String -> String
lacontrol la [] 
          | elem [] la = []
          | otherwise  = error ("Syntax error: expected: "++ show la 
				++" found: eof")
lacontrol la inp@(c:cs) 
          | elem [c] la = inp
          | otherwise   = error ("Syntax error: expected: "++ show la 
				++" found: "++ show inp)


-- combine parsers using look ahead information

lachoice :: (Show a,Eq a) 
	    => [[[a]]] -> [Parser a b] -> Parser a b
lachoice  las parsers inp
   | (null inp)     && (elem inp all_las) ||
     not (null inp) && (elem [head inp] all_las) 
               = findParser las parsers inp
   | otherwise = error ("Syntax error: expected: "++ show all_las 
			++" found: "++ show inp)
   where all_las = concat las


findParser :: (Show a, Eq a) 
			=> [[[a]]] -> [Parser a b] -> Parser a b
findParser (la:las)  (p:ps)  [] 
	| elem [] la  	= p []
        | otherwise   	= findParser las ps []
findParser (la:las)  (p:ps)  inp@(c:cs)   
       	| elem [c] la 	= p inp
       	| otherwise   	= findParser las ps inp
findParser [] ps inp 	= error "No Parser found - this case is not possible!"



-----------------------------------------------------
-- extend parser functions by control information  --
-----------------------------------------------------

-- E -> TH, Look-ahead: ["(","a"]
expr2 :: Parser Char [Int]
expr2 = (term2                 &&& \lt -> 
         hexpr2                &&& \le ->
         result (1:lt++le))
        .(lacontrol ["(","a"])

-- H -> +TH | eps, Look-ahead: ["+"] | [")",""]
hexpr2 = lachoice [["+"],[")",""]] 
                  [(tok "+")             &&& \c -> 
                   term2                 &&& \lt -> 
                   hexpr2                &&& \le ->
                   result (2:lt++le),result [3]] 

-- T -> FG, Look-ahead: ["(","a"]
term2 = (factor2               &&& \lf -> 
         hterm2                &&& \lt ->
         result (4:lf++lt)).(lacontrol ["(","a"])


-- G -> *FG | eps, Look-ahead: ["*"]   |   ["+",")",""]
hterm2 = lachoice [["*"],["+",")",""]]
           [ ((tok "*") &&& \c -> 
             factor2               &&& \lf -> 
             hterm2                &&& \lt ->
             result (5:lf++lt)), result [6]] 

-- F -> (E) | a, Look-ahead: ["("]  | ["a"] 
factor2 = lachoice [["("], ["a"]]
          [((tok "(") &&& \c -> 
           expr2      &&& \le -> 
           (tok ")") &&& \c ->
           result (7:le)), (tok "a" &&& \ c -> result [8])]


parseRDla :: String -> [Int]
parseRDla s = case expr2 s of
                 ((l,""):xs) -> l
                 ((l,cs):xs) -> error ("Syntax error: expected: eof found:"
					++show cs)
                 _ -> error "Syntax error: closing bracket missing"


--