diff --git a/hw3/WhileInterp.hs b/hw3/WhileInterp.hs index c322700..4612ecb 100644 --- a/hw3/WhileInterp.hs +++ b/hw3/WhileInterp.hs @@ -140,16 +140,38 @@ boolP = do "false" -> BoolVal False "skip" -> BoolVal False -- Treating the command 'skip' as a synonym for false, for ease of parsing -numberP = error "TBD" +numberP = do + n <- many1 digit + return $ IntVal (read n) -varP = error "TBD" +varP = do + x <- many1 letter + return $ Var x -ifP = error "TBD" +ifP = do + string "if" + e1 <- exprP + string "then" + e2 <- exprP + string "else" + e3 <- exprP + string "endif" + return $ If e1 e2 e3 -whileP = error "TBD" +whileP = do + string "while" + e1 <- exprP + string "do" + e2 <- exprP + string "endwhile" + return $ While e1 e2 -- An expression in parens, e.g. (9-5)*2 -parenP = error "TBD" +parenP = do + char '(' + e <- exprP + char ')' + return $ e -- This function will be useful for defining binary operations. @@ -159,19 +181,52 @@ parenP = error "TBD" -- The first case is done for you. applyOp :: Binop -> Value -> Value -> Either ErrorMsg Value applyOp Plus (IntVal i) (IntVal j) = Right $ IntVal $ i + j -applyOp _ _ _ = error "TBD" +applyOp Minus (IntVal i) (IntVal j) = Right $ IntVal $ i - j +applyOp Times (IntVal i) (IntVal j) = Right $ IntVal $ i * j +applyOp Divide (IntVal i) (IntVal j) = Right $ IntVal $ i `div` j +applyOp Gt (IntVal i) (IntVal j) = Right $ BoolVal $ i > j +applyOp Ge (IntVal i) (IntVal j) = Right $ BoolVal $ i >= j +applyOp Lt (IntVal i) (IntVal j) = Right $ BoolVal $ i < j +applyOp Le (IntVal i) (IntVal j) = Right $ BoolVal $ i <= j +applyOp _ v1 v2 = Left $ "Non-integer value pair: '" ++ show v1 ++ "', '" ++ show v2 ++ "' used in binary operation" -- As with the applyOp method, the semantics for this function -- should return Either values. Left indicates an error, -- whereas Right indicates a successful execution. evaluate :: Expression -> Store -> Either ErrorMsg (Value, Store) +evaluate (Val v) s = Right (v, s) +evaluate (Var x) s = case Map.lookup x s of + Just v -> Right (v, s) + Nothing -> Left $ "Variable " ++ x ++ " not found" +evaluate (Assign x e) s = do + (v,s') <- evaluate e s + return (v, Map.insert x v s') +evaluate (Sequence e1 e2) s = do + (_,s1) <- evaluate e1 s + (v2,s') <- evaluate e2 s1 + return (v2, s') evaluate (Op o e1 e2) s = do (v1,s1) <- evaluate e1 s (v2,s') <- evaluate e2 s1 v <- applyOp o v1 v2 return (v, s') -evaluate _ _ = error "TBD" +evaluate (If e1 e2 e3) s = do + (v1, s1) <- evaluate e1 s + (v', s') <- case v1 of + BoolVal True -> evaluate e2 s1 + BoolVal False -> evaluate e3 s1 + _ -> Left $ "Non-boolean value '" ++ show v1 ++ "' used as conditional" + return (v', s') +evaluate (While e1 e2) s = do + (v1,s1) <- evaluate e1 s + case v1 of + BoolVal True -> do + (_,s2) <- evaluate e2 s1 + (v', s') <- evaluate (While e1 e2) s2 + return (v', s') + BoolVal False -> Right $ (BoolVal False, s) + _ -> Left $ "Non-boolean value '" ++ show v1 ++ "' used as while condition" -- Evaluates a program with an initially empty state