bf-fast.lua 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. -- Brainfuck interpreter in Lua using a [] cache.
  2. -- This is public domain.
  3. local src, err = io.open(arg[1], "r")
  4. if src == nil then
  5. print("Error opening file " .. arg[1] .. ": " .. err)
  6. os.exit(1)
  7. end
  8. local code = src:read("*a")
  9. src:close()
  10. src = nil
  11. local ip = 1
  12. local dp = 1
  13. local mem = {0}
  14. local codelen = string.len(code)
  15. local jumpcache = {}
  16. local commands =
  17. {
  18. add = string.byte("+"),
  19. sub = string.byte("-"),
  20. next = string.byte(">"),
  21. prev = string.byte("<"),
  22. startloop = string.byte("["),
  23. endloop = string.byte("]"),
  24. input = string.byte(","),
  25. output = string.byte(".")
  26. }
  27. while ip <= codelen do
  28. local cmd = string.byte(code, ip)
  29. if cmd == commands.add then
  30. mem[dp] = mem[dp] + 1
  31. if mem[dp] == 256 then mem[dp] = 0 end
  32. elseif cmd == commands.sub then
  33. mem[dp] = mem[dp] - 1
  34. if mem[dp] == -1 then mem[dp] = 255 end
  35. elseif cmd == commands.next then
  36. dp = dp + 1
  37. if mem[dp] == nil then mem[dp] = 0 end
  38. elseif cmd == commands.prev then
  39. dp = dp - 1
  40. if dp == 0 then
  41. print("Underflow error at " .. ip)
  42. os.exit(1)
  43. end
  44. elseif cmd == commands.input then
  45. local entry = io.stdin:read(1)
  46. if entry == nil then
  47. mem[dp] = 0 -- end of file
  48. else
  49. entry = string.byte(entry)
  50. if entry > 255 then entry = 255
  51. elseif entry < 0 then entry = 0 end
  52. mem[dp] = entry
  53. end
  54. elseif cmd == commands.output then
  55. io.stdout:write(string.char(mem[dp]))
  56. elseif cmd == commands.startloop and mem[dp] == 0 then
  57. if jumpcache[ip] ~= nil then ip = jumpcache[ip]
  58. else
  59. local descent, oldip = 1, ip
  60. repeat
  61. ip = ip + 1
  62. if ip > codelen then
  63. print("Unmatched [")
  64. os.exit(1)
  65. end
  66. cmd = string.byte(code, ip)
  67. if cmd == commands.startloop then descent = descent + 1
  68. elseif cmd == commands.endloop then descent = descent - 1 end
  69. until descent == 0
  70. jumpcache[oldip] = ip
  71. end
  72. elseif cmd == commands.endloop and mem[dp] ~= 0 then
  73. if jumpcache[ip] ~= nil then ip = jumpcache[ip]
  74. else
  75. local descent, oldip = 1, ip
  76. repeat
  77. ip = ip - 1
  78. if ip == 0 then
  79. print("Unmatched ]")
  80. os.exit(1)
  81. end
  82. cmd = string.byte(code, ip)
  83. if cmd == commands.startloop then descent = descent - 1
  84. elseif cmd == commands.endloop then descent = descent + 1 end
  85. until descent == 0
  86. jumpcache[oldip] = ip
  87. end
  88. end
  89. ip = ip + 1
  90. end