F# code, code below
If i = 1 the branch jumps to line 2, so the program prints 20, 21, 20, 21, 20, 21, . . . and does not
terminate.
If i = 2 the branch jumps to line 12, so the program prints 20, 21.
The file:
// Abstract syntax
type branchId = int
type expr =
| Num of int // integer
| Var of string // variable
| Op of string * expr * expr // e1 op e2
type stmt =
| Print of expr // print e;
| Assign of string * expr // x = e;
| Block of stmt list // block { stmt1; ...; stmtN }
| Loop of stmt list // loop { stmt1; ...; stmtN }
| Br of branchId // br i;
| BrIf of expr * branchId // if (e) br i;
// Two more examples
// block {
// x = 0
// loop {
// print x;
// x = x + 1;
// if (x < n) br 0;
// }
// }
let countTo n =
Block [
Assign ("x", Num 0)
Loop [
Print (Var "x")
Assign ("x", Op ("+", Var "x", Num 1))
BrIf (Op ("<", Var "x", Num n), 0)
]
]
// block {
// x = 10
// y = 0
// block {
// loop {
// if (x < 2) br 1;
// x = x - 2;
// y = y + 1;
// br 0;
// }
// }
// print y;
// }
let div2 =
Block [
Assign ("x", Num 10)
Assign ("y", Num 0)
Block [
Loop [
BrIf (Op ("<", Var "x", Num 2), 1)
Assign ("x", Op ("-", Var "x", Num 2))
Assign ("y", Op ("+", Var "y", Num 1))
Br 0
]
]
Print (Var "y")
]
// Prettyprinter
let paren b s = if b then "(" + s + ")" else s
let rec prettyExpr (prec : int) (e : expr) : string =
match e with
| Var x -> x
| Num i -> sprintf "%d" i
| Op (op, e1, e2) ->
let e1 = prettyExpr 1 e1
let e2 = prettyExpr 1 e2
sprintf "%s %s %s" e1 op e2 |> paren (0 < prec)
let rec prettyStmtI (indent : string) (stmt : stmt) : string =
let extraIndent = indent + " "
match stmt with
| Print e ->
let e = prettyExpr 1 e
sprintf "%sprint %s;" indent e
| Assign (x, e) ->
let e = prettyExpr 0 e
sprintf "%s%s = %s;" indent x e
| Block stmts ->
let stmts = prettyStmtsI extraIndent stmts
sprintf "%sblock {\n%s%s}" indent stmts indent
| Loop stmts ->
let stmts = prettyStmtsI extraIndent stmts
sprintf "%sloop {\n%s%s}" indent stmts indent
| Br i -> sprintf "%sbr %i;" indent i
| BrIf (e, i) ->
let e = prettyExpr 0 e
sprintf "%sif (%s) br %i;" indent e i
and prettyStmtsI (indent : string) (stmts : stmt list) : string =
List.map (fun stmt -> prettyStmtI indent stmt + "\n") stmts |> String.concat ""
let prettyStmt (stmt : stmt) : string =
prettyStmtI "" stmt
// Execution of statements
type naivestore = Map
let emptystore : Map = Map.empty
let getSto (store : naivestore) x = store.Item x
let setSto (store : naivestore) (k, v) = store.Add(k, v)
type result =
| Continue of naivestore
| Branch of branchId * naivestore
let rec eval e (store : naivestore) : int =
match e with
| Num i -> i
| Var x -> getSto store x
| Op (op, e1, e2) ->
let i1 = eval e1 store
let i2 = eval e2 store
match op with
| "*" -> i1 * i2
| "+" -> i1 + i2
| "-" -> i1 - i2
| "==" -> if i1 = i2 then 1 else 0
| "<" -> if i1 < i2 then 1 else 0
| _ -> failwith "unknown primitive"
let rec exec (stmt : stmt) (store : naivestore) : result =
match stmt with
| Print e ->
let v = eval e store
printfn "%d" v
C.
ICT Role in 21st Century Education & its Challenges.pptx
F# code, code below If i = 1 the branch jumps to line 2, so the pr.pdf
1. F# code, code below
If i = 1 the branch jumps to line 2, so the program prints 20, 21, 20, 21, 20, 21, . . . and does not
terminate.
If i = 2 the branch jumps to line 12, so the program prints 20, 21.
The file:
// Abstract syntax
type branchId = int
type expr =
| Num of int // integer
| Var of string // variable
| Op of string * expr * expr // e1 op e2
type stmt =
| Print of expr // print e;
| Assign of string * expr // x = e;
| Block of stmt list // block { stmt1; ...; stmtN }
| Loop of stmt list // loop { stmt1; ...; stmtN }
| Br of branchId // br i;
| BrIf of expr * branchId // if (e) br i;
// Two more examples
// block {
// x = 0
// loop {
// print x;
// x = x + 1;
// if (x < n) br 0;
// }
// }
let countTo n =
Block [
Assign ("x", Num 0)
Loop [
Print (Var "x")
Assign ("x", Op ("+", Var "x", Num 1))
2. BrIf (Op ("<", Var "x", Num n), 0)
]
]
// block {
// x = 10
// y = 0
// block {
// loop {
// if (x < 2) br 1;
// x = x - 2;
// y = y + 1;
// br 0;
// }
// }
// print y;
// }
let div2 =
Block [
Assign ("x", Num 10)
Assign ("y", Num 0)
Block [
Loop [
BrIf (Op ("<", Var "x", Num 2), 1)
Assign ("x", Op ("-", Var "x", Num 2))
Assign ("y", Op ("+", Var "y", Num 1))
Br 0
]
]
Print (Var "y")
]
// Prettyprinter
let paren b s = if b then "(" + s + ")" else s
let rec prettyExpr (prec : int) (e : expr) : string =
match e with
3. | Var x -> x
| Num i -> sprintf "%d" i
| Op (op, e1, e2) ->
let e1 = prettyExpr 1 e1
let e2 = prettyExpr 1 e2
sprintf "%s %s %s" e1 op e2 |> paren (0 < prec)
let rec prettyStmtI (indent : string) (stmt : stmt) : string =
let extraIndent = indent + " "
match stmt with
| Print e ->
let e = prettyExpr 1 e
sprintf "%sprint %s;" indent e
| Assign (x, e) ->
let e = prettyExpr 0 e
sprintf "%s%s = %s;" indent x e
| Block stmts ->
let stmts = prettyStmtsI extraIndent stmts
sprintf "%sblock {n%s%s}" indent stmts indent
| Loop stmts ->
let stmts = prettyStmtsI extraIndent stmts
sprintf "%sloop {n%s%s}" indent stmts indent
| Br i -> sprintf "%sbr %i;" indent i
| BrIf (e, i) ->
let e = prettyExpr 0 e
sprintf "%sif (%s) br %i;" indent e i
and prettyStmtsI (indent : string) (stmts : stmt list) : string =
List.map (fun stmt -> prettyStmtI indent stmt + "n") stmts |> String.concat ""
let prettyStmt (stmt : stmt) : string =
prettyStmtI "" stmt
// Execution of statements
type naivestore = Map
let emptystore : Map = Map.empty
let getSto (store : naivestore) x = store.Item x
let setSto (store : naivestore) (k, v) = store.Add(k, v)
4. type result =
| Continue of naivestore
| Branch of branchId * naivestore
let rec eval e (store : naivestore) : int =
match e with
| Num i -> i
| Var x -> getSto store x
| Op (op, e1, e2) ->
let i1 = eval e1 store
let i2 = eval e2 store
match op with
| "*" -> i1 * i2
| "+" -> i1 + i2
| "-" -> i1 - i2
| "==" -> if i1 = i2 then 1 else 0
| "<" -> if i1 < i2 then 1 else 0
| _ -> failwith "unknown primitive"
let rec exec (stmt : stmt) (store : naivestore) : result =
match stmt with
| Print e ->
let v = eval e store
printfn "%d" v
Continue store
| Assign (x, e) ->
let v = eval e store
let store = setSto store (x, v)
Continue store
| Block stmts ->
match execStmts stmts store with
| Continue store -> Continue store
| Branch (i, store) ->
if i = 0
then Continue store
5. else Branch (i - 1, store)
| Loop stmts ->
failwith "Not implemented"
| Br i -> Branch (i, store)
| BrIf (e, i) ->
let v = eval e store
if v = 0 then Continue store else Branch (i, store)
and execStmts (stmts : stmt list) (store : naivestore) : result =
match stmts with
| [] -> Continue store
| stmt::stmts ->
match exec stmt store with
| Continue store -> execStmts stmts store
| Branch (i, store) -> Branch (i, store)
let run (stmt : stmt) : unit =
match exec stmt emptystore with
| Continue _ -> ()
| Branch _ -> failwith "Invalid branch"
// Make an if statement
let makeIf (e : expr) (stmt1 : stmt) (stmt2 : stmt) : stmt =
failwith "Not implemented"
// Abstract syntax of a simple imperative language with if statements,
// and a function that converts to the language above (assuming makeIf
// is implemented correctly)
type sstmt =
| SPrint of expr // print e
| SAssign of string * expr // x = e
| SBlock of sstmt list // { stmt1; stmt2; ...; stmtN }
| SIf of expr * sstmt * sstmt // if (e) stmt stmt
let rec convert (stmt : sstmt) : stmt =
match stmt with
| SPrint e -> Print e
6. | SAssign (x, e) -> Assign (x, e)
| SBlock stmts -> Block (List.map convert stmts)
| SIf (e, stmt1, stmt2) -> makeIf e (convert stmt1) (convert stmt2)
Here are tests for the question:
// block {
// x = n;
// y = 0;
// loop {
// z = x;
// loop {
// if (z < 1) br 2;
// y = y + 1;
// z = z - 1;
// if (0 < z) br 0;
// }
// x = x - 1;
// print y;
// br 0;
// }
// print z;
// }
let triangle n =
Block [
Assign ("x", Num n)
Assign ("y", Num 0)
Loop [
Assign ("z", Var "x")
Loop [
BrIf (Op ("<", Var "z", Num 1), 2)
Assign ("y", Op ("+", Var "y", Num 1))
Assign ("z", Op ("-", Var "z", Num 1))
BrIf (Op ("<", Num 0, Var "z"), 0)
]
Assign ("x", Op ("-", Var "x", Num 1))
Print (Var "y")
7. Br 0
]
Print (Var "z")
]
// > run (countTo 0);;
// 0
// val it: unit = ()
// > run (countTo 3);;
// 0
// 1
// 2
// val it: unit = ()
// > run (countTo 8);;
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// val it: unit = ()
// > run div2;;
// 5
// val it: unit = ()
// > run (triangle 2);;
// 2
// 3
// val it: unit = ()
// > run (triangle 6);;
// 6
// 11
// 15
// 18
// 20
8. // 21
// val it: unit = ()
let s1 = SIf (Num 1, SPrint (Num 10), SPrint (Num 20))
let s2 = SIf (Num 0, SPrint (Num 10), SPrint (Num 20))
let s3 = SBlock [SAssign ("x", Num 10); SIf (Var "x", SPrint (Num 100), SBlock [])]
let s4 n =
SBlock [
SAssign ("x", Num n);
SIf (Op ("<", Num 0, Var "x"), SBlock [
SPrint (Num 0);
SIf (Op ("<", Num 5, Var "x"), SPrint (Num 5), SPrint (Var "x"))
],
SBlock [
SAssign ("x", Num 100)
SPrint (Var "x")
])
]
// The following test makeIf
// > run (convert s1);;
// 10
// val it: unit = ()
// > run (convert s2);;
// 20
// val it: unit = ()
// > run (convert s3);;
// 100
// val it: unit = ()
// > run (convert (s4 -1));;
// 100
// val it: unit = ()
// > run (convert (s4 1));;
// 0
9. // 1
// val it: unit = ()
// > run (convert (s4 10));;
// 0
// 5
// val it: unit = () Assignment4.fs contains a simple imperative language with WebAssembly-like
control flow involving blocks and branch statements. The statement br i means branch to the i th,
where blocks are counted from the innermost to the outermost. The 0th block is the block that
directly contains the branch statement, and the (i+1) th block is the block that directly contains
the i th block. There are two kinds of block: simple blocks (block in concrete syntax) and loops
(loop in concrete syntax). They differ in how they behave as branch targets: - If the target of a
branch is a simple block, then control jumps to the end of the block, so that the next statement
executed is (lexically) after the block. - If the target of a branch is a loop, then control jumps to
the beginning of the loop. At the end of a block of either kind, if there is no branch, then the next
statement executed is the next one that appears lexically. For an example, consider what the
branch in the following program will do when program is executed.
123456789101112block{loop{print20;block{block{print21;}bri;loop{print22;}}print23;}print24
;
(i) The function exec executes a statement, given a store. The result is Branch (i, sto) if execution
should branch to the ith block, and Continue sto otherwise. In both cases, sto is the new store.
Implement the Loop case of exec. You should use a recursive call to exec to handle a branch to
the beginning of the loop. ii) There are no if statements except for conditional branches, but
conditional branches are enough to implement if. Implement makeIf : expr stmt stmt stmt so
that makeIf e stmt1 stmt2 is a statement that behaves like stmt1 if e is non-zero and stmt2
otherwise. Your function should not inspect e, stmt1 or stmt2, and it should not use Loop.