- Commit
- be8f1b0db18b47dddebccc9aad86124f5f836fd4
- Parent
- accf21fd370d049d1bb9df8ffde82d74c64aed18
- Author
- Pablo <pablo-escobar@riseup.net>
- Date
Fixed a bunch of bugs
A OCaml module for manipulating unlimited register machines
Fixed a bunch of bugs
3 files changed, 57 insertions, 62 deletions
Status | File Name | N° Changes | Insertions | Deletions |
Modified | docs.pdf | 0 | 0 | 0 |
Modified | urm.ml | 72 | 35 | 37 |
Modified | urm.mli | 47 | 22 | 25 |
diff --git a/urm.ml b/urm.ml @@ -1,4 +1,5 @@ open Array +open Genlex type instruction = | T of int * int @@ -6,17 +7,19 @@ type instruction = | S of int | J of int * int * int -type t = machine = +type t = { instruction_pointer : int; - registers : nat -> nat; + registers : int -> int; } +type machine = t + let of_registers f = - { intruction_pointer = 0; + { instruction_pointer = 0; registers = f } -let zero = from_registers (fun _ -> 0) +let zeros = of_registers (fun _ -> 0) let register m = m.registers @@ -70,36 +73,31 @@ let nexec max program m = 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 (List.filter_map f (String.split_on_char '\n' s)) -end + +(********************************** Parsing **********************************) + +exception Syntax_error of string + +(** A simple lexer for instructions *) +let lex = make_lexer ["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 = parse_instruction (Stream.npeek 8 (lex (Stream.of_string s))) + in Array.of_list (List.map f (String.split_on_char '\n' s)) +
diff --git a/urm.mli b/urm.mli @@ -38,49 +38,46 @@ type t (** An alias for {! t } *) type machine -(** Returns a machine whose value of the [n]-th register is given by [f n]. *) -val of_registers : f:(int -> int) -> machine +(** Returns a machine whose register values are given by a function. *) +val of_registers : (int -> int) -> machine -(** Returns the value of the [i]-th register of [m]. *) -val register : m:machine -> i:int -> int +(** [register m i] the value of the [i]-th register of [m]. *) +val register : machine -> int -> int (** A machine whose registers are all zeros. *) val zeros : machine -(** Returns a machine whose register values are given by the register values of +(** [exec m program] returns a machine whose register values are given by the + register values of [m] with updates corresponding to the execution of [program]. This function only returns when [program] actually halts. Please use {! - nexec } if you don't trust the [program]. + nexec } if you don't trust [program]. @raise Invalid_argument if [program] attempts to jump to a non-positive integer. *) -val exec : program:instruction array -> m:machine -> machine +val exec : instruction array -> machine -> machine (** A safe version of {! exec }, where the maximum number of clock-cycles - allowed is controlled by [n]. Each instruction takes a single clock-cycle - to execute. + allowed is controlled the first argument. Each instruction takes a single + clock-cycle to execute. - Returns [Some _] if [program] halts in at most [n] clock-cycles and - [None] otherwise. + [nexec n program] returns [Some _] if [program] halts in at most [n] + clock-cycles and [None] otherwise. @raise Invalid_argument if [program] attempts to jump to a non-positive - integer. - @raise Invalid_argument if [n] is not a positive integer. *) -val nexec : n:int -> program: instruction array -> machine -> machine option + integer. @raise Invalid_argument if [n] is not a positive integer. *) +val nexec : int -> instruction array -> machine -> machine option -(** Parse URM programs from strings. The syntax used by the parser is based on +(** Exception raised when parsing fails. *) +exception Syntax_error of string + +(** Parse a program from a string. The syntax used by the parser is based on the one used by Ramin Naimi's URM simulator, but again the register indexes can be arbitrary integers. - @see <https://sites.oxy.edu/rnaimi/home/URMsim.htm> URM simulator. *) -module Parse : sig - (** Exception raised when parsing fails. *) - exception Syntax_error of string - - (** Parse a program from a string. + @see <https://sites.oxy.edu/rnaimi/home/URMsim.htm> URM simulator. - @raise Syntax_error in case any syntax error is encountered, including - invalid syntax and jumps to invalid addresses. *) - val parse : string -> instruction array -end + @raise Syntax_error in case any syntax error is encountered, including + invalid syntax and jumps to invalid addresses. *) +val parse : string -> instruction array