xforth.asm 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. ;; XForth, a minimal Forth system for Intel x86-32 ELF executables
  2. format elf executable 3
  3. entry _start
  4. include 'symbols.inc'
  5. include '/lib/live/mount/persistence/sdb2/trans/fasm/include/proc32.inc'
  6. include '/lib/live/mount/persistence/sdb2/trans/fasm/include/print.inc'
  7. ;; Public domain disclaimer:
  8. ;; I release this work into the public domain.
  9. ;; In case this isn't possible, I grant you the right to do whatever you want with this code.
  10. ;; Entrypoints are addresses referencing some code. They can reference native and directly
  11. ;; runnable code or a interpretable word. In the case of directly runnable code, they are meant
  12. ;; to internal interpreter use. They can be call-able (you start its execution with a `call`
  13. ;; instruction, they return to your code with a 'ret' instruction) or jmp-able (you start it
  14. ;; with a 'jmp' instruction, they will continue to execute internal interpreter's code).
  15. ;; EBP holds the return stack top. ESP holds the data stack top.
  16. _pushrst: ;Native call-able entrypoint to push ESI onto return stack
  17. lea ebp, [ebp-4]
  18. mov [ebp], esi
  19. ret
  20. _poprst: ;Native call-able entrypoint to pop the return stack into ESI
  21. mov esi, [ebp]
  22. lea ebp, [ebp+4]
  23. ret
  24. ;; Words are (potentially) user-accessible sets of instructions. Every word has a entrypoint and
  25. ;; a definition (its contents). They can be run by the interpreter, can call or be called by
  26. ;; other words through the interpreter (which supports the word's code controlling the return
  27. ;; stack for proper operation) and can be referenced at a dictionary.
  28. ;; Codewords are special entrypoints used as a pointer in the beggining of the definition of
  29. ;; every word. They implement the specific interpreter code needed to execute that word.
  30. _enter_native: ;Codeword for native words: words made of native machine code
  31. jmp esi
  32. _leave_routine: ;Word to end a virtual routine
  33. dd _enter_native
  34. _end_caller: ;Jmp-able entrypoint to end the caller routine
  35. call _poprst
  36. _next_routine: ;Jmp-able entrypoint to end the current native routine
  37. call _poprst
  38. add esi, 4
  39. _enter_routine: ;Codeword for virtual words: words made of other words entrypoints
  40. call _pushrst
  41. lodsd
  42. mov esi, eax
  43. _next: ;Entrypoint to jump into the next word's codeword
  44. lodsd
  45. jmp eax
  46. _halt:
  47. dd _enter_native
  48. mov eax, sys_exit
  49. mov ebx, 0
  50. int 80h
  51. ;; `_literal` word gets the value that should be the next word to be run in the current routine
  52. ;; and pushes this value at the data stack, skipping its execution.
  53. _literal:
  54. dd _enter_native
  55. add dword [ebp], 4 ;Return stack top points at the next word to be run
  56. mov eax, [ebp]
  57. push dword [eax]
  58. jmp _next_routine
  59. flag_immediate = 0x80
  60. flag_hidden = 0x40
  61. include 'primitives.asm'
  62. _start:
  63. cld
  64. mov ebp, esp
  65. sub esp, 2*1024*1024 ;Return stack size: 2MB
  66. mov [data_stack_bottom], esp
  67. mov [return_stack_bottom], ebp
  68. mov esi, _forth_boot
  69. jmp _next
  70. ;; Faux word to bootstrap the interpreter:
  71. _forth_boot:
  72. dd _enter_routine
  73. dd main
  74. dd _halt
  75. main:
  76. dd _enter_routine
  77. ;; Empty by now
  78. dd _leave_routine
  79. segment writeable readable
  80. read:
  81. .buffer rb 4096
  82. .cursor rw 1
  83. .top rw 1
  84. word_buffer: rb 32
  85. reg_buffer registers
  86. return_stack_bottom: rd 1
  87. data_stack_bottom: rd 1
  88. compiling_state: rb 1