caml-urm
A OCaml module for manipulating unlimited register machines
main.ml (3474B)
1 open List 2 3 let usage () = 4 Printf.printf "USAGE: urm FILE [-i ITERS] [-RN=V...] [-RN...] \n"; 5 Printf.printf "See urm.1 for additional information\n" 6 7 let default_max_iters = 1073741824 8 9 (** Execute the program from [file] with initial register values given by 10 [regs] and the maximum number of allowed iterations set to [iters] *) 11 let main iters init_m regs_prints file = 12 let contents = really_input_string file (in_channel_length file) in 13 try 14 let program = Urm.parse contents in 15 match Urm.nexec iters program init_m with 16 | Some m -> 17 List.iter (fun n -> Printf.printf "R%d = %d\n" n (Urm.register m n)) 18 regs_prints 19 | None -> 20 Printf.eprintf 21 "ERROR: the input program did not halt after %d iterations\n" 22 iters; 23 Printf.eprintf "The input program may not halt\n"; 24 exit 1 25 with Urm.Syntax_error err -> Printf.eprintf "ERROR: %s\n" err 26 27 (** Parses the command-line arguments concerning registers. 28 returns [(regs_vals, regs_prints)], where [regs_vals] is the list of pairs 29 encoding the initial values of the machine, and [regs_prints] is the list 30 of registers that should be printed at the end of execution. *) 31 let parse_regs (regs : string list) : (int * int) list * int list = 32 let rec fail reg = 33 Printf.eprintf "ERROR: invalid arguments provided: %s\n" reg; 34 usage (); 35 exit 1 36 and f reg (acc_vals, acc_prints) = 37 if String.starts_with ~prefix:"-R" reg then 38 let reg' = String.sub reg 2 (String.length reg - 2) in 39 match String.split_on_char '=' reg' with 40 | [reg_n] -> 41 (match int_of_string_opt reg_n with 42 | Some reg_n -> (acc_vals, reg_n :: acc_prints) 43 | None -> fail reg) 44 | [ reg_n ; reg_val ] -> 45 (match (int_of_string_opt reg_n, int_of_string_opt reg_val) with 46 | (Some reg_n, Some reg_val) -> 47 ((reg_n, reg_val) :: acc_vals, acc_prints) 48 | _ -> fail reg) 49 | _ -> fail reg 50 else fail reg 51 in List.fold_right f regs ([], []) 52 53 (** Parses the [-i] command line argument *) 54 let parse_iters (iters_str : string) : int = 55 match int_of_string_opt iters_str with 56 | Some n when n > 0 -> 57 n 58 | Some n -> 59 Printf.eprintf 60 "ERROR: negative number of maximum iterations provided: %d\n" n; 61 Printf.eprintf "Expected a positive integers\n"; 62 usage (); 63 exit 1 64 | None -> 65 Printf.eprintf 66 "ERROR: invalid number of maximum iterations provided: '%s'\n" 67 iters_str; 68 Printf.eprintf "Expected a positive integers\n"; 69 usage (); 70 exit 1 71 72 (** Parses all command line arguments *) 73 let (iters, init_m, regs_prints, filepath) : int * Urm.t * int list * string = 74 match Array.to_list Sys.argv with 75 | _ :: file_path :: "-i" :: iters_str :: regs -> 76 let (reg_vals, reg_prints) = parse_regs regs in 77 (parse_iters iters_str, Urm.of_list reg_vals, reg_prints, file_path) 78 | _ :: file_path :: regs -> 79 let (reg_vals, reg_prints) = parse_regs regs in 80 (default_max_iters, Urm.of_list reg_vals, reg_prints, file_path) 81 | _ -> 82 Printf.eprintf "ERROR: not enought arguments provided\n"; 83 usage (); 84 exit 1 85 86 (** Try to open the file with the contents of the program *) 87 let file = 88 try 89 if Sys.is_directory filepath 90 then raise (Sys_error (Printf.sprintf "Is a directory: %s" filepath)) 91 else open_in filepath 92 with Sys_error err -> 93 Printf.eprintf "ERROR: %s\n" err; 94 exit 1 95 96 let () = main iters init_m regs_prints file 97