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