123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- ;; XForth, a minimal Forth system for Intel x86-32 ELF executables
- format elf executable 3
- entry _start
- include 'symbols.inc'
- include '/lib/live/mount/persistence/sdb2/trans/fasm/include/proc32.inc'
- include '/lib/live/mount/persistence/sdb2/trans/fasm/include/print.inc'
- ;; Public domain disclaimer:
- ;; I release this work into the public domain.
- ;; In case this isn't possible, I grant you the right to do whatever you want with this code.
- ;; Entrypoints are addresses referencing some code. They can reference native and directly
- ;; runnable code or a interpretable word. In the case of directly runnable code, they are meant
- ;; to internal interpreter use. They can be call-able (you start its execution with a `call`
- ;; instruction, they return to your code with a 'ret' instruction) or jmp-able (you start it
- ;; with a 'jmp' instruction, they will continue to execute internal interpreter's code).
- ;; EBP holds the return stack top. ESP holds the data stack top.
- _pushrst: ;Native call-able entrypoint to push ESI onto return stack
- lea ebp, [ebp-4]
- mov [ebp], esi
- ret
- _poprst: ;Native call-able entrypoint to pop the return stack into ESI
- mov esi, [ebp]
- lea ebp, [ebp+4]
- ret
- ;; Words are (potentially) user-accessible sets of instructions. Every word has a entrypoint and
- ;; a definition (its contents). They can be run by the interpreter, can call or be called by
- ;; other words through the interpreter (which supports the word's code controlling the return
- ;; stack for proper operation) and can be referenced at a dictionary.
- ;; Codewords are special entrypoints used as a pointer in the beggining of the definition of
- ;; every word. They implement the specific interpreter code needed to execute that word.
- _enter_native: ;Codeword for native words: words made of native machine code
- jmp esi
- _leave_routine: ;Word to end a virtual routine
- dd _enter_native
- _end_caller: ;Jmp-able entrypoint to end the caller routine
- call _poprst
- _next_routine: ;Jmp-able entrypoint to end the current native routine
- call _poprst
- add esi, 4
- _enter_routine: ;Codeword for virtual words: words made of other words entrypoints
- call _pushrst
- lodsd
- mov esi, eax
- _next: ;Entrypoint to jump into the next word's codeword
- lodsd
- jmp eax
- _halt:
- dd _enter_native
- mov eax, sys_exit
- mov ebx, 0
- int 80h
- ;; `_literal` word gets the value that should be the next word to be run in the current routine
- ;; and pushes this value at the data stack, skipping its execution.
- _literal:
- dd _enter_native
- add dword [ebp], 4 ;Return stack top points at the next word to be run
- mov eax, [ebp]
- push dword [eax]
- jmp _next_routine
- flag_immediate = 0x80
- flag_hidden = 0x40
- include 'primitives.asm'
- _start:
- cld
- mov ebp, esp
- sub esp, 2*1024*1024 ;Return stack size: 2MB
- mov [data_stack_bottom], esp
- mov [return_stack_bottom], ebp
- mov esi, _forth_boot
- jmp _next
- ;; Faux word to bootstrap the interpreter:
- _forth_boot:
- dd _enter_routine
- dd main
- dd _halt
- main:
- dd _enter_routine
- ;; Empty by now
- dd _leave_routine
- segment writeable readable
- read:
- .buffer rb 4096
- .cursor rw 1
- .top rw 1
- word_buffer: rb 32
- reg_buffer registers
- return_stack_bottom: rd 1
- data_stack_bottom: rd 1
- compiling_state: rb 1
|