fork download
  1. -- Global variables that hold the input:
  2. subj = "5 DUP * ." -- what we are interpreting (example)
  3. pos = 1 -- where are are (1 = "at the beginning")
  4.  
  5. -- Low-level functions to read things from "pos" and advance "pos".
  6. -- Note: the "pat" argument in "parsebypattern" is a pattern with
  7. -- one "real" capture and then an empty capture.
  8. parsebypattern = function (pat)
  9. local capture, newpos = string.match(subj, pat, pos)
  10. if newpos then pos = newpos; return capture end
  11. end
  12. parsespaces = function () return parsebypattern("^([ \t]*)()") end
  13. parseword = function () return parsebypattern("^([^ \t\n]+)()") end
  14. parsenewline = function () return parsebypattern("^(\n)()") end
  15. parserestofline = function () return parsebypattern("^([^\n]*)()") end
  16. parsewordornewline = function () return parseword() or parsenewline() end
  17.  
  18. -- A "word" is a sequence of one or more non-whitespace characters.
  19. -- The outer interpreter reads one word at a time and executes it.
  20. -- Note that `getwordornewline() or ""' returns a word, or a newline, or "".
  21. getword = function () parsespaces(); return parseword() end
  22. getwordornewline = function () parsespaces(); return parsewordornewline() end
  23.  
  24. -- The dictionary.
  25. -- Entries whose values are functions are primitives.
  26. _F = {}
  27. _F["%L"] = function () assert(load(parserestofline(), '=L', nil, _ENV))() end
  28.  
  29. -- The "processor". It can be in any of several "modes".
  30. -- Its initial behavior is to run modes[mode]() - i.e.,
  31. -- modes.interpret() - until `mode' becomes "stop".
  32. mode = "interpret"
  33. modes = {}
  34. run = function () while mode ~= "stop" do modes[mode]() end end
  35.  
  36. -- Initially the processor knows only this mode, "interpret"...
  37. -- Note that "word" is a global variable.
  38. interpretprimitive = function ()
  39. if type(_F[word]) == "function" then _F[word](); return true end
  40. end
  41. interpretnonprimitive = function () return false end -- stub
  42. interpretnumber = function () return false end -- stub
  43. p_s_i = function () end -- print state, for "interpret" (stub)
  44. modes.interpret = function ()
  45. word = getwordornewline() or ""
  46. p_s_i()
  47. local _ = interpretprimitive() or
  48. interpretnonprimitive() or
  49. interpretnumber() or
  50. error("Can't interpret: "..word)
  51. end
  52.  
  53. -- ( Program 3a: the core of miniforth )
  54.  
  55. -- Our first program in MiniForth.
  56. -- It defines a meaning for newlines (they are no-ops; go ahead),
  57. -- for "" ("at end-of-text, change the mode to 'stop'"),
  58. -- and for "[L" - read everything until a "L]", and interpret
  59. -- what is between the "[L" and the "L] as Lua code, with eval.
  60. -- Then it creates a data stack ("DS") and four words - "5", "DUP",
  61. -- "*", "." - that operate on it.
  62. --
  63. subj = [=[
  64. %L _F["\n"] = function () end
  65. %L _F[""] = function () mode = "stop" end
  66. %L _F["[L"] = function () eval(parsebypattern("^(.-)%sL]()")) end
  67. %L DS = { n = 0 }
  68. %L push = function (stack, x) stack.n = stack.n + 1; stack[stack.n] = x end
  69. %L pop = function (stack) local x = stack[stack.n]; stack[stack.n] = nil; stack.n = stack.n - 1; return x end
  70. %L _F["5"] = function () push(DS, 5) end
  71. %L _F["DUP"] = function () push(DS, DS[DS.n]) end
  72. %L _F["*"] = function () push(DS, pop(DS) * pop(DS)) end
  73. %L _F["."] = function () io.write(" "..pop(DS)) end
  74. 5 DUP * .
  75. ]=]
  76.  
  77. -- Now run it. There's no visible output.
  78. pos = 1
  79. mode = "interpret"
  80. run()
  81.  
  82. -- At this point the dictionary (_F) has eight words.
  83.  
  84. -- ( Program 3b: a first program in miniforth )
Success #stdin #stdout 0s 2788KB
stdin
Standard input is empty
stdout
 25