diff --git a/urm.ml b/urm.ml
@@ -6,12 +6,12 @@ type instruction =
| S of int
| J of int * int * int
-type machine =
+type t = machine =
{ instruction_pointer : int;
registers : nat -> nat;
}
-let from_registers f =
+let of_registers f =
{ intruction_pointer = 0;
registers = f
}
@@ -23,8 +23,7 @@ let register m = m.registers
(** Executes the next instruction. Returns [Some _] is the instruction pointer
points to a valid adress and [None] otherwise. *)
let step (program : instruction array) (m : machine) : machine option =
- if m.instruction_pointer >= length program || m.instruction_pointer < 0
- then None
+ if m.instruction_pointer >= length program then None
else
let updated =
match program.(m.instruction_pointer) with
@@ -43,7 +42,12 @@ let step (program : instruction array) (m : machine) : machine option =
instruction_pointer = m.instruction_pointer + 1;
}
| J (r1, r2, i) when m.registers r1 == m.registers r2 ->
- { m with instruction_pointer = i }
+ (* [i - 1] is used so that the instruction count starts at 1 instead of
+ 0 *)
+ if i > 0 then { m with instruction_pointer = i - 1 }
+ else
+ let e = Printf.sprintf "invalid jump address: J(%d, %d, %d)" r1 r2 i
+ in raise (Invalid_argument e)
| J _ ->
{ m with instruction_pointer = m.instruction_pointer + 1 }
in Some updated
@@ -53,7 +57,7 @@ let rec exec program m =
| None -> { m with instruction_pointer = 0 }
| Some n -> exec program n
-let exec_safe program m max =
+let nexec max program m =
if max <= 0
then raise (Invalid_argument "the number of clock-cycles must be positive ")
else
@@ -66,3 +70,38 @@ let exec_safe program m max =
else None
in exec_safe_tail m 0
+module Parse = struct
+ open Genlex
+
+ exception Syntax_error of string
+
+ (** A simple lexer for instructions *)
+ let lex = make_lexes ["T"; "Z"; "S"; "J"; "("; ")"; ","]
+
+ (** Parse a single instruction *)
+ let parse_instruction (i: token list) : instruction =
+ match i with
+ | [ Kwd "T"; Kwd "("; Int r1; Kwd ","; Int r2; Kwd ")" ] ->
+ T (r1, r2)
+ | [ Kwd "Z"; Kwd "("; Int r; Kwd ")" ] ->
+ Z r
+ | [ Kwd "S"; Kwd "("; Int r; Kwd ")" ] ->
+ S r
+ | [ Kwd "J"; Kwd "("; Int r1; Kwd ","; Int r2; Kwd ","; Int i; Kwd ")" ]
+ when i > 0 ->
+ J (r1, r2, i)
+ | [ Kwd "J"; Kwd "("; Int _; Kwd ","; Int _; Kwd ","; Int i; Kwd ")" ] ->
+ raise (Syntax_error (Printf.sprintf "invalid jump address: %d" i))
+ | _ -> raise (Syntax_error "invalid syntax")
+
+ let parse (s : string) : instruction array =
+ let f s =
+ if String.trim s <> "" then None
+ else
+ match Stream.npeek 8 (lex (Stream.of_string s)) with
+ | Some l ->
+ Some (parse_instruction l)
+ | None ->
+ raise (Syntax_error Prinf.sprintf "invalid syntax: %s" s)
+ in Array.of_list (filter_map (String.split_on_char '\n' s))
+end