Talk:Minks
Jump to navigation
Jump to search
How can any instructions be executed if all of them have to be preceded by a condition, and it is not possible to set a condition without executing an instruction? Are undefined conditions true by default? --Marinus 16:01, 21 Jul 2006 (UTC)
- Apparently so. --Ihope127 21:59, 21 Jul 2006 (UTC)
Implementation
I have written an interpreter in Ocaml which I believe is working. I have tested it on the Minks programs blabla DEC blabla (exits without doing anything), b INP b DEC b b INC b OUT (cat program), and b INC b INC b INC b INC b INC
b INC b INC b INC b INC b INC
b OUT b dec b (prints a newline, then exits.)
Features:
- if
INP(orinp) is executed while input has reached end of file, the number 0 is stored in the REGISTER (or register) - each register can hold a value between 0 and Ocaml's
max_int- technically, they can hold negative values, but since
DEC/decnever go below 0, the only way to do that is to overflow them with a lot ofINC/incinstructions - trying to output a negative value will display an error like
Invalid_argument "char_of_int", because Ocaml's modulo function is such that-1 mod 256results in -1
- technically, they can hold negative values, but since
- whitespace (spaces, newlines, tabulations) are mostly ignored, except every condition must be separated from the next instruction or condition with at least one space/tab/newline
- conditions can have any alphabetic names (except the empty string); whether a word is an instruction or a condition depends entirely on its position within the program
Here is the source:
(* conditions are A-Za-z only, case insensitive *)
type condition = int
(* REGISTER is true, register is false *)
type instruction = Inc of bool | Dec of bool * condition | Out of bool | Inp of bool
type item = I of instruction | C of condition
exception Syntax_error
let string_of_list l =
let length = List.length l in
let s = String.create length and l = ref l in
for k = length - 1 downto 0 do
s.[k] <- List.hd !l;
l := List.tl !l
done;
s
let l_pos =
let l_of_conds = ref [] and n = ref 0
in
let rec pos s k l =
match l with
| h :: t -> if h = s then !n - k else pos s (succ k) t
| [] ->
(l_of_conds := s :: !l_of_conds;
incr n;
pred !n)
in
function s ->
pos s 1 !l_of_conds
let rec take_cond l =
match l with
| ' ' :: t | '\n' :: t | '\t' :: t ->
take_cond t
| _ -> t_2 [] l
and t_2 acc l =
match l with
| ' ' :: t | '\n' :: t | '\t' :: t ->
let s = string_of_list acc in
(l_pos s, t)
| [] ->
let s = string_of_list acc in
(l_pos s, [])
| h :: t ->
t_2
((let x = int_of_char h in
if (x > 64 && x < 91) then h
else if x > 96 && x < 123 then Char.lowercase h
else raise Syntax_error
) :: acc)
t
let rec parser acc prev p_list =
match (prev, p_list) with
| (C s, 'I' :: 'N' :: 'C' :: t) ->
parser ((s, Inc true) :: acc) (I (Inc true)) t
| (C s, 'i' :: 'n' :: 'c' :: t) ->
parser ((s, Inc false) :: acc) (I (Inc false)) t
| (C s, 'O' :: 'U' :: 'T' :: t) ->
parser ((s, Out true) :: acc) (I (Out true)) t
| (C s, 'o' :: 'u' :: 't' :: t) ->
parser ((s, Out false) :: acc) (I (Out false)) t
| (C s, 'I' :: 'N' :: 'P' :: t) ->
parser ((s, Inp true) :: acc) (I (Inp true)) t
| (C s, 'i' :: 'n' :: 'p' :: t) ->
parser ((s, Inp false) :: acc) (I (Inp false)) t
| (C s, 'D' :: 'E' :: 'C' :: t) ->
parser acc (I (Dec (true, s))) t
| (C s, 'd' :: 'e' :: 'c' :: t) ->
parser acc (I (Dec (false, s))) t
| (_, ' ' :: t) | (_, '\n' :: t) | (_, '\t' :: t) ->
parser acc prev t
| (I (Dec (b, s)), l) ->
let (s2, t2) = take_cond l in
parser ((s, Dec (b, s2)) :: acc) (I (Inc b)) t2
| (C s, _) -> raise Syntax_error
| (I _, []) ->
(let n = l_pos "" in Array.make n true,
List.rev acc)
| (I _, l) ->
let (s, t) = take_cond l in
parser acc (C s) t;;
let list_of_string s =
let l = ref [] in
for k = String.length s - 1 downto 0 do
l := s.[k] :: !l
done;
!l
let (cond_tab, program) = parser [] (I (Inc true)) (list_of_string Sys.argv.(1))
let is_true c = cond_tab.(c)
let set_cond c b = cond_tab.(c) <- b
let (register, rEGISTER) = (ref 0, ref 0)
let rec execution have_met p_list =
match p_list with
| (c, Inc b) :: t ->
if is_true c then
(incr (if b then rEGISTER else register);
execution true t)
else execution have_met t
| (c, Out b) :: t ->
if is_true c then
(print_char
(char_of_int (!(if b then rEGISTER else register) mod 256)
);
execution true t)
else execution have_met t
| (c, Inp b) :: t ->
if is_true c then
((if b then rEGISTER else register) :=
begin try int_of_char (input_char stdin) with
| End_of_file -> 0 end;
execution true t)
else execution have_met t
| (c, Dec (b, c2)) :: t ->
(if is_true c then let reg = (if b then rEGISTER else register)
in
if !reg = 0
then set_cond c2 false
else (decr reg; set_cond c2 true)
); execution (have_met || is_true c) t
| [] -> if have_met then execution false program;;
execution false program;;