hw3: impl parser and interpreter
This commit is contained in:
@@ -140,16 +140,38 @@ boolP = do
|
|||||||
"false" -> BoolVal False
|
"false" -> BoolVal False
|
||||||
"skip" -> BoolVal False -- Treating the command 'skip' as a synonym for false, for ease of parsing
|
"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
|
-- 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.
|
-- This function will be useful for defining binary operations.
|
||||||
@@ -159,19 +181,52 @@ parenP = error "TBD"
|
|||||||
-- The first case is done for you.
|
-- The first case is done for you.
|
||||||
applyOp :: Binop -> Value -> Value -> Either ErrorMsg Value
|
applyOp :: Binop -> Value -> Value -> Either ErrorMsg Value
|
||||||
applyOp Plus (IntVal i) (IntVal j) = Right $ IntVal $ i + j
|
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
|
-- As with the applyOp method, the semantics for this function
|
||||||
-- should return Either values. Left <error msg> indicates an error,
|
-- should return Either values. Left <error msg> indicates an error,
|
||||||
-- whereas Right <something> indicates a successful execution.
|
-- whereas Right <something> indicates a successful execution.
|
||||||
evaluate :: Expression -> Store -> Either ErrorMsg (Value, Store)
|
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
|
evaluate (Op o e1 e2) s = do
|
||||||
(v1,s1) <- evaluate e1 s
|
(v1,s1) <- evaluate e1 s
|
||||||
(v2,s') <- evaluate e2 s1
|
(v2,s') <- evaluate e2 s1
|
||||||
v <- applyOp o v1 v2
|
v <- applyOp o v1 v2
|
||||||
return (v, s')
|
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
|
-- Evaluates a program with an initially empty state
|
||||||
|
|||||||
Reference in New Issue
Block a user