Commits

Vincent Fiack committed 1f21198

separation between standalone bf compiler and generated js compiler

  • Participants
  • Parent commits 07f3f3c

Comments (0)

Files changed (5)

brainfuck/bfdemo.html

+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Brainfuck optimisation demo</title>
+<style type="text/css">
+td { 
+vertical-align: top;
+}
+
+textarea, input, pre#output {
+width: 400px;
+}
+
+textarea {
+height: 220px;
+}
+
+pre {
+background-color: #eee;
+}
+
+pre#ast, pre#optim {
+width: 200px;
+}
+
+</style>
+</head>
+<body>
+<h3>Optimisation brainfuck</h3>
+<table>
+<tr>
+<td>Source du programme :</td>
+<td><textarea id="source">
+++++++++++[&gt;+++++++&gt;++++++++++&gt;+++&gt;+&lt;&lt;&lt;&lt;-]&gt;++.&gt;+.+++++++..+++.&gt;++.&lt;&lt;+++++++++++++++.&gt;.+++.------.--------.&gt;+.&gt;.
+</textarea></td>
+</tr>
+<tr>
+<td>Flux en entrée :</td>
+<td><input id="io_input"></input></td>
+</tr>
+<tr>
+<td>Exécution :</td>
+<td><button id="run">Hop !</button></td>
+</tr>
+<tr>
+<td>Flux de sortie :</td>
+<td><pre id="output"></pre></td>
+</tr>
+<tr>
+<td>Arbre d'exécution :</td>
+<td>
+  <table class="ast">
+    <tr><td>Sans optimisations</td><td>Avec optimisations</td></tr>
+    <tr><td><pre id="ast"></pre></td><td><pre id="optim"></pre></td></tr>
+  </table>
+</td>
+</tr>
+</table>
+
+<script type="text/javascript" src="bfjs.js"></script>
+</body>
+</html>

brainfuck/bfjs.ml

+open Brainfuck
+
+module Html = Dom_html
+let js = Js.string
+
+let document = Html.window##document
+let jsget msg opt = Js.Opt.get opt (fun () -> failwith msg)
+let get_by_id id  = jsget id (document##getElementById (js id))
+let get_typed_by_id coerce id = jsget "coerce" (coerce (get_by_id id))
+
+let source_elem = get_typed_by_id Html.CoerceTo.textarea "source"
+let input_elem = get_typed_by_id Html.CoerceTo.input "io_input"
+let run_elem = get_by_id "run"
+let ast_elem = get_by_id "ast"
+let optim_elem = get_by_id "optim"
+let output_elem = get_by_id "output"
+
+let debug s = Html.window##alert (js s)
+
+let append_text e s = Dom.appendChild e (document##createTextNode (js s))
+
+module JsIo = struct
+  let input_pointer = ref 0
+
+  let reset () = 
+    output_elem##innerHTML <- js "";
+    input_pointer := 0
+
+  let putchar c = append_text output_elem (String.make 1 c)
+
+  let getchar () = 
+    let str = Js.to_string (input_elem##value) in
+    let c = str.[!input_pointer] in
+    incr input_pointer;
+    c
+end
+
+let reset () = 
+  JsIo.reset ();
+  ast_elem##innerHTML <- js "";
+  optim_elem##innerHTML <- js ""
+
+let run () = 
+  reset ();
+  let module JsInterpreter = Interpreter(JsIo) in
+  let source = Js.to_string (source_elem##value) in
+  let stream = Stream.of_string source in
+  let ast = Parser.parse stream in
+  let optim = Optimizer.optimize ast in
+  ast_elem##innerHTML <- js (ParseTree.string_of_ast ast);  
+  optim_elem##innerHTML <- js (ParseTree.string_of_ast optim);
+  JsInterpreter.exec optim
+
+let set_handlers _ = 
+  run_elem##onclick <- Html.handler (fun _ -> run (); Js._false);
+  Js._false
+
+let _ = 
+  Html.window##onload <- Html.handler set_handlers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

brainfuck/brainfuck.ml

       | Macro macro -> macro_to_string indent macro
     in to_string "" ops
   
-  let dump ast =
-    List.iter (fun op -> print_endline (string_of_op op)) ast
+  let string_of_ast ast = 
+    let str_ops = List.map string_of_op ast in
+    String.concat "\n" str_ops
 end
 
 (** Parse the source file and build the AST *)
 end
 
 (** Runs the AST *)
-module Interpreter = struct
+module type IO = sig
+  val getchar : unit -> char
+  val putchar : char -> unit
+end
+
+module Interpreter = functor (Io:IO) -> struct
   open ParseTree
   
   let memory = Array.make 30_000 0
   
   let add i = memory.(!pointer) <- memory.(!pointer) + i
   
-  let output () = Printf.printf "%c%!" (char_of_int memory.(!pointer))
+  let read () = Io.putchar (char_of_int memory.(!pointer))
   
-  let input () =
-    let c = input_char stdin in
+  let write () =
+    let c = Io.getchar () in
     memory.(!pointer) <- int_of_char c
   
   (* macros *)
     let exec_node = function
       | Move i -> move i
       | Add i -> add i
-      | Output -> output ()
-      | Input -> input ()
+      | Output -> read ()
+      | Input -> write ()
       | Loop nodes ->
           while memory.(!pointer) <> 0 do
             exec nodes;
     List.iter exec_node ast
 end
 
-let brainfuck optimize dump filename =
-  let stream = Stream.of_channel (open_in filename) in
-  let ast = Parser.parse stream in
-  let ast' = if !optimize then Optimizer.optimize ast else ast in
-  if !dump then ParseTree.dump ast' else Interpreter.exec ast'
 
-let _ =
-  let dump = ref false in
-  let optimize = ref false in
-  let args = [
-    ("-optimize", Arg.Set optimize, "optimize ast");
-    ("-dump", Arg.Set dump, "dump ast, don't execute");
-    ] in
-  Arg.parse args (brainfuck optimize dump) "usage"
+
+
+
+
+
+
+
+
+
+

brainfuck/build.sh

+CAMLP4="camlp4o /usr/lib/ocaml/js_of_ocaml/pa_js.cmo"
+TARGET=bfjs
+
+ocamlbuild -use-ocamlfind -pkgs js_of_ocaml -pp "$CAMLP4" $TARGET.byte
+js_of_ocaml $TARGET.byte

brainfuck/standalone.ml

+open Brainfuck
+
+module StdIo = struct
+  let putchar c = Printf.printf "%c%!" c
+  let getchar () = input_char stdin
+end
+
+module StdInterpreter = Interpreter(StdIo)
+
+let brainfuck optimize dump filename =
+  let stream = Stream.of_channel (open_in filename) in
+  let ast = Parser.parse stream in
+  let ast' = if !optimize then Optimizer.optimize ast else ast in
+  if !dump then print_endline (ParseTree.string_of_ast ast) else StdInterpreter.exec ast'
+
+let _ =
+  let dump = ref false in
+  let optimize = ref false in
+  let args = [
+    ("-optimize", Arg.Set optimize, "optimize ast");
+    ("-dump", Arg.Set dump, "dump ast, don't execute");
+    ] in
+  Arg.parse args (brainfuck optimize dump) "usage"
+
+
+
+
+
+
+
+
+
+
+