/brainfuck.coffee

https://github.com/1337/brainfuck.js · CoffeeScript · 141 lines · 111 code · 16 blank · 14 comment · 17 complexity · fc43a7198cd52666d74786ada68853f2 MD5 · raw file

  1. #
  2. # Brainfuck interpreter by github.com/1337
  3. # How to run: new $.brainfuck('>>>.')).run().out().reset();
  4. #
  5. # MIT Licence
  6. #
  7. pointer = 0 # current memory address
  8. stack = [] # array of values (memory)
  9. buffer = ""
  10. reset = ->
  11. pointer = 0
  12. stack = []
  13. buffer = ""
  14. # taken from this jackass
  15. # http://stackoverflow.com/questions/8567114/how-to-make-an-ajax-call-without-jquery#comment26730310_8567149
  16. jax = (url, callback) ->
  17. if window.XMLHttpRequest
  18. xmlhttp = new XMLHttpRequest()
  19. else
  20. xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
  21. xmlhttp.onreadystatechange = ->
  22. if xmlhttp.readyState == 4 and xmlhttp.status == 200
  23. callback(xmlhttp.responseText or xmlhttp.response)
  24. xmlhttp.open "GET", url, true
  25. xmlhttp.send()
  26. class BrainFuck
  27. constructor: (@code) ->
  28. run: (code=@code) ->
  29. pointer = 0
  30. index = -1
  31. while index++ < code.length
  32. # prevent miscalculations
  33. if isNaN stack[pointer]
  34. stack[pointer] = 0
  35. switch code[index]
  36. when ">"
  37. pointer++
  38. when "<"
  39. pointer--
  40. when "+"
  41. stack[pointer]++
  42. when "-"
  43. if stack[pointer] > 0
  44. stack[pointer]--
  45. when "."
  46. buffer += String.fromCharCode(stack[pointer])
  47. when ","
  48. stack[pointer] = prompt()
  49. when "["
  50. # while condition intercepted by code termination in ']'
  51. index += (new BrainFuck(@code.substring(index + 1))).run()
  52. when "]"
  53. if stack[pointer] is 0
  54. return index + 1
  55. index = -1
  56. else
  57. @
  58. out: (execute=true, reset=true) ->
  59. # completes the interpretation and outputs the result
  60. if execute
  61. try
  62. eval buffer
  63. catch err
  64. alert buffer
  65. if reset
  66. @reset()
  67. @toString()
  68. toString: ->
  69. buffer
  70. reset: ->
  71. reset()
  72. @
  73. BrainFuck.from_js = (js='alert(undefined);') ->
  74. # translate js to bf.
  75. moveChar = (a, b) ->
  76. # returns the bit shifts required to move current value from a to b.
  77. # a and b are things with .charCodeAt()s.
  78. ordA = a.charCodeAt(0)
  79. ordB = b.charCodeAt(0)
  80. diff = ordB - ordA
  81. if diff == 0
  82. "."
  83. else if diff > 0
  84. Array(diff + 1).join("+") + "."
  85. else if diff < 0
  86. Array(-diff + 1).join("-") + "."
  87. js = "eval('" + js.replace(/'/g, "\\'") + "');"
  88. brainfuck_buffer = ""
  89. charAt = String.fromCharCode(0)
  90. while js.length > 0
  91. brainfuck_buffer += moveChar(charAt, js[0])
  92. charAt = js[0]
  93. js = js.substring(1)
  94. return brainfuck_buffer
  95. BrainFuck.to_js = (bf) ->
  96. # run bf as js.
  97. runtime = new BrainFuck(bf)
  98. src = runtime.run().out(false, false)
  99. eval(src)
  100. runtime.reset()
  101. # strap on some automatic text/brainfuck magic
  102. previous_onload = window.onload
  103. window.onload = ->
  104. if previous_onload
  105. previous_onload.apply(this, arguments)
  106. script_tags = document.getElementsByTagName('script')
  107. for tag in script_tags
  108. if tag.type.toLowerCase() is 'text/brainfuck'
  109. if tag.innerHTML # is inline script
  110. setTimeout(->
  111. BrainFuck.to_js(tag.innerHTML)
  112. , 0)
  113. else if tag.src # is external
  114. jax tag.src, (bf) ->
  115. BrainFuck.to_js(bf)
  116. # lazy
  117. window.BrainFuck = BrainFuck