Guest User

brainfuck.ml

a guest
Apr 21st, 2012
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 4.41 KB | None | 0 0
  1. (** The abstract syntax tree (AST) that will be build then executed *)
  2. module ParseTree = struct
  3.   type operation =
  4.     | PtrAdd of int          (** add n to the cell pointer *)
  5.     | DataAdd of int         (** add n to the current cell's value *)
  6.     | Output                 (** write the current cell as an ascii char *)
  7.     | Input                  (** read a char and write it in the current cell *)
  8.     | Loop of operation list (** loop while the current cell is <> 0 *)
  9.  
  10.   let string_of_op ops =
  11.     let open Printf in
  12.     let rec to_string indent = function
  13.       | PtrAdd i -> sprintf "%sPtrAdd(%d)" indent i
  14.       | DataAdd i -> sprintf "%sDataAdd(%d)" indent i
  15.       | Output -> sprintf "%sOutput" indent
  16.       | Input -> sprintf "%sInput" indent
  17.       | Loop nodes ->
  18.           sprintf "%sLoop <<\n%s\n%sLoop >>"
  19.             indent
  20.             (String.concat "\n" (List.map (to_string ("| "^indent)) nodes))
  21.             indent
  22.     in to_string "" ops
  23.  
  24.   let dump ast =
  25.     List.iter (fun op -> print_endline (string_of_op op)) ast  
  26. end
  27.  
  28. (** Parse the source file and build the AST *)
  29. module Parser = struct
  30.   open ParseTree
  31.  
  32.   (* lexical analysis, build token list from chars *)
  33.   type token =
  34.     | IncrPtr | DecrPtr
  35.     | IncrData | DecrData
  36.     | Write | Read
  37.     | Open | Close
  38.     | Comment of char
  39.  
  40.   let token_of_char = function
  41.     | '>' -> IncrPtr
  42.     | '<' -> DecrPtr
  43.     | '+' -> IncrData
  44.     | '-' -> DecrData
  45.     | '.' -> Write
  46.     | ',' -> Read
  47.     | '[' -> Open
  48.     | ']' -> Close
  49.     | c -> Comment c
  50.  
  51.   let tokenize charstream =
  52.     let tokens = ref [] in
  53.     Stream.iter (fun c -> tokens := (token_of_char c) :: !tokens) charstream;
  54.     List.rev !tokens
  55.  
  56.   (* syntaxic analysis, build AST from tokens *)
  57.   let build_group incr decr constructor tokens =
  58.     let rec loop i lst = match lst with
  59.       | token :: rest when token = incr -> loop (succ i) rest
  60.       | token :: rest when token = decr -> loop (pred i) rest
  61.       | _ -> (constructor i), lst
  62.     in loop 0 tokens
  63.  
  64.   let build_ptr_add = build_group IncrPtr DecrPtr (fun i -> PtrAdd i)
  65.  
  66.   let build_data_add = build_group IncrData DecrData (fun i -> DataAdd i)
  67.  
  68.   let build_loop tokens =
  69.     let rec loop acc opened = function
  70.       | Open :: rest -> loop (Open :: acc) (succ opened) rest
  71.       | Close :: rest ->
  72.           if opened = 0 then (List.rev acc), rest
  73.           else loop (Close :: acc) (pred opened) rest
  74.       | other:: rest -> loop (other :: acc) opened rest
  75.       | [] -> failwith "malformed Loop"
  76.     in
  77.     loop [] 0 (List.tl tokens)
  78.  
  79.   let rec build_ast tokens =
  80.     let rec loop tokens acc =
  81.       match tokens with
  82.       | [] -> acc
  83.       | (IncrPtr | DecrPtr) :: _ ->
  84.           let op, rest = build_ptr_add tokens in
  85.           loop rest (op:: acc)
  86.       | (IncrData | DecrData) :: _ ->
  87.           let op, rest = build_data_add tokens in
  88.           loop rest (op:: acc)
  89.       | Write :: rest -> loop rest (Output :: acc)
  90.       | Read :: rest -> loop rest (Input :: acc)
  91.       | Open :: rest ->
  92.           let sublist, rest = build_loop tokens in
  93.           let cond = build_ast sublist in
  94.           loop rest ((Loop cond) :: acc)
  95.       | Close :: rest -> failwith "Close should have been consumed by build_loop"
  96.       | (Comment _) :: rest -> loop rest acc
  97.     in
  98.     List.rev (loop tokens [])
  99.  
  100.   (** builds the AST from a char stream *)
  101.   let parse stream =
  102.     let tokens = tokenize stream in
  103.     build_ast tokens
  104. end
  105.  
  106. (** Runs the AST *)
  107. module Interpreter = struct
  108.   open ParseTree
  109.  
  110.   let memory = Array.make 30_000 0
  111.   let pointer = ref 0
  112.  
  113.   let rec exec ast =
  114.     let exec_node = function
  115.       | PtrAdd i -> pointer := !pointer + i
  116.       | DataAdd i -> memory.(!pointer) <- memory.(!pointer) + i
  117.       | Output -> Printf.printf "%c%!" (char_of_int memory.(!pointer))
  118.       | Input ->
  119.           let c = input_char stdin in
  120.           memory.(!pointer) <- int_of_char c
  121.       | Loop nodes ->
  122.           while memory.(!pointer) <> 0 do
  123.             exec nodes;
  124.           done
  125.     in
  126.     List.iter exec_node ast
  127. end
  128.  
  129. let brainfuck dump filename =
  130.   let stream = Stream.of_channel (open_in filename) in
  131.   let ast = Parser.parse stream in
  132.   if !dump then ParseTree.dump ast else Interpreter.exec ast
  133.  
  134. let _ =
  135.   let dump = ref false in
  136.   let args = [("-dump", Arg.Set dump, "dump ast, don't execute")] in
  137.   Arg.parse args (brainfuck dump) "usage"
Advertisement
Add Comment
Please, Sign In to add comment