✨
This commit is contained in:
@ -258,13 +258,6 @@ let rec compileExp (e : TypedExp)
|
|||||||
let code2 = compileExp e2 vtable t2
|
let code2 = compileExp e2 vtable t2
|
||||||
code1 @ code2 @ [Mips.SUB (place,t1,t2)]
|
code1 @ code2 @ [Mips.SUB (place,t1,t2)]
|
||||||
|
|
||||||
(* TODO project task 1:
|
|
||||||
Look in `AbSyn.fs` for the expression constructors `Times`, ...
|
|
||||||
`Times` is very similar to `Plus`/`Minus`.
|
|
||||||
For `Divide`, you may ignore division by zero for a quick first
|
|
||||||
version, but remember to come back and clean it up later.
|
|
||||||
`Not` and `Negate` are simpler; you can use `Mips.XORI` for `Not`
|
|
||||||
*)
|
|
||||||
| Times (e1, e2, pos) ->
|
| Times (e1, e2, pos) ->
|
||||||
let t1 = newReg "times_L"
|
let t1 = newReg "times_L"
|
||||||
let t2 = newReg "times_R"
|
let t2 = newReg "times_R"
|
||||||
@ -397,13 +390,6 @@ let rec compileExp (e : TypedExp)
|
|||||||
let code2 = compileExp e2 vtable t2
|
let code2 = compileExp e2 vtable t2
|
||||||
code1 @ code2 @ [Mips.SLT (place,t1,t2)]
|
code1 @ code2 @ [Mips.SLT (place,t1,t2)]
|
||||||
|
|
||||||
(* TODO project task 1:
|
|
||||||
Look in `AbSyn.fs` for the expression constructors of `And` and `Or`.
|
|
||||||
The implementation of `And` and `Or` is more complicated than `Plus`
|
|
||||||
because you need to ensure the short-circuit semantics, e.g.,
|
|
||||||
in `e1 || e2` if the execution of `e1` will evaluate to `true` then
|
|
||||||
the code of `e2` must not be executed. Similarly for `And` (&&).
|
|
||||||
*)
|
|
||||||
| And (e1, e2, pos) ->
|
| And (e1, e2, pos) ->
|
||||||
let R0 = Mips.RS "0"
|
let R0 = Mips.RS "0"
|
||||||
let label = newLab "false"
|
let label = newLab "false"
|
||||||
@ -589,31 +575,6 @@ let rec compileExp (e : TypedExp)
|
|||||||
; Mips.LABEL loop_end
|
; Mips.LABEL loop_end
|
||||||
]
|
]
|
||||||
|
|
||||||
(* TODO project task 2:
|
|
||||||
`replicate (n, a)`
|
|
||||||
`filter (f, arr)`
|
|
||||||
`scan (f, ne, arr)`
|
|
||||||
Look in `AbSyn.fs` for the shape of expression constructors
|
|
||||||
`Replicate`, `Filter`, `Scan`.
|
|
||||||
General Hint: write down on a piece of paper the C-like pseudocode
|
|
||||||
for implementing them, then translate that to Mips pseudocode.
|
|
||||||
To allocate heap space for an array you may use `dynalloc` defined
|
|
||||||
above. For example, if `sz_reg` is a register containing an integer `n`,
|
|
||||||
and `ret_type` is the element-type of the to-be-allocated array, then
|
|
||||||
`dynalloc (sz_reg, arr_reg, ret_type)` will alocate enough space for
|
|
||||||
an n-element array of element-type `ret_type` (including the first
|
|
||||||
word that holds the length, and the necessary allignment padding), and
|
|
||||||
will place in register `arr_reg` the start address of the new array.
|
|
||||||
Since you need to allocate space for the result arrays of `Replicate`,
|
|
||||||
`Map` and `Scan`, then `arr_reg` should probably be `place` ...
|
|
||||||
|
|
||||||
`replicate(n,a)`: You should allocate a new (result) array, and execute a
|
|
||||||
loop of count `n`, in which you store the value hold into the register
|
|
||||||
corresponding to `a` into each memory location corresponding to an
|
|
||||||
element of the result array.
|
|
||||||
If `n` is less than `0` then remember to terminate the program with
|
|
||||||
an error -- see implementation of `iota`.
|
|
||||||
*)
|
|
||||||
| Replicate (n_exp, a_exp, a_type, (line, _)) ->
|
| Replicate (n_exp, a_exp, a_type, (line, _)) ->
|
||||||
let a_size = getElemSize a_type
|
let a_size = getElemSize a_type
|
||||||
|
|
||||||
@ -668,21 +629,6 @@ let rec compileExp (e : TypedExp)
|
|||||||
@ loop_replicate
|
@ loop_replicate
|
||||||
@ loop_footer
|
@ loop_footer
|
||||||
|
|
||||||
(* TODO project task 2: see also the comment to replicate.
|
|
||||||
(a) `filter(f, arr)`: has some similarity with the implementation of map.
|
|
||||||
(b) Use `applyFunArg` to call `f(a)` in a loop, for every element `a` of `arr`.
|
|
||||||
(c) If `f(a)` succeeds (result in the `true` value) then (and only then):
|
|
||||||
- set the next element of the result array to `a`, and
|
|
||||||
- increment a counter (initialized before the loop)
|
|
||||||
(d) It is useful to maintain two array iterators: one for the input array `arr`
|
|
||||||
and one for the result array. (The latter increases slower because
|
|
||||||
some of the elements of the input array are skipped because they fail
|
|
||||||
under the predicate).
|
|
||||||
(e) The last step (after the loop writing the elments of the result array)
|
|
||||||
is to update the logical size of the result array to the value of the
|
|
||||||
counter computed in step (c). You do this of course with a
|
|
||||||
`Mips.SW(counter_reg, place, 0)` instruction.
|
|
||||||
*)
|
|
||||||
| Filter (farg, arr_exp, a_type, pos) ->
|
| Filter (farg, arr_exp, a_type, pos) ->
|
||||||
let size_reg = newReg "size_reg" (* size of input/output array *)
|
let size_reg = newReg "size_reg" (* size of input/output array *)
|
||||||
let arr_reg = newReg "arr_reg" (* address of array *)
|
let arr_reg = newReg "arr_reg" (* address of array *)
|
||||||
@ -737,13 +683,6 @@ let rec compileExp (e : TypedExp)
|
|||||||
@ loop_map
|
@ loop_map
|
||||||
@ loop_footer
|
@ loop_footer
|
||||||
|
|
||||||
(* TODO project task 2: see also the comment to replicate.
|
|
||||||
`scan(f, ne, arr)`: you can inspire yourself from the implementation of
|
|
||||||
`reduce`, but in the case of `scan` you will need to also maintain
|
|
||||||
an iterator through the result array, and write the accumulator in
|
|
||||||
the current location of the result iterator at every iteration of
|
|
||||||
the loop.
|
|
||||||
*)
|
|
||||||
| Scan (farg, e_exp, arr_exp, a_type, pos) ->
|
| Scan (farg, e_exp, arr_exp, a_type, pos) ->
|
||||||
let size_reg = newReg "size_reg" (* size of input/output array *)
|
let size_reg = newReg "size_reg" (* size of input/output array *)
|
||||||
let arr_reg = newReg "arr_reg" (* address of array *)
|
let arr_reg = newReg "arr_reg" (* address of array *)
|
||||||
|
@ -134,16 +134,6 @@ let rec evalExp (e : UntypedExp, vtab : VarTable, ftab : FunTable) : Value =
|
|||||||
| (IntVal n1, IntVal n2) -> IntVal (n1-n2)
|
| (IntVal n1, IntVal n2) -> IntVal (n1-n2)
|
||||||
| (IntVal _, _) -> reportWrongType "right operand of -" Int res2 (expPos e2)
|
| (IntVal _, _) -> reportWrongType "right operand of -" Int res2 (expPos e2)
|
||||||
| (_, _) -> reportWrongType "left operand of -" Int res1 (expPos e1)
|
| (_, _) -> reportWrongType "left operand of -" Int res1 (expPos e1)
|
||||||
(* TODO: project task 1:
|
|
||||||
Look in `AbSyn.fs` for the arguments of the `Times`
|
|
||||||
(`Divide`,...) expression constructors.
|
|
||||||
Implementation similar to the cases of Plus/Minus.
|
|
||||||
Try to pattern match the code above.
|
|
||||||
For `Divide`, remember to check for attempts to divide by zero.
|
|
||||||
For `And`/`Or`: make sure to implement the short-circuit semantics,
|
|
||||||
e.g., `And (e1, e2, pos)` should not evaluate `e2` if `e1` already
|
|
||||||
evaluates to false.
|
|
||||||
*)
|
|
||||||
| Times(e1, e2, pos) ->
|
| Times(e1, e2, pos) ->
|
||||||
let res1 = evalExp(e1, vtab, ftab)
|
let res1 = evalExp(e1, vtab, ftab)
|
||||||
let res2 = evalExp(e2, vtab, ftab)
|
let res2 = evalExp(e2, vtab, ftab)
|
||||||
@ -276,15 +266,6 @@ let rec evalExp (e : UntypedExp, vtab : VarTable, ftab : FunTable) : Value =
|
|||||||
| ArrayVal (lst,tp1) ->
|
| ArrayVal (lst,tp1) ->
|
||||||
List.fold (fun acc x -> evalFunArg (farg, vtab, ftab, pos, [acc;x])) nel lst
|
List.fold (fun acc x -> evalFunArg (farg, vtab, ftab, pos, [acc;x])) nel lst
|
||||||
| otherwise -> reportNonArray "3rd argument of \"reduce\"" arr pos
|
| otherwise -> reportNonArray "3rd argument of \"reduce\"" arr pos
|
||||||
(* TODO project task 2: `replicate(n, a)`
|
|
||||||
Look in `AbSyn.fs` for the arguments of the `Replicate`
|
|
||||||
(`Map`,`Scan`) expression constructors.
|
|
||||||
- evaluate `n` then evaluate `a`,
|
|
||||||
- check that `n` evaluates to an integer value >= 0
|
|
||||||
- If so then create an array containing `n` replicas of
|
|
||||||
the value of `a`; otherwise raise an error (containing
|
|
||||||
a meaningful message).
|
|
||||||
*)
|
|
||||||
| Replicate (narg, aarg, _, pos) ->
|
| Replicate (narg, aarg, _, pos) ->
|
||||||
let n = evalExp(narg, vtab, ftab)
|
let n = evalExp(narg, vtab, ftab)
|
||||||
let a = evalExp(aarg, vtab, ftab)
|
let a = evalExp(aarg, vtab, ftab)
|
||||||
@ -294,14 +275,6 @@ let rec evalExp (e : UntypedExp, vtab : VarTable, ftab : FunTable) : Value =
|
|||||||
ArrayVal (a_array, valueType a)
|
ArrayVal (a_array, valueType a)
|
||||||
| _ -> reportWrongType "argument of \"Replicate\"" Int n pos
|
| _ -> reportWrongType "argument of \"Replicate\"" Int n pos
|
||||||
|
|
||||||
(* TODO project task 2: `filter(p, arr)`
|
|
||||||
pattern match the implementation of map:
|
|
||||||
- check that the function `p` result type (use `rtpFunArg`) is bool;
|
|
||||||
- evaluate `arr` and check that the (value) result corresponds to an array;
|
|
||||||
- use F# `List.filter` to keep only the elements `a` of `arr` which succeed
|
|
||||||
under predicate `p`, i.e., `p(a) = true`;
|
|
||||||
- create an `ArrayVal` from the (list) result of the previous step.
|
|
||||||
*)
|
|
||||||
| Filter (farg, arrayarg, _, pos) ->
|
| Filter (farg, arrayarg, _, pos) ->
|
||||||
let arr = evalExp(arrayarg, vtab, ftab)
|
let arr = evalExp(arrayarg, vtab, ftab)
|
||||||
match arr with
|
match arr with
|
||||||
@ -315,11 +288,6 @@ let rec evalExp (e : UntypedExp, vtab : VarTable, ftab : FunTable) : Value =
|
|||||||
ArrayVal (new_array, a_type)
|
ArrayVal (new_array, a_type)
|
||||||
| _ -> reportWrongType "argument of \"Filter\"" Int arr pos
|
| _ -> reportWrongType "argument of \"Filter\"" Int arr pos
|
||||||
|
|
||||||
|
|
||||||
(* TODO project task 2: `scan(f, ne, arr)`
|
|
||||||
Implementation similar to reduce, except that it produces an array
|
|
||||||
of the same type and length to the input array `arr`.
|
|
||||||
*)
|
|
||||||
| Scan (farg, ne, arrayexp, _, pos) ->
|
| Scan (farg, ne, arrayexp, _, pos) ->
|
||||||
let arr = evalExp(arrayexp, vtab, ftab)
|
let arr = evalExp(arrayexp, vtab, ftab)
|
||||||
let init_e = evalExp(ne, vtab, ftab)
|
let init_e = evalExp(ne, vtab, ftab)
|
||||||
|
@ -1,20 +1,3 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// TODO: project task 1
|
|
||||||
// implement lexer tokens for the new operators:
|
|
||||||
// multiplication (*), division (/), numerical negation (~),
|
|
||||||
// logical negation (not), logical and (&&), logical or (||),
|
|
||||||
// boolean literals (true, false), semicolon (;)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// TODO: project task 2
|
|
||||||
// implement lexer tokens (keywords) for replicate, filter, scan
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// TODO: project task 4
|
|
||||||
// implement the lexer tokens (keywords) for array comprehension
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
module Lexer
|
module Lexer
|
||||||
|
|
||||||
|
@ -19,23 +19,6 @@ let parse_error_rich =
|
|||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// TODO: Add new (lexer) token definitions:
|
|
||||||
//
|
|
||||||
// TODO: project task 1 :
|
|
||||||
// - multiplication (*), division (/), numerical negation (~),
|
|
||||||
// logical negation (not), logical and (&&), logical or (||),
|
|
||||||
// boolean literals (true, false)
|
|
||||||
// - add the required precedence and associativity rules for
|
|
||||||
// *, /, ~, not, &&, ||
|
|
||||||
// - generalize the syntax of let-expressions to allow
|
|
||||||
// multiple variable declarations
|
|
||||||
//
|
|
||||||
// TODO: project task 2: replicate, filter, scan
|
|
||||||
//
|
|
||||||
// TODO: project task 4: array comprehension
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
%token <int * Position> NUM
|
%token <int * Position> NUM
|
||||||
%token <char * Position> CHARLIT
|
%token <char * Position> CHARLIT
|
||||||
%token <string * Position> ID STRINGLIT
|
%token <string * Position> ID STRINGLIT
|
||||||
@ -68,7 +51,7 @@ let parse_error_rich =
|
|||||||
%type <AbSyn.UntypedExp> Exp
|
%type <AbSyn.UntypedExp> Exp
|
||||||
%type <AbSyn.UntypedExp list> Exps
|
%type <AbSyn.UntypedExp list> Exps
|
||||||
%type <AbSyn.UntypedFunArg> FunArg
|
%type <AbSyn.UntypedFunArg> FunArg
|
||||||
// TODO: Task 1(b): add any new nonterminals here
|
|
||||||
%type <AbSyn.UntypedExp> MultiLet
|
%type <AbSyn.UntypedExp> MultiLet
|
||||||
|
|
||||||
%%
|
%%
|
||||||
@ -106,11 +89,6 @@ BinOp : PLUS { (Lambda
|
|||||||
$1) ,$1))}
|
$1) ,$1))}
|
||||||
;
|
;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
|
||||||
// TODO: project tasks 1,2,4:
|
|
||||||
// add grammer rules for the new expressions
|
|
||||||
///////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
Exp : NUM { Constant (IntVal (fst $1), snd $1) }
|
Exp : NUM { Constant (IntVal (fst $1), snd $1) }
|
||||||
| CHARLIT { Constant (CharVal (fst $1), snd $1) }
|
| CHARLIT { Constant (CharVal (fst $1), snd $1) }
|
||||||
| ID { Var $1 }
|
| ID { Var $1 }
|
||||||
|
@ -125,10 +125,6 @@ and checkExp (ftab : FunTable)
|
|||||||
let (e1_dec, e2_dec) = checkBinOp ftab vtab (pos, Int, e1, e2)
|
let (e1_dec, e2_dec) = checkBinOp ftab vtab (pos, Int, e1, e2)
|
||||||
(Int, Minus (e1_dec, e2_dec, pos))
|
(Int, Minus (e1_dec, e2_dec, pos))
|
||||||
|
|
||||||
(* TODO project task 1:
|
|
||||||
Implement by pattern matching Plus/Minus above.
|
|
||||||
See `AbSyn.fs` for the expression constructors of `Times`, ...
|
|
||||||
*)
|
|
||||||
| Times (e1, e2, pos) ->
|
| Times (e1, e2, pos) ->
|
||||||
let (e1_dec, e2_dec) = checkBinOp ftab vtab (pos, Int, e1, e2)
|
let (e1_dec, e2_dec) = checkBinOp ftab vtab (pos, Int, e1, e2)
|
||||||
(Int, Times (e1_dec, e2_dec, pos))
|
(Int, Times (e1_dec, e2_dec, pos))
|
||||||
@ -294,16 +290,6 @@ and checkExp (ftab : FunTable)
|
|||||||
f_argres_type e_type pos
|
f_argres_type e_type pos
|
||||||
(f_argres_type, Reduce (f', e_dec, arr_dec, elem_type, pos))
|
(f_argres_type, Reduce (f', e_dec, arr_dec, elem_type, pos))
|
||||||
|
|
||||||
(* TODO project task 2:
|
|
||||||
See `AbSyn.fs` for the expression constructors of
|
|
||||||
`Replicate`, `Filter`, `Scan`.
|
|
||||||
|
|
||||||
Hints for `replicate(n, a)`:
|
|
||||||
- recursively type check `n` and `a`
|
|
||||||
- check that `n` has integer type
|
|
||||||
- assuming `a` is of type `t` the result type
|
|
||||||
of replicate is `[t]`
|
|
||||||
*)
|
|
||||||
| Replicate (n_exp, a_exp, _, pos) ->
|
| Replicate (n_exp, a_exp, _, pos) ->
|
||||||
let (n_t, n_dec) = checkExp ftab vtab n_exp
|
let (n_t, n_dec) = checkExp ftab vtab n_exp
|
||||||
let (a_t, a_dec) = checkExp ftab vtab a_exp
|
let (a_t, a_dec) = checkExp ftab vtab a_exp
|
||||||
@ -311,15 +297,6 @@ and checkExp (ftab : FunTable)
|
|||||||
(Array a_t, Replicate (n_dec, a_dec, a_t, pos))
|
(Array a_t, Replicate (n_dec, a_dec, a_t, pos))
|
||||||
else raise (MyError("parameter n not Int", pos))
|
else raise (MyError("parameter n not Int", pos))
|
||||||
|
|
||||||
(* TODO project task 2: Hint for `filter(f, arr)`
|
|
||||||
Look into the type-checking lecture slides for the type rule of `map`
|
|
||||||
and think of what needs to be changed for filter (?)
|
|
||||||
Use `checkFunArg` to get the signature of the function argument `f`.
|
|
||||||
Check that:
|
|
||||||
- `f` has type `ta -> Bool`
|
|
||||||
- `arr` should be of type `[ta]`
|
|
||||||
- the result of filter should have type `[tb]`
|
|
||||||
*)
|
|
||||||
| Filter (f, arr_exp, _, pos) ->
|
| Filter (f, arr_exp, _, pos) ->
|
||||||
let (arr_type, arr_exp_dec) = checkExp ftab vtab arr_exp
|
let (arr_type, arr_exp_dec) = checkExp ftab vtab arr_exp
|
||||||
let elem_type =
|
let elem_type =
|
||||||
@ -338,12 +315,6 @@ and checkExp (ftab : FunTable)
|
|||||||
|
|
||||||
(Array f_arg_type, Filter (f', arr_exp_dec, elem_type, pos))
|
(Array f_arg_type, Filter (f', arr_exp_dec, elem_type, pos))
|
||||||
|
|
||||||
(* TODO project task 2: `scan(f, ne, arr)`
|
|
||||||
Hint: Implementation is very similar to `reduce(f, ne, arr)`.
|
|
||||||
(The difference between `scan` and `reduce` is that
|
|
||||||
scan's return type is the same as the type of `arr`,
|
|
||||||
while reduce's return type is that of an element of `arr`).
|
|
||||||
*)
|
|
||||||
| Scan (f, e_exp, arr_exp, _, pos) ->
|
| Scan (f, e_exp, arr_exp, _, pos) ->
|
||||||
let (e_type , e_dec ) = checkExp ftab vtab e_exp
|
let (e_type , e_dec ) = checkExp ftab vtab e_exp
|
||||||
let (arr_type, arr_dec) = checkExp ftab vtab arr_exp
|
let (arr_type, arr_dec) = checkExp ftab vtab arr_exp
|
||||||
|
Reference in New Issue
Block a user