caml-urm
A OCaml module for manipulating unlimited register machines
- Commit
- 4da5a6d6d4b15412cba9732ea48bda6c1c75f1f0
- Parent
- 47dc65a881e96aa5061037a9ce1ca84183b736dc
- Author
- Pablo <pablo-escobar@riseup.net>
- Date
Changed the command line paramenters
Also introduced the Urm.of_list function to help parsing of the command line arguments
Diffstat
5 files changed, 97 insertions, 81 deletions
Status |
File Name |
N° Changes |
Insertions |
Deletions |
Modified |
docs.pdf |
0 |
0 |
0 |
Modified |
main.ml |
141 |
69 |
72 |
Modified |
urm.1 |
27 |
19 |
8 |
Modified |
urm.ml |
4 |
4 |
0 |
Modified |
urm.mli |
6 |
5 |
1 |
diff --git a/main.ml b/main.ml
@@ -1,89 +1,86 @@
open List
let usage () =
- Printf.printf "USAGE: urm [-i ITERS] REGISTERS FILE\n";
+ Printf.printf "USAGE: urm FILE [-i ITERS] [-RN=V...] [-RN...] \n";
Printf.printf "See urm.1 for additional information\n"
let default_max_iters = 1000
-(** An equivalent to Haskell's [sequence] *)
-let sequence (xs : 'a option list) : 'a list option =
- let f x acc = Option.bind x (fun x -> Option.map (List.cons x) acc)
- in List.fold_right f xs (Some [])
-
(** Execute the program from [file] with initial register values given by
[regs] and the maximum number of allowed iterations set to [iters] *)
-let main iters regs file =
+let main iters init_m regs_prints file =
let contents = really_input_string file (in_channel_length file) in
try
- let program = Urm.parse contents
- and regs_fn i = if i < Array.length regs then regs.(i) else 0
- in
- match Urm.nexec iters program (Urm.of_registers regs_fn) with
- | Some m ->
- let regs_strs =
- Urm.register m
- |> List.init (Array.length regs)
- |> List.map (Printf.sprintf "%d")
- in Printf.printf "%s\n" (String.concat " " regs_strs)
- | None ->
- Printf.eprintf
- "ERROR: the input program did not halt after %d iterations\n"
- iters;
- Printf.eprintf "The input program may not halt\n";
- exit 1
- with Urm.Syntax_error err -> Printf.eprintf "ERROR: %s\n" err
-
-
-(** Initial parsing of the command-line arguments: get the strings out *)
-let (iters, regs_str, filepath) : int * string * string =
- let parse_iters iters_str =
- match int_of_string_opt iters_str with
- | Some n when n > 0 ->
- n
- | Some n ->
- Printf.eprintf
- "ERROR: negative number of maximum iterations provided: %d\n" n;
- Printf.eprintf "Expected a positive integers\n";
- usage ();
- exit 1
+ let program = Urm.parse contents in
+ match Urm.nexec iters program init_m with
+ | Some m ->
+ List.iter (fun n -> Printf.printf "R%d = %d\n" n (Urm.register m n))
+ regs_prints
| None ->
Printf.eprintf
- "ERROR: invalid number of maximum iterations provided: '%s'\n"
- iters_str;
- Printf.eprintf "Expected a positive integers\n";
- usage ();
- exit 1
- in
- match Sys.argv with
- | [| _ ; "-i" ; iters_str ; regs ; filepath |] ->
- (parse_iters iters_str, regs, filepath)
- | [| _ ; regs ; filepath |] ->
- (default_max_iters, regs, filepath)
- | argv when Array.length argv < 3 ->
- Printf.eprintf "ERROR: not enought arguments provided\n";
- usage ();
- exit 1
- | _ ->
- Printf.eprintf "ERROR: invalid arguments provided\n";
- usage ();
+ "ERROR: the input program did not halt after %d iterations\n"
+ iters;
+ Printf.eprintf "The input program may not halt\n";
exit 1
+ with Urm.Syntax_error err -> Printf.eprintf "ERROR: %s\n" err
-(** Parse the initial values of the registers as a list of ints separated by
- spaces *)
-let regs =
- let regs = List.filter ((<>) "") (String.split_on_char ' ' regs_str)
- in
- match sequence (List.map int_of_string_opt regs) with
- | Some regs ->
- regs
- | None ->
- Printf.eprintf
- "ERROR: invalid initial values for the registers provided: '%s'\n"
- regs_str;
- Printf.eprintf "Expected a list of integers separated by spaces\n";
- usage ();
- exit 1
+(** Parses the command-line arguments concerning registers.
+ returns [(regs_vals, regs_prints)], where [regs_vals] is the list of pairs
+ encoding the initial values of the machine, and [regs_prints] is the list
+ of registers that should be printed at the end of execution. *)
+let parse_regs (regs : string list) : (int * int) list * int list =
+ let rec fail reg =
+ Printf.eprintf "ERROR: invalid arguments provided: %s\n" reg;
+ usage ();
+ exit 1
+ and f reg (acc_vals, acc_prints) =
+ if not (String.starts_with ~prefix:"-R" reg) then fail reg
+ else let reg' = String.sub reg 2 (String.length reg - 2) in
+ match String.split_on_char '=' reg' with
+ | [reg_n] ->
+ (match int_of_string_opt reg_n with
+ | Some reg_n -> (acc_vals, reg_n :: acc_prints)
+ | None -> fail reg)
+ | [ reg_n ; reg_val ] ->
+ (match (int_of_string_opt reg_n, int_of_string_opt reg_val) with
+ | (Some reg_n, Some reg_val) ->
+ ((reg_n, reg_val) :: acc_vals, acc_prints)
+ | _ -> fail reg)
+ | _ -> fail reg
+ in List.fold_right f regs ([], [])
+
+(** Parses the [-i] command line argument *)
+let parse_iters (iters_str : string) : int =
+ match int_of_string_opt iters_str with
+ | Some n when n > 0 ->
+ n
+ | Some n ->
+ Printf.eprintf
+ "ERROR: negative number of maximum iterations provided: %d\n" n;
+ Printf.eprintf "Expected a positive integers\n";
+ usage ();
+ exit 1
+ | None ->
+ Printf.eprintf
+ "ERROR: invalid number of maximum iterations provided: '%s'\n"
+ iters_str;
+ Printf.eprintf "Expected a positive integers\n";
+ usage ();
+ exit 1
+
+(** Parses all command line arguments *)
+let (iters, init_m, regs_prints, filepath) : int * Urm.t * int list * string =
+ match Array.to_list Sys.argv with
+ | _ :: file_path :: "-i" :: iters_str :: regs ->
+ let (reg_vals, reg_prints) = parse_regs regs in
+ (parse_iters iters_str, Urm.of_list reg_vals, reg_prints, file_path)
+ | _ :: file_path :: regs ->
+ let (reg_vals, reg_prints) = parse_regs regs in
+ (default_max_iters, Urm.of_list reg_vals, reg_prints, file_path)
+ | _ ->
+ Printf.eprintf "ERROR: not enought arguments provided\n";
+ usage ();
+ exit 1
(** Try to open the file with the contents of the program *)
let file =
@@ -93,5 +90,5 @@ let file =
Printf.eprintf "ERROR: %s\n" err;
exit 1
-let () = main iters (Array.of_list regs) file
+let () = main iters init_m regs_prints file