-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathofuck.ml
More file actions
72 lines (65 loc) · 2.06 KB
/
ofuck.ml
File metadata and controls
72 lines (65 loc) · 2.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
open Printf
type token = LAngle | RAngle | Plus | Minus | Dot | Comma | LSquare | RSquare
let lexer (text : string) : token list =
let lex acc = function
| '<' -> LAngle :: acc
| '>' -> RAngle :: acc
| '-' -> Minus :: acc
| '+' -> Plus :: acc
| '.' -> Dot :: acc
| ',' -> Comma :: acc
| '[' -> LSquare :: acc
| ']' -> RSquare :: acc
| _ -> acc
in
String.to_seq text |> Seq.fold_left lex [] |> List.rev
let eval (tokens : token list) =
let cells = Array.make 30_000 0 in
let instrs = Array.of_list tokens in
let rec jump_right ip nest =
match instrs.(ip) with
| LSquare -> jump_right (ip + 1) (nest + 1)
| RSquare ->
let v = nest - 1 in
if v = 0 then ip + 1 else jump_right (ip + 1) (nest - 1)
| _ -> jump_right (ip + 1) nest
in
let rec jump_left ip nest =
match instrs.(ip) with
| RSquare -> jump_left (ip - 1) (nest + 1)
| LSquare ->
let v = nest - 1 in
if v = 0 then ip + 1 else jump_left (ip - 1) (nest - 1)
| _ -> jump_left (ip - 1) nest
in
let rec run ip dp =
if ip < Array.length instrs && ip >= 0 then
match instrs.(ip) with
| Dot ->
cells.(dp) |> Char.chr |> printf "%c";
run (ip + 1) dp
| Plus ->
cells.(dp) <- cells.(dp) + 1;
run (ip + 1) dp
| Minus ->
cells.(dp) <- cells.(dp) - 1;
run (ip + 1) dp
| Comma -> cells.(dp) <- input_byte stdin
| RAngle -> run (ip + 1) (dp + 1)
| LAngle -> run (ip + 1) (dp - 1)
| LSquare ->
if cells.(dp) = 0 then run (jump_right (ip + 1) 1) dp
else run (ip + 1) dp
| RSquare ->
if cells.(dp) <> 0 then run (jump_left (ip - 1) 1) dp
else run (ip + 1) dp
else if ip = Array.length instrs then printf "EOF\n"
else printf "Suspicious termination at ip = %d\n" ip
in
run 0 0
let () =
if Array.length Sys.argv <> 2 then print_endline "Usage: ./ofuckml <file>"
else
let ic = open_in Sys.argv.(1) in
let text = In_channel.input_all ic in
text |> lexer |> eval