module List = ListLabels module Spl : sig type id = string type binop = | Plus | Minus | Times | Div type stm = | CompoundStm of stm * stm | AssignStm of id * exp | PrintStm of exp list and exp = | IdExp of id | NumExp of int | OpExp of exp * binop * exp | EseqExp of stm * exp val maxargs : stm -> int option (** Option because a program may not have any print statements at all. *) end = struct type id = string type binop = | Plus | Minus | Times | Div type stm = | CompoundStm of stm * stm | AssignStm of id * exp | PrintStm of exp list and exp = | IdExp of id | NumExp of int | OpExp of exp * binop * exp | EseqExp of stm * exp (* 01.p.1: Write ML function (maxargs : stm -> int) that tells the * maximum number of arguments of any print statement within any * subexpression of a given statement. For example, maxargs(prog) * is 2. *) let maxargs stm = let opt_max_update opt n = match opt with | None -> Some n | Some m -> Some (max m n) in let opt_max_merge a b = match a, b with | None , None -> None | None , b -> b | Some _, None -> a | Some _, Some n -> opt_max_update a n in let rec check_stm max_opt stm = match stm with | PrintStm exps -> List.fold_left exps ~init:(opt_max_update max_opt (List.length exps)) ~f:check_exp | AssignStm (_, e) -> check_exp max_opt e | CompoundStm (s1, s2) -> opt_max_merge (check_stm max_opt s1) (check_stm max_opt s2) and check_exp max_opt exp = match exp with | IdExp _ | NumExp _ -> max_opt | OpExp (e1, _, e2) -> opt_max_merge (check_exp max_opt e1) (check_exp max_opt e2) | EseqExp (s, e) -> opt_max_merge (check_stm max_opt s) (check_exp max_opt e) in check_stm None stm end let spl_prog_orig = (* a := 5 + 3; * b := (print(a, a - 1), 10 * a); * print(b) *) Spl.CompoundStm ( Spl.AssignStm ("a", Spl.OpExp (Spl.NumExp 5, Spl.Plus, Spl.NumExp 3)) , Spl.CompoundStm ( Spl.AssignStm ( "b" , Spl.EseqExp ( Spl.PrintStm [ Spl.IdExp "a" ; Spl.OpExp (Spl.IdExp "a", Spl.Minus, Spl.NumExp 1) ] , Spl.OpExp (Spl.NumExp 10, Spl.Times, Spl.IdExp "a") ) ) , Spl.PrintStm [Spl.IdExp "b"] ) ) let spl_prog_noprint = (* a := 5 + 3; * b := 10 * a *) Spl.CompoundStm ( Spl.AssignStm ("a", Spl.OpExp (Spl.NumExp 5, Spl.Plus, Spl.NumExp 3)) , Spl.AssignStm ("b", Spl.OpExp (Spl.NumExp 10, Spl.Times, Spl.IdExp "a")) ) let () = let string_of_maxargs int_opt = match int_opt with | Some n -> string_of_int n | None -> "N/A" in Printf.printf "maxargs : spl_prog_orig -> %s\n" (string_of_maxargs (Spl.maxargs spl_prog_orig)); Printf.printf "maxargs : spl_prog_noprint -> %s\n" (string_of_maxargs (Spl.maxargs spl_prog_noprint))