Commit 7a19bf92 authored by Tadej Borovšak's avatar Tadej Borovšak
Browse files

Finish hw

parent bd9a889d
......@@ -4,17 +4,33 @@ import Imp_AbsSyntax
import Imp_State
evalAExp :: State -> AExp -> Integer
evalAExp _ (Num n) = n
evalAExp s (Loc l) = valof s l
evalAExp s (AOp (opName, e1, e2)) = op v1 v2
where v1 = evalAExp s e1
v2 = evalAExp s e2
op = case opName of
"+" -> (+)
"-" -> (-)
"*" -> (*)
_ -> error $ "Runtime error: unknow arithmetic op - " ++ opName
evalBExp :: State -> BExp -> Bool
evalBExp _ (Boolean b) = b
evalBExp s (BOp (opName, e1, e2)) = op v1 v2
where v1 = evalAExp s e1
v2 = evalAExp s e2
op = case opName of
"==" -> (==)
"<" -> (<)
_ -> error $ "Runtime error: unknown boolean op - " ++ opName
evalCom :: State -> Com -> State
--
-- [[DEFINE EVALUATION FUNCTIONS FOR:
--
-- * ARITHMETIC EXPRESSIONS
-- * BOOLEAN EXPRESSIONS
-- * COMMANDS
--
-- WITH THE TYPES SPECIFIED ABOVE]]
--
evalCom s (Assign (l, e)) = update s l $ evalAExp s e
evalCom s (Cond (e, c1, c2)) = evalCom s $ if evalBExp s e then c1 else c2
evalCom s (Seq (c1, c2)) = evalCom (evalCom s c1) c2
evalCom s Skip = s
evalCom s loop@(While (e, c)) =
if evalBExp s e
then evalCom (evalCom s c) loop
else s
......@@ -11,7 +11,6 @@ import Imp_Evaluator
runImp filename s = do
progtext <- readFile filename
let lexed = imp_lex progtext
parsed = imp_parse lexed
s' = evalCom s parsed
in print s'
print $ run progtext s
run progtext s = evalCom s $ imp_parse $ imp_lex progtext
-- vim: set syntax=alex autoindent
-- vim: set syntax=alex autoindent ts=4 sts=4 sw=4 expandtab :
{module Imp_Lex where }
{
module Imp_Lex
( Token(..)
, AlexPosn(AlexPn)
, pos
, imp_lex
) where
}
%wrapper "posn"
%wrapper "basic"
$digit = [0-9]
$alpha = [A-Za-z]
-- character classes
@number = $digit+
@ident = [$alpha _] [$alpha $digit _]*
@keywords = if | then | else | while | do | skip
@operations = \+ | \- | \* | \=\= | \<
@booleans = True | False
$digit = [0-9]
$alpha = [A-Za-z]
tokens :-
:-
$white+ ; -- whitespace
$white+ ; -- whitespace
\( | \) {\s -> SCOPE s} -- scope
\; {\s -> DELIM} -- command delimiter
\+ | \- | \* {\s -> OP s} -- arithmetic ops
\=\= | \< {\s -> OP s} -- boolean ops
\:\= {\s -> ASSIGN} -- assignment
if | then | else {\s -> KEYWORD s} -- if command
while | do {\s -> KEYWORD s} -- while command
skip {\s -> KEYWORD s} -- skip command
True | False {\s -> BOOL $ read s} -- boolean literals
$digit+ {\s -> NUM $ read s} -- numbers
$alpha [$alpha $digit \_]* {\s -> LOC s} -- locations
\( { \p _ -> LPAREN p } -- scope start
\) { \p _ -> RPAREN p } -- scope end
\; { \p _ -> DELIM p } -- command delimiter
\:\= { \p _ -> ASSIGN p } -- assignment
@operations { \p s -> BINOP p s } -- binary operations
@keywords { \p s -> KEYWORD p s } -- keywords
@number { \p s -> NUM p $ read s } -- integer literals
@booleans { \p s -> BOOL p $ read s } -- Boolean literals
@ident { \p s -> LOC p s } -- locations (variables)
. { \p s -> INVALID p s } -- invalid char
{
-- The Token type - the action for each lexical class has type String -> Token
data Token = SCOPE String
| DELIM
| OP String
| ASSIGN
| KEYWORD String
| BOOL Bool
| NUM Integer
| LOC String
| INVALID
data Token = LPAREN AlexPosn
| RPAREN AlexPosn
| DELIM AlexPosn
| ASSIGN AlexPosn
| BINOP AlexPosn String
| KEYWORD AlexPosn String
| NUM AlexPosn Integer
| BOOL AlexPosn Bool
| LOC AlexPosn String
| INVALID AlexPosn String
deriving Show
-- Position accessor
pos :: Token -> AlexPosn
pos (LPAREN p ) = p
pos (RPAREN p ) = p
pos (DELIM p ) = p
pos (ASSIGN p ) = p
pos (BINOP p _) = p
pos (KEYWORD p _) = p
pos (NUM p _) = p
pos (BOOL p _) = p
pos (LOC p _) = p
pos (INVALID p _) = p
-- Exported lexer
imp_lex = alexScanTokens
}
-- vim: set syntax=happy
-- vim: set syntax=happy autoindent ts=4 sts=4 sw=4 :
{
module Imp_Parse (imp_parse) where
{module Imp_Parse where
import Imp_Lex
import Imp_AbsSyntax
}
-- the parser implements a function
--
-- imp_parse :: [Token] -> Com
--
-- that converts a list of tokens to the abstract syntax tree of a command
%name imp_parse Com
%name imp_parse Prog
%tokentype { Token }
%error { parseError }
%token
--declaration of terminal symbols
-- tokens
%token '(' { LPAREN _ }
')' { RPAREN _ }
';' { DELIM _ }
assign { ASSIGN _ }
'+' { BINOP _ "+" }
'-' { BINOP _ "-" }
'*' { BINOP _ "*" }
'<' { BINOP _ "<" }
'~' { BINOP _ "==" }
if { KEYWORD _ "if" }
then { KEYWORD _ "then" }
else { KEYWORD _ "else" }
while { KEYWORD _ "while" }
do { KEYWORD _ "do" }
skip { KEYWORD _ "skip" }
num { NUM _ $$ }
bool { BOOL _ $$ }
loc { LOC _ $$ }
--
-- [[DECLARE YOUR TERMINAL SYMBOLS HERE]]
--
-- precedence and associativity declarations, lowest precedence first
--
-- [[MAKE PRECEDENCE AND ASSOCIATIVITY DECLARATIONS HERE]]
--
-- these are needed to break shift/reduce conflict in while/if statements
%nonassoc do then else
%right ';'
%nonassoc assign
%nonassoc '~' '<'
%left '+' '-'
%left '*'
%%
-- the grammar
Prog : {- empty -} { Skip }
| Command { $1 }
Command : skip { Skip }
| loc assign AExpr { Assign ($1, $3) }
| if BExpr then Command else Command { Cond ($2, $4, $6) }
| while BExpr do Command { While ($2, $4) }
| Command ';' Command { Seq ($1, $3) }
| '(' Command ')' { $2 }
AExpr : loc { Loc $1 }
| num { Num $1 }
| AExpr '+' AExpr { AOp ("+", $1, $3) }
| AExpr '-' AExpr { AOp ("-", $1, $3) }
| AExpr '*' AExpr { AOp ("*", $1, $3) }
--
-- [[DEFINE YOUR GRAMMAR AND ITS ACTIONS HERE]]
--
BExpr : bool { Boolean $1 }
| AExpr '<' AExpr { BOp ("<", $1, $3) }
| AExpr '~' AExpr { BOp ("==", $1, $3) }
{
parseError :: [Token] -> a
parseError _ = error "Imp parse error"
parseError ts = error ("Parse error at " ++ location ++ "\n")
where
location = case ts of
[] -> "end of file"
(t:_) -> "line " ++ show l ++ ", column " ++ show c
where AlexPn _ l c = pos t
}
Y := 1 ; while 0 < X do Y := Y * X ; X := X - 1
X := 6 ; Y := 1 ; while 0 < X do Y := Y * X ; X := X - 1
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment