views:

297

answers:

1
data Expr =  Var Char | Tall Int | Sum Expr Expr | Mult Expr Expr | Neg Expr | Let Expr Expr Expr
    deriving(Eq, Show) 

parseExpr :: String -> (Expr, String)

parseExpr ('*':'(':s) = (Mult x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr ('+':'(':s) = (Sum x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr (x : xs) | isDigit x = (Tall (digitToInt x), xs)
parseExpr (x:s) = (Var x,s) 
    where  x >= 'A' = True
     x <= 'Z' = True

My parser is lacking two things before it is complete. As from the datatype above its lacking "Neg Expr" and Let "Expr Expr Expr". The first part would be something like this:

parseExpr('-' 
parseExpr('l':'e':'t':x:'b':'e

As in the datatype, the Let expressions starts with let and takes in three Expr. I don't know how to write out these last functions. Any help at all will be very much appreciated.

I did ask another question here on SO about this, and here is the link for that question.


Here is an example:

parseProg "let X be 4 in let Y be *(2 , X) in let Z be +(Y , X) in
+(+(X , Y) , Z)"
Let (Var 'X') (Tall 4) (Let (Var 'Y') (Mult (Tall 2) (Var 'X')) (Let
(Var 'Z') (Sum (Var 'Y') (Var 'X')) (Sum (Sum (Var 'X') (Var 'Y')) (Var
'Z'))))
+1  A: 

The basic strategy for these parts of the expression would be the same as for the other operations, just that you don't have to parse two subexpressions, but one or three. For let it would look like this:

parseExpr ('l':'e':'t':s) = (Let x y z, s3)
    where (x, 'b':'e':s1) = parseExpr s
          (y, 'i':'n':s2) = parseExpr s1
          (z, s3)         = parseExpr s2

If a string starts with the letters l, e, t take the remaining string (s) and try to parse an expression from it. This results in an expression (x) and a remaining string. We expect that this remaining string starts with the letters b, e. Since this should be followed by another expression we give the rest of this string (s2) again to parseExpr to parse another expression. And so on.

The only problem with this is that we don't account for spaces that might separate these keywords like "let" and "be" from the surrounding expressions. The easy solution would be to require exactly one space before/after these keywords and change the patterns in parseExpr to explicitly include these, for example:

    where (x, ' ':'b':'e':' ':s1) = parseExpr s

More flexible would be to add a dropSpaces :: String -> String function that removes leading spaces and gets called in the appropriate places.

sth
Indeed, I have a function the remove the spaces. Filter function works just fine.
Algific