

	ParseCalc.lhs

	Parsing expressions and commands

	(c) Simon Thompson, 1998

>	module ParseCalc where

>	import Types
>	import ParseLib

A parser for expressions					
 
 
The parser has three components, corresponding to the three	
clauses in the definition of the syntactic type.		
 
>       parseExpr :: Parse Char Expr
>       parseExpr = (litParse `alt` varParse) `alt` opExpParse
 
Spotting variables.						
 
>       varParse :: Parse Char Expr
>       varParse = spot isVar `build` Var

>       isVar :: Char -> Bool
>       isVar x = ('a' <= x && x <= 'z')
 
Parsing (fully bracketed) operator applications.		
 
>       opExpParse 
>         = (token '(' >*>
>            parseExpr >*>
>            spot isOp >*>
>            parseExpr >*>
>            token ')') 
>            `build` makeExpr

>       makeExpr (_,(e1,(bop,(e2,_)))) = Op (charToOp bop) e1 e2

>       isOp :: Char -> Bool
>       isOp ch = elem ch "+-*/%"

>       charToOp :: Char -> Ops
>       charToOp ch 
>	  = case ch of
>             '+' -> Add
>             '-' -> Sub
>             '*' -> Mul
>             '/' -> Div
>             '%' -> Mod

 
A number is a list of digits with an optional ~ at the front. 
 
>       litParse 
>         = ((optional (token '~')) >*>
>            (neList (spot isDigit)))
>            `build` (charListToExpr.join) 
>            where
>            join = uncurry (++)

Converting strings representing numbers into numbers
 
>       charListToExpr :: [Char] -> Expr
>       charListToExpr = Lit . charListToInt 

>       charListToInt :: [Char] -> Int
>	charListToInt ('~':rest) = - (charListToNat rest)
>	charListToInt other = charListToNat other

>       charListToNat :: [Char] -> Int
>	charListToNat [] = 0
>       charListToNat (ch:rest) 
>         = charToNat ch * 10^(length rest) + charListToNat rest

>	charToNat :: Char -> Int
>	charToNat ch 
>         | ord ch < ord '0' + 10        = ord ch - ord '0'
>         | otherwise                    = ord '0'						

 
The top-level parser						
 
>       topLevel :: Parse a b -> [a] -> b
>       topLevel p inp
>         = case results of
>             [] -> error "parse unsuccessful"
>             _  -> head results
>           where
>           results = [ found | (found,[]) <- p inp ]

A parse for the type of commands.						
 
>       parseCommand :: Parse Char Command
>       parseCommand 
>         = ((parseExpr `build` Eval)
>	    `alt`
>	    (((spot isVar) >*> 
>            (token ':') >*> 
>            parseExpr) `build` makeComm))
>            `alt`
>	     endOfInput Null

>	makeComm (v,(_,e)) = Assign v e

This is the function which gets used in a top-level interaction.....

>	calcLine :: String -> Command

>	calcLine = topLevel parseCommand
 


