Skip to content

Latest commit

 

History

History
7619 lines (6795 loc) · 209 KB

cicada-nymph.org

File metadata and controls

7619 lines (6795 loc) · 209 KB

小蟬語 / cicada-nymph

todo

home-path & search-path to load files

  • poi denotes path-organizer
  • 實現 條件性的被解釋的代碼 這樣就能實現
    1. little-tester
    2. 在不同的平臺下執行不同的代碼

nested load-file

  • a stack of buffer would solve this problem

add more notes about the limitations of the program

add more notes about exception handling on io functions

optimize local-variable by new instruction

  • too many literal is too waste of memory

code clean-up & documentation update

[maybe] bare-metal version of cicada-nymph for x86

[maybe] better error handling of load-file

  • error code is different between windows and linux which is problematic

[maybe] make instruction a type of jo

this is needed when doing report of the dictionary

note problem

[BUG] about div

  • div can not handle the following -8 2 div .

[BUG] about inline comment

  • inline comment such as add1 << dup . >> swap will be viewed as add1swap

[BUG] about comment in string

  • << >> can not be in “”

[LIMIT] about stack

  • there are 64 positions below the all those stacks when you are belowing-stack so much bad things happen

[BAD-DESIGN] local-variable

  • 想要加入 @:address <number> 或者 <number> %>:address
  • 但是 由於對 offset 的計算是在編譯時進行的 所以根本就沒利用到這裏所能得到的最大的靈活性 以至於沒法以良好的方式實現 在 local_data_heap 中動態地分配變長的內存
  • 形成這種局面的原因在於 對局部變元的名字和值的關係的處理 是在編譯時期進行的
  • 由於這中問題產生於兩種分配內存方式的交織 所以 其解決辦法也許是 再多入返回站一個指針 這個指針所指向的數據區中的數據 是純粹在運行時動態分配的 但是這些數據沒有名字 [名字的問題是另外一個指針結局的]

===================================

note

jo & jojo

  • use “jo” to denote bead and use “jojo” to denote a thread of beads [which reads like “珠珠” in Chinese]

naming convention

  • a predicate of a type which denotes a subtype of that type uses that type as postfix such as “space-char?”
  • a function of a type uses that type as prefix such as “string-reverse” “string-equal?”
  • side-effect of structured data is postfixed by “!”

convention in assembly code

  • using underline to compose big word from small words
  • using “$” as prefix and postfix separator
  • indentation level = 3
  • naming convention of jo
    conventionjo type
    prefix “V__”variable
    prefix “M__”macro
  • but I use
    1. “zero” instead of “V__zero”
    2. “true” instead of “V__true”

convention in cicada-nymph code

  • using dash to compose big word from small words
  • using “,” as prefix and postfix separator
  • indentation style = free
  • words are separated by space except for bar-ket every bar-ket is viewed as a word

syntax of cicada-nymph

  • syntax & semantic
    syntaxsemantic
    borderfix “* *”variable
    borderfix “+ +”[maybe use]
    bar-ket ( )not use
    bar-ket [ ]not use
    bar-ket { }macro call
    (for macros of which
    the number of
    arguments is not fix)
    double-quoteviewed as special bar-ket
    (bar is the same as ket)
    to support string literal
    prefix “!”exception
    postfix “!”some of the side-effect
    postfix “?”predicate
  • but I use
    1. “true” instead of ”true
    2. “false” instead of ”false

unique id

  • if one wish to get a named unique id a jo maybe used for a jo is an address in memory it is unique as a memory address
  • but there is not effort made to distinguish address and fixnum as different type of things thus this kind of unique id is not fit for some tasks

different from the re-designed cicada-language

  • simplifications are for teaching purpose only
  • first and foremost function programming will NOT be supported in this implementation
  • a helper function must be defined before it is used
  • no mixfix-notation
    • function call is “function” instead of “(function)”
    • no such thing like 1 2 (add) = 1 (add 2) = (add 1 2)
  • no named local argument
    • thus no inited local argument
  • no title-name-table
    • thus in this implementation we only use single name space
    • thus in this implementation we do NOT have the concept of “context” so the syntax is not as flexible as it will be in cicada-language
  • no type
    • no type inference
    • no dynamic type tag
    • no static type declaration
  • global linked-list for naming
    • not hash-table
    • by the way in classical forth the linked-list of jo is called dictionary
  • no dynamic-memory-management
    • no garbage-collector
  • about comment
    • the comment of the argument & return value of function is allowed to be written in free style normal comment

note instar

1st-instar

  • indirect-threaded-code interpreter
    1. macro about argument_stack & return_stack
    2. macro about jo & jojo
    3. macro about next
    4. the way to do memory allocation
    5. begin_to_interpret_threaded_code
    6. little_test

2ed-instar

  • instruction as special primitive function
    1. literal
    2. address
  • and primitive functions about
    1. the stack
    2. bool
    3. fixnum
    4. memory
  • and taca for explicit tail-call
  • false?branch and taca are needed for “power”

3rd-instar

  • primitive function about io
    1. write_byte
    2. read_byte

4th-instar

  • more function about io
    1. about word
    2. about string
    3. about number
  • more function
    1. jo
    2. char
    3. buffer
  • more in epilog
    1. last_link
  • function about dictionary
    1. find
    2. execute-word
  • basic-REPL as postfix-notation function executer
    1. basic-REPL

5th-instar

  • type of jo
  • more in epilog
    1. current-free-address,primitive-string-heap
  • colon semicolon
    1. ”:” and “;” are used to read a string of words for compiler [looks like bar-ket but special]
    2. comment is handled here “<< >>” as the only way to do comment
  • compiler
    • make-jojo and macro for make-jojo
      1. macro system
      2. exception handling system
    • function about definition which leave data into memory

6th-instar

  • local-variable

記 數據結構與口總結

jojo

  • jo 的數組 每個數組外加一些元數據

dictionary of jojo

  • 單項鏈接的鏈表

primitive-string

stack

argument-stack

return-stack

  • jo 的詮釋者 決定了 如何入這個棧
  • 結尾詞 決定了 如何出這個棧

eval-string-stack

  • 兩個一對

dispatch-word-stack

  • 兩個一對 每對爲 [語法處理函數, 作用於字符串的謂詞]

local-variable-table

  • a heap like table of string
  • 只有一個 local-variable-table 用以在編譯時期解決局部變元的名與值的對應 這個數據結構被 M__local_variable_save_string 和 M__local_variable_fetch_string 所使用
  • 其中保存
    • offset-in-local-data-heap
    • length-of-string
    • address-of-string
  • 並且每次在定義一個新的函數體的時候 這個 local-variable-table 會被初始化
  • 基本的接口是
    • clear 清空 offset 和 border
    • insert 插入字符串 和 offset-in-local-data-heap
    • find 通過字符串尋找 offset-in-local-data-heap

    有兩個全局變量幫助實現這些接口

    • cursor 每次 find 的時候使用一個新的 cursor 來做循環
    • border insert 會擴大 border find 以 border 爲邊界

    另外 還有一個全局變量

    • offset 用以計算 offset-in-local-data-heap

記 性狀總結

自動管理加載文件時所使用的搜索路徑列表

  • 原理如下
    • 在 cicada-nymph 中 load 一個 file 的時候 需要指定出這個 被 load 的 file 的路徑
    • 維護一個需要被搜索的路徑的列表 以使得 load 的 file 的時候 不必使用完整的路徑
    • 提供自動管理搜索路徑的機制
  • 維護搜索路徑的列表的方式是 利用文件系統中的一個某個固定路徑 也就是說 只有唯一的一個需要被找到的路徑 而其他的路徑都是被自動管理的 這個路徑將有一個默認值 並且可以被環境變量覆蓋
  • 限制加載文件的方式 使得只能使用所提供的動態管理機制來加載文件 這樣就可以減輕理解這個系統的困難

>< 局部變元

===================================

prolog

----------------------------------

note conditional preprocessing

  • flower bar-ket can not be nested in fasm’s “match” so
    1. when defining macro conditionally one should use “if eq” & “finish if”
    2. when doing “define” or “equ” one should use “match { }”

platform configuration

;;;; before you compile the code
;;;; do not forget to choose your platform
;;;; in the following code

include "platform-configuration.inc"

;; define platform linux or windows
;; define machine  64bit or 32bit

misc

;; in fasm, "dup" is a reserved word
dup equ duplicate

;; in fasm, "end" is a reserved word
finish equ end
end equ exit

----------------------------------

jo_size

match =64bit, machine {

jo_size = 8 ;; (byte)
xx equ dq

}

jo_size

match =32bit, machine {

jo_size = 4 ;; (byte)
xx equ dd

rax equ eax
rbx equ ebx
rcx equ ecx
rdx equ edx
rsp equ esp
rbp equ ebp
rsi equ esi
rdi equ edi

syscall equ int 80h

}

----------------------------------

header

match =linux =64bit, platform machine {

define linux64_sys_6_r8  r8
define linux64_sys_5_r9  r9
define linux64_sys_4_r10 r10
define linux64_sys_3_rdx rdx
define linux64_sys_2_rsi rsi
define linux64_sys_1_rdi rdi
define linux64_sys_n_rax rax

define linux64_syscall_read   0
define linux64_syscall_write  1
define linux64_syscall_open   2
define linux64_syscall_close  3
define linux64_syscall_getpid 39
define linux64_syscall_exit   60
;; about open & read & write

open_read         = 0
open_write        = 1
open_readAndWrite = 2

open_creat      = 0100o
open_rewrite    = 1000o ;; rewrite if file exist
open_append     = 2000o

open_excl       = 0200o ;; ensure that THIS call creates the file
open_noctty     = 0400o
open_nonblock   = 4000o
open_nondelay   = open_nonblock
open_sync       = 10000o
open_async      = 20000o
open_direct     = 40000o
    ;; to minimize cache effects of the I/O to and from this file.

open_largefile  = 100000o
open_directory  = 200000o
open_nofollow   = 400000o ;; If pathname is a symbolic link, then the open fails.

}

format

match =linux =64bit, platform machine {

format ELF64 executable 3

}

entry

match =linux =64bit, platform machine {

entry begin_to_interpret_threaded_code
segment readable executable writeable

}

----------------------------------

header

  • /usr/include/asm/unistd_32.h (on archlinux)
match =linux =32bit, platform machine {

define linux32_sys_6_ebp ebp
define linux32_sys_5_edi edi
define linux32_sys_4_esi esi
define linux32_sys_3_edx edx
define linux32_sys_2_ecx ecx
define linux32_sys_1_ebx ebx
define linux32_sys_n_eax eax

define linux32_syscall_exit    1
define linux32_syscall_read    3
define linux32_syscall_write   4
define linux32_syscall_open    5
define linux32_syscall_close   6
define linux32_syscall_getpid  20

open_read         = 0
open_write        = 1
open_readAndWrite = 2

open_creat      = 0100o
open_rewrite    = 1000o ;; rewrite if file exist
open_append     = 2000o

}

format

match =linux =32bit, platform machine {

format ELF executable 3

}

entry

match =linux =32bit, platform machine {

entry begin_to_interpret_threaded_code
segment readable executable writeable

}

----------------------------------

note calling convention

  • Stack Allocation Calling Convention x64 Software Conventions
  • why windows64 is different
  • if you respect the calling convention
    1. your functions will be able to call other functions which respect the calling convention
    2. your functions will be call-able by other functions which respect the calling convention
  • in our program
    1. we do NOT need to respect the calling convention to let our functions be call-able by other function which respect the calling convention
    2. we ONLY need to respect the calling convention to let our functions be able to call other functions which respect the calling convention
  • before a call to function in kernel you have to 16-byte aligne the stack
  • pass first 4 arguments by rcx rdx r8 r9 pass other arguments by stack
  • you have to reserve 4 place for the first 4 arguments although you do not need to push them into stack
  • you have to reserve 4 place for the first 4 arguments even if the function you are calling only uses less then 4 arguments
  • the code I am using to handle windows calling convention is de-macro-lized and un-optimized this is for teaching purpose only

header

match =windows =64bit, platform machine {

define windows64_fun_4_r9  r9
define windows64_fun_3_r8  r8
define windows64_fun_2_rdx rdx
define windows64_fun_1_rcx rcx

define STD_INPUT_HANDLE  -10
define STD_OUTPUT_HANDLE -11

}

format

match =windows =64bit, platform machine {

format PE64 console

}

entry

match =windows =64bit, platform machine {

entry begin_to_interpret_threaded_code
section '.text' code writeable readable executable

}

macro

  • macro about windows64 calling-convention
match =windows =64bit, platform machine {


;; 這裏的 number_of_arguments 其實代表
;; 在對齊棧之後
;; 你還想要將棧的指針 向下移動多少個單位
;; 根據 windows calling convention
;; 這個數字最少是 4

macro windows64_function number_of_arguments \{
   push rbp
   mov rbp, rsp

   mov rax, rsp
   add rax, 8*number_of_arguments
   mov rbx, 1111b
   and rbx, rax

   sub rsp, 16
   add rsp, rbx
\}

macro end_windows64_function \{
   mov rsp, rbp
   pop rbp
\}


}

----------------------------------

note calling convention

header

match =windows =32bit, platform machine {

define STD_INPUT_HANDLE  -10
define STD_OUTPUT_HANDLE -11

}

format

match =windows =32bit, platform machine {

format PE console

}

entry

match =windows =32bit, platform machine {

entry begin_to_interpret_threaded_code
section '.text' code writeable readable executable

}

----------------------------------

memory allocation in un_initialized_memory

  • implemented as a memory map
current_free_address$un_initialized_memory = address$un_initialized_memory

labeling  equ = current_free_address$un_initialized_memory
preserve  equ current_free_address$un_initialized_memory = current_free_address$un_initialized_memory +

----------------------------------

-----------------------------------

note stack

  • when doing “push” a stack-pointer moves to lower address
  • note that another style is that when doing “push” a stack-pointer moves to higher address
  • the stack-pointer always stores the address of current-free-address of the stack
  • note that another style is that under the stack-pointer there always stores the value of the-top-of-the-stack

argument_stack

----------------------------------

memory allocation

  • for we do not build border-check into the interface of pop and push we allocation some memory below the stacks
   preserve 64 * jo_size
address$argument_stack labeling
   preserve 1024 * 1024 * jo_size

----------------------------------

pointer

match =64bit, machine {

;; if you want to extend cicada in assembly
;; the following registers must NOT be used

define pointer$argument_stack r15

}

push & pop

match =64bit, machine {

macro push_argument_stack register \{
   mov [pointer$argument_stack], register
   add pointer$argument_stack, jo_size
\}

macro pop_argument_stack register \{
   sub pointer$argument_stack, jo_size
   mov register, [pointer$argument_stack]
\}

}

----------------------------------

pointer

match =32bit, machine {

pointer$argument_stack:
   xx address$argument_stack

}

push & pop

match =32bit, machine {

macro push_argument_stack register \{
   if register in <eax>
   push ebx
   mov ebx, [pointer$argument_stack]
   mov [ebx], register
   add ebx, jo_size
   mov [pointer$argument_stack], ebx
   pop ebx
   else
   push eax
   mov eax, [pointer$argument_stack]
   mov [eax], register
   add eax, jo_size
   mov [pointer$argument_stack], eax
   pop eax
   finish if
\}

macro pop_argument_stack register \{
   if register in <eax>
   push ebx
   mov ebx, [pointer$argument_stack]
   sub ebx, jo_size
   mov register, [ebx]
   mov [pointer$argument_stack], ebx
   pop ebx
   else
   push eax
   mov eax, [pointer$argument_stack]
   sub eax, jo_size
   mov register, [eax]
   mov [pointer$argument_stack], eax
   pop eax
   finish if
\}

}

----------------------------------

return_stack

----------------------------------

memory allocation

   preserve 64 * jo_size
address$return_stack labeling
   preserve 1024 * 1024 * jo_size

----------------------------------

pointer

match =64bit, machine {

;; if you want to extend cicada in assembly
;; the following registers must NOT be used

define pointer$return_stack r14

}

push & pop

match =64bit, machine {

macro push_return_stack register \{
   mov [pointer$return_stack], register
   add pointer$return_stack, jo_size
\}

macro pop_return_stack register \{
   sub pointer$return_stack, jo_size
   mov register, [pointer$return_stack]
\}

}

----------------------------------

pointer

match =32bit, machine {

pointer$return_stack:
   xx address$return_stack

}

push & pop

match =32bit, machine {

macro push_return_stack register \{
   if register in <eax>
   push ebx
   mov ebx, [pointer$return_stack]
   mov [ebx], register
   add ebx, jo_size
   mov [pointer$return_stack], ebx
   pop ebx
   else
   push eax
   mov eax, [pointer$return_stack]
   mov [eax], register
   add eax, jo_size
   mov [pointer$return_stack], eax
   pop eax
   finish if
\}

macro pop_return_stack register \{
   if register in <eax>
   mov ebx, [pointer$return_stack]
   sub ebx, jo_size
   mov register, [ebx]
   mov [pointer$return_stack], ebx
   else
   mov eax, [pointer$return_stack]
   sub eax, jo_size
   mov register, [eax]
   mov [pointer$return_stack], eax
   finish if
\}

}

----------------------------------

-----------------------------------

next

match =64bit, machine {

macro next \{
   pop_return_stack rbx
     mov rax, [rbx]
   add rbx, jo_size
   push_return_stack rbx
     jmp qword [rax]
\}

}


match =32bit, machine {

macro next \{
   pop_return_stack rbx
     mov rax, [rbx]
   add rbx, jo_size
   push_return_stack rbx
     jmp dword [rax]
\}

}

note play with jo & jojo

  1. at the beginning
    • argument-stack << 2 >>
    • return-stack
      - [ (square) ]
          (square)
          (end)
              
  2. next
    • argument-stack << 2 >>
    • return-stack
          (square)
      - [ (square) ] - [ (dup) ]
          (end)          (mul)
                         (end)
              
  3. next
    • argument-stack << 2, 2 >>
    • return-stack
          (square)       (dup)
      - [ (square) ] - [ (mul) ]
          (end)          (end)
              
  4. next
    • argument-stack << 4 >>
    • return-stack
                         (dup)
          (square)       (mul)
      - [ (square) ] - [ (end) ]
          (end)
              
  5. next
    • argument-stack << 4 >>
    • return-stack
          (square)
          (square)
      - [ (end) ] - [ (dup) ]
                      (mul)
                      (end)
              
  6. next
    • argument-stack << 4, 4 >>
    • return-stack
          (square)
          (square)    (dup)
      - [ (end) ] - [ (mul) ]
                      (end)
              
  7. next
    • argument-stack << 16 >>
    • return-stack
          (square)    (dup)
          (square)    (mul)
      - [ (end) ] - [ (end) ]
              
  8. next
    • argument-stack << 16 >>
    • return-stack
          (square)
          (square)
      - [ (end) ]
              
  9. next
    • argument-stack << 16 >>
    • return-stack
      - [  ]
              
  10. it is really simple ^-^ is it not ?

-----------------------------------

helper function in assembly code

----------------------------------

__exit_with_TOS

match =linux =64bit, platform machine {

__exit_with_TOS:
   pop_argument_stack linux64_sys_1_rdi
   mov linux64_sys_n_rax, linux64_syscall_exit
   syscall

}

__exit_with_zero

match =linux =64bit, platform machine {

__exit_with_zero:
   xor linux64_sys_1_rdi, linux64_sys_1_rdi
   mov linux64_sys_n_rax, linux64_syscall_exit
   syscall

}

__exit_with_six

match =linux =64bit, platform machine {

__exit_with_six:
   mov linux64_sys_1_rdi, 6
   mov linux64_sys_n_rax, linux64_syscall_exit
   syscall

}

----------------------------------

__exit_with_TOS

match =linux =32bit, platform machine {

__exit_with_TOS:
   pop_argument_stack linux32_sys_1_ebx
   mov linux32_sys_n_eax, linux32_syscall_exit
   syscall

}

__exit_with_zero

match =linux =32bit, platform machine {

__exit_with_zero:
   xor linux32_sys_1_ebx, linux32_sys_1_ebx
   mov linux32_sys_n_eax, linux32_syscall_exit
   syscall

}

__exit_with_six

match =linux =32bit, platform machine {

__exit_with_six:
   mov linux32_sys_1_ebx, 6
   mov linux32_sys_n_eax, linux32_syscall_exit
   syscall

}

----------------------------------

__exit_with_TOS

match =windows =64bit, platform machine {

__exit_with_TOS:

windows64_function 4
   sub rsp, 8*4
   pop_argument_stack windows64_fun_1_rcx
   call [ExitProcess]
end_windows64_function

}

__exit_with_zero

match =windows =64bit, platform machine {

__exit_with_zero:

windows64_function 4
   sub rsp, 8*4
   xor windows64_fun_1_rcx, windows64_fun_1_rcx
   call [ExitProcess]
end_windows64_function

}

__exit_with_six

match =windows =64bit, platform machine {

__exit_with_six:

windows64_function 4
   sub rsp, 8*4
   mov windows64_fun_1_rcx, 6
   call [ExitProcess]
end_windows64_function

}

----------------------------------

__exit_with_TOS

match =windows =32bit, platform machine {

__exit_with_TOS:

   pop_argument_stack rax
   push rax
   call [ExitProcess]

}

__exit_with_zero

match =windows =32bit, platform machine {

__exit_with_zero:

   push 0
   call [ExitProcess]

}

__exit_with_six

match =windows =32bit, platform machine {

__exit_with_six:

   push 6
   call [ExitProcess]

}

----------------------------------

-----------------------------------

macro for jo & explainer

----------------------------------

link

;; initial link to point to 0 (as null)
link = 0

----------------------------------

note primitive_string_heap

memory allocation

size$primitive_string_heap = 64 * 1024 ;; (byte)

address$primitive_string_heap:
   times size$primitive_string_heap db 0

current_free_address$primitive_string_heap = address$primitive_string_heap

make_primitive_string

  • 2 bytes for length of name_string
  • note that the following is using local label
macro make_primitive_string string {

virtual at 0
.start$string:
   db string
.end$string:
   dw (.end$string - .start$string)
   load .length word from (.end$string)
finish virtual
store word .length at (current_free_address$primitive_string_heap)

current_free_address$primitive_string_heap = current_free_address$primitive_string_heap + 2

repeat .length
   virtual at 0
      db string
      load .char byte from (% - 1)
   finish virtual
   store byte .char at (current_free_address$primitive_string_heap)
   current_free_address$primitive_string_heap = current_free_address$primitive_string_heap + 1
finish repeat

}

----------------------------------

note

  • note that after a “next” “jmp” to a explainer the “rax” stores the value of the jo to be explained so “rax” is used as an inexplicit argument of the following functions
  • explain$function is used as jojo-head and explains the meaning of the jojo as function
  • a jojo-head identifies one type of jo

define_function

macro define_function string, jo {

define_function__#jo:

name__#jo:
   xx current_free_address$primitive_string_heap

   make_primitive_string string

link__#jo:
   xx link
   link = link__#jo

jo:
   xx explain$function

   ;; here follows a jojo as function-body

}

explain$function

  • find a jojo from a function-jo and push the jojo to return-stack
  • a jojo can not be of size 0
  • use rax as an argument which stores a jo
explain$function:
   mov rbx, [current_free_address$local_data_heap]
   push_return_stack rbx
   add rax, jo_size
   push_return_stack rax
   next

----------------------------------

note

  • primitive functions are special they explain themself and their type is not identified by jojo-head

define_primitive_function

macro define_primitive_function string, jo {

define_primitive_function__#jo:

name__#jo:
   xx current_free_address$primitive_string_heap

   make_primitive_string string

link__#jo:
   xx link
   link = link__#jo

jo:
   xx assembly_code__#jo

assembly_code__#jo:

   ;; here follows assembly code
   ;; as primitive function body

}

----------------------------------

note

  • no constant only variable
  • when a variable jo in the jojo it push the value of the variable to argument_stack
  • when wish to change a variable’s value use key_word “address” to get the address of the variable

define_variable

macro define_variable string, jo {

define_variable__#jo:

name__#jo:
   xx current_free_address$primitive_string_heap

   make_primitive_string string

link__#jo:
   xx link
   link = link__#jo

jo:
   xx explain$variable

   ;; here follows a value of jo_size
   ;; only one value is allowed

}

explain$variable

explain$variable:
   add rax, jo_size
   mov rbx, [rax]
   push_argument_stack rbx
   next

----------------------------------

macro for make-jojo

----------------------------------

note

  • the same as function we need to redefine it for the value of explainer is used to decide the type of the jo

define_macro

macro define_macro string, jo {

define_macro__#jo:

name__#jo:
   xx current_free_address$primitive_string_heap

   make_primitive_string string

link__#jo:
   xx link
   link = link__#jo

jo:
   xx explain$macro

   ;; here follows a jojo as function-body

}

explain$macro

explain$macro:
   mov rbx, [current_free_address$local_data_heap]
   push_return_stack rbx
   add rax, jo_size
   push_return_stack rax
   next

----------------------------------

note

  • explain$exception will
    1. search the return-stack for that exception
    2. special side-effect on return-stack to do exception handling

define_exception

macro define_exception string, jo {

define_exception__#jo:

name__#jo:
   xx current_free_address$primitive_string_heap

   make_primitive_string string

link__#jo:
   xx link
   link = link__#jo

jo:
   xx explain$exception

   ;; here follows a jojo as function-body

}

note return-stack in action

  1. when “explain$exception” is called jojo by jojo it searchs the jo stored in “rax” in the return-stack of course only jojo with “exception_head” as head needs to be searched
  2. for example we have
    define_exception "!exception-1", !exception_1
       xx fun1
       xx fun2
       xx end
        
  3. return-stack
                                             (prepare_for)
                                               (exception_head)
                                               (!exception_1)
                                               (!exception_2)
                                               (end_of_prepare)
                    (prepare_for)            (function_1)
    - [ pointer ] - [ (exception_head) ] - [ (function_2) ] - [ (!exception_1) ]
                      (!exception_1)         (end)              (end)
                      (!exception_2)
                      (end_of_prepare)
                    (function_1)
                    (function_2)
                    (end)
    
    the pointer above is into argument-stack
        
  4. next
    • pointer$argument_stack should be set to the pointer above
    • and to call “next” again the return-stack should be change to
      - [ (fun1) ]
          (fun2)
          (end)
              

note the plan

  • so we need a two-level loop
  • note that although we have to use assembly code to write primitive functions but we still can use argument-stack to pass arguments

explain$exception

  • no error handling for now
match =64bit, machine {

explain$exception:
   mov rsi, rax

.next_jojo:
   pop_return_stack rbx
   mov rax, qword [rbx]
   cmp rax, exception_head
   je .next_jo
   cmp pointer$return_stack, address$return_stack
   je .not_found
   jmp .next_jojo


.next_jo:
   ;; expecting
   ;;   rbx jojo
   ;;   rsi jo (to cmp)
   add rbx, jo_size
   mov rax, qword [rbx]
   cmp rax, rsi
   je .found
   test rax, rax
   jz .next_jojo
   jmp .next_jo


.found:
   ;; expecting
   ;;   pointer$return_stack
   ;;   rsi jo
   pop_return_stack rax
   mov pointer$argument_stack, rax

   mov rbx, [current_free_address$local_data_heap]
   push_return_stack rbx

   add rsi, jo_size
   push_return_stack rsi
   next

.not_found:
   call __exit_with_six

}

explain$exception

  • no error handling for now
match =32bit, machine {

explain$exception:
   mov rsi, rax

.next_jojo:
   pop_return_stack rbx
   mov rax, dword [rbx]
   cmp rax, exception_head
   je .next_jo
   mov rdx, [pointer$return_stack]
   cmp rdx, address$return_stack
   je .not_found
   jmp .next_jojo


.next_jo:
   ;; expecting
   ;;   rbx jojo
   ;;   rsi jo (to cmp)
   add rbx, jo_size
   mov rax, dword [rbx]
   cmp rax, rsi
   je .found
   test rax, rax
   jz .next_jojo
   jmp .next_jo


.found:
   ;; expecting
   ;;   pointer$return_stack
   ;;   rsi jo
   pop_return_stack rax
   mov [pointer$argument_stack], rax

   mov rbx, [current_free_address$local_data_heap]
   push_return_stack rbx

   add rsi, jo_size
   push_return_stack rsi
   next

.not_found:
   call __exit_with_six

   }

----------------------------------

execute-jo & structure of jo

----------------------------------

execute-jo

match =64bit, machine {

define_primitive_function "execute-jo", execute_jo
   ;; << jo -- UNKNOWN >>
   pop_argument_stack rax
   jmp qword [rax]

}


match =32bit, machine {

define_primitive_function "execute-jo", execute_jo
   ;; << jo -- UNKNOWN >>
   pop_argument_stack eax
   jmp dword [eax]

}

----------------------------------

jo-size

define_variable "*jo-size*", V__jo_size
   xx jo_size

jo->name

define_function "jo->name", jo_to_name
   ;; << jo -- string[address, length] >>
   xx literal, jo_size, subtraction
   xx literal, jo_size, subtraction
   xx fetch
   xx address_to_primitive_string
   xx end

jo->link

define_function "jo->link", jo_to_link
   ;; << jo -- link >>
   xx literal, jo_size
   xx subtraction
   xx end

last-jo,dictionary?

  • first jo in assembly code is the last jo in dictionary
define_function "last-jo,dictionary?", last_jo__dictionary?
   ;; << jo -- bool >>
   xx jo_to_link
   xx fetch
   xx zero?
   xx end

jo->pre-jo

  • treat last-jo,dictionary specially i.e. return zero on that case
define_function "jo->pre-jo", jo_to_pre_jo
   ;; << jo -- pre-jo >>
   xx jo_to_link
   xx fetch
   xx dup, zero?, false?branch, 2
   xx   end
   xx literal, jo_size
   xx addition
   xx end

jo->type

  • the type of primitive function jo is encoded by 0
  • other types of jo are encoded by their explainers
define_function "jo->type", jo_to_type
   ;; << jo -- type >>
   xx dup

   xx dup, fetch
   xx swap, subtraction, literal, jo_size, equal?, false?branch, 4
   xx   drop, zero
   xx   end

   xx fetch
   xx end

----------------------------------

primitive-string-heap

primitive-string-heap

define_variable "*primitive-string-heap*", V__primitive_string_heap
   xx address$primitive_string_heap

define_variable "*size,primitive-string-heap*", V__size__primitive_string_heap
   xx size$primitive_string_heap

;; *current-free-address,primitive-string-heap*
;; is at epilog

address->primitive-string

define_function "address->primitive-string", address_to_primitive_string
   ;; << address -- string[address, length] >>
   xx dup
   xx literal, 2, addition  ;; address
   xx swap, fetch_two_bytes ;; length
   xx end

type of jo

primitive-function-jo?

define_function "primitive-function-jo?", primitive_function_jo?
   ;; << jo -- bool >>
   xx jo_to_type
   xx zero?
   xx end

function-jo?

define_function "function-jo?", function_jo?
   ;; << jo -- bool >>
   xx jo_to_type
   xx literal, explain$function
   xx equal?
   xx end

macro-jo?

define_function "macro-jo?", macro_jo?
   ;; << jo -- bool >>
   xx jo_to_type
   xx literal, explain$macro
   xx equal?
   xx end

exception-jo?

define_function "exception-jo?", exception_jo?
   ;; << jo -- bool >>
   xx jo_to_type
   xx literal, explain$exception
   xx equal?
   xx end

variable-jo?

define_function "variable-jo?", variable_jo?
   ;; << jo -- bool >>
   xx jo_to_type
   xx literal, explain$variable
   xx equal?
   xx end

-----------------------------------

end & taca

end

define_primitive_function "end", end
   pop_return_stack rbx
   pop_return_stack rax
   mov [current_free_address$local_data_heap], rax
   next

taca

  • tail-call
match =64bit, machine {

define_primitive_function "<>", taca
   pop_return_stack rbx
   pop_return_stack rax
   mov [current_free_address$local_data_heap], rax
   mov rax, [rbx]
   jmp qword [rax]
}


match =32bit, machine {

define_primitive_function "<>", taca
   pop_return_stack ebx
   pop_return_stack ecx
   mov [current_free_address$local_data_heap], ecx
   mov eax, [ebx]
   jmp dword [eax]

;; ><><>< can not be the following
;; maybe still something wrong with pop_return_stack
;; but I care less about this now
;; define_primitive_function "<>", taca
;;    pop_return_stack ebx
;;    pop_return_stack eax
;;    mov [current_free_address$local_data_heap], eax
;;    mov eax, [ebx]
;;    jmp dword [eax]

}

note explicit tail call in action

  1. the tail position of a function body must be recognized explicit tail call is used to achieve this
  2. thus tail-recursive-call can be use to do loop without pushing too many address into return-stack
  3. for example if we have a function which is called “example”
    define_function "example", example
       xx fun1
       xx fun2
       xx taca, example
        
  4. and we have the following jojo in return-stack
    - [ (example) ]
        (end)
        
  5. next
        (example)
    - [ (end) ] - [ (fun1) ]
                    (fun2)
                    (taca)
                    (example)
        
  6. next
        (example)   (fun1)
    - [ (end) ] - [ (fun2) ]
                    (taca)
                    (example)
        
  7. next
                    (fun1)
        (example)   (fun2)
    - [ (end) ] - [ (taca) ]
                    (example)
        
  8. next by the definition of taca
        (example)
    - [ (end) ] - [ (fun1) ]
                    (fun2)
                    (taca)
                    (example)
        
  9. you can see return-stack of (8.) is the same as (5.) it is clear how the example function is actually a loop now

-----------------------------------

the story begin

begin_to_interpret_threaded_code

match =linux =64bit, platform machine {

begin_to_interpret_threaded_code:

   cld ;; set DF = 0, then rsi and rdi are incremented

   mov pointer$argument_stack,  address$argument_stack
   mov pointer$return_stack,    address$return_stack

   mov rax, first_jojo
   push_return_stack rax
   next

}

begin_to_interpret_threaded_code

match =linux =32bit, platform machine {

begin_to_interpret_threaded_code:

   cld ;; set DF = 0, then rsi and rdi are incremented

   mov eax, first_jojo
   push_return_stack eax
   next

}

begin_to_interpret_threaded_code

match =windows =64bit, platform machine {

_output_handle:
   xx 0
_input_handle:
   xx 0

begin_to_interpret_threaded_code:

   cld ;; set DF = 0, then rsi and rdi are incremented

windows64_function 4
   sub rsp, 8*4
   mov windows64_fun_1_rcx, STD_INPUT_HANDLE
   call [GetStdHandle]
   mov [_input_handle], rax
end_windows64_function

windows64_function 4
   sub rsp, 8*4
   mov windows64_fun_1_rcx, STD_OUTPUT_HANDLE
   call [GetStdHandle]
   mov [_output_handle], rax
end_windows64_function

   mov pointer$argument_stack,  address$argument_stack
   mov pointer$return_stack,    address$return_stack

   mov rax, first_jojo
   push_return_stack rax
   next

}

begin_to_interpret_threaded_code

match =windows =32bit, platform machine {

_output_handle:
   xx 0
_input_handle:
   xx 0

begin_to_interpret_threaded_code:

   cld ;; set DF = 0, then rsi and rdi are incremented

   push STD_INPUT_HANDLE
   call [GetStdHandle]
   mov [_input_handle], rax

   push STD_OUTPUT_HANDLE
   call [GetStdHandle]
   mov [_output_handle], rax

   mov rax, first_jojo
   push_return_stack rax
   next

}

first_jojo

  • you can use the following “xx little_test” to do some little tests
first_jojo:
   xx welcome
   ;; xx little_test
   xx initialize_dispatch_word_stack
   xx initialize_local_variable
match =linux, platform {
   xx init_operating_system_environment
}
   xx load_core_file
   xx basic_REPL

welcome

define_function "welcome", welcome
   ;; << -- >>
   xx literal, string$welcome_to_cicada_nymph
   xx literal, length$welcome_to_cicada_nymph
   xx write_string
   xx end

string$welcome_to_cicada_nymph:
   db 10
   db "* welcome to cicada-nymph ^-^"
   db 10
.end:
length$welcome_to_cicada_nymph = (.end - string$welcome_to_cicada_nymph)

exit_with_TOS a.k.a. bye

define_primitive_function "bye", exit_with_TOS
   call __exit_with_TOS

little_test

define_variable "", V__little_test_number
   xx 3


define_function "little_test", little_test

   ;;;; variable
   ;; xx V__little_test_number
   ;; xx exit_with_TOS
   ;;;; exit ocde : 3

   ;;;; literal
   ;; xx literal, 4
   ;; xx exit_with_TOS
   ;;;; exit ocde : 4

   ;;;; address
   ;; xx address, V__little_test_number, fetch, add2
   ;; xx address, V__little_test_number, save
   ;; xx V__little_test_number
   ;; xx exit_with_TOS
   ;;;; exit ocde : 5

   ;;;; end
   ;; xx literal, 2, negate
   ;; xx literal, 8
   ;; xx addition
   ;; xx exit_with_TOS
   ;;;; 6

   ;;;; taca
   ;; xx literal, 2
   ;; xx literal, 4
   ;; xx power
   ;; xx exit_with_TOS
   ;;;; exit ocde : 16

   ;;;; write_byte
   ;; xx literal, 64, write_byte
   ;; xx literal, 10, write_byte
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; @

   ;;;; read_byte
   ;; xx read_byte, write_byte
   ;; xx exit_with_TOS
   ;;;;

   ;;;; branch
   ;; xx read_byte, write_byte
   ;; xx branch, -3
   ;;;; read a string that ended by <return>
   ;;;; write the readed string
   ;;;; or we can say
   ;;;; read line and write line
   ;;;; or we can say
   ;;;; echo line

   ;;;; false?branch
   ;; xx false, false?branch, 9
   ;; xx   literal, 64, write_byte
   ;; xx   literal, 10, write_byte
   ;; xx   zero
   ;; xx   exit_with_TOS
   ;; xx true, false?branch, 9
   ;; xx   literal, 65, write_byte
   ;; xx   literal, 10, write_byte
   ;; xx   zero
   ;; xx   exit_with_TOS
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; A

   ;;;; read_word & write_string
   ;; xx read_word, write_string
   ;; xx literal, 10, write_byte
   ;; xx read_word_for_REPL, write_string
   ;; xx literal, 10, write_byte
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; read line
   ;;;; write first two words of the line

   ;;;; string->integer
   ;; xx read_word, string_to_integer
   ;; xx exit_with_TOS
   ;;;; type 123
   ;;;; exit code 123

   ;;;; use jo_to_name to test the macro make_primitive_string
   ;; xx literal, jo_to_name, jo_to_name, write_string
   ;; xx literal, 10, write_byte
   ;; xx literal, addition, jo_to_name, write_string
   ;; xx literal, 10, write_byte
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; print "jo->name"
   ;;;; print "add"

   ;;;; xxoverxx
   ;; xx literal, 1
   ;; xx literal, 2
   ;; xx literal, 3
   ;; xx literal, 4
   ;; xx xxoverxx
   ;; xx pretty_write_integer
   ;; xx pretty_write_integer
   ;; xx pretty_write_integer
   ;; xx pretty_write_integer
   ;; xx pretty_write_integer
   ;; xx pretty_write_integer
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; 2 1 4 3 2 1

   ;;;; find
   ;; xx read_word, string_to_integer ;; number
   ;; xx read_word, string_to_integer ;; number
   ;; xx read_word, find ;; add
   ;; xx drop ;; true
   ;; xx execute_jo
   ;; xx write_integer
   ;; xx zero
   ;; xx exit_with_TOS
   ;;;; 1 2 add
   ;;;; print "3"

   ;;;; basic-REPL (without the ability to define function)
   ;;;; after this test
   ;;;; we will use basic-REPL to do further tests
   ;; xx basic_REPL
   ;;;; 1 2 add .

-----------------------------------

the stack

----------------------------------

drop

define_primitive_function "drop", drop
   ;; << a -- >>
   pop_argument_stack rax
   next

define_primitive_function "drop2", drop2
   ;; << a b -- >>
   pop_argument_stack rax
   pop_argument_stack rax
   next

dup

match =64bit, machine {

define_primitive_function "dup", dup
   ;; << a -- a, a >>
   mov  rax, [pointer$argument_stack - (1 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "dup2", dup2
   ;; << a b -- a b a b >>
   mov  rbx, [pointer$argument_stack - (1 * jo_size)]
   mov  rax, [pointer$argument_stack - (2 * jo_size)]
   push_argument_stack rax
   push_argument_stack rbx
   next

}

dup

match =32bit, machine {

define_primitive_function "dup", dup
   ;; << a -- a a >>
   pop_argument_stack rax
   push_argument_stack rax
   push_argument_stack rax
   next

define_primitive_function "dup2", dup2
   ;; << a b -- a b a b >>
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rax
   push_argument_stack rbx
   next

}

over

match =64bit, machine {

define_primitive_function "over", over
   ;; << a b -- a b | a >>
   mov  rax, [pointer$argument_stack - (2 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xx", xoverxx
   ;; << a | b c -- a | b c | a >>
   mov  rax, [pointer$argument_stack - (3 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|x", xxoverx
   ;; << a b | c -- a b | c | a b >>
   mov  rax, [pointer$argument_stack - (3 * jo_size)]
   push_argument_stack rax
   mov  rax, [pointer$argument_stack - (3 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|xx", xxoverxx
   ;; << a b | c d -- a b | c d | a b >>
   mov  rax, [pointer$argument_stack - (4 * jo_size)]
   push_argument_stack rax
   mov  rax, [pointer$argument_stack - (4 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xxx", xoverxxx
   ;; << a | b c d -- a | b c d | a >>
   mov  rax, [pointer$argument_stack - (4 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xxxx", xoverxxxx
   ;; << a | b c d -- a | b c d | a >>
   mov  rax, [pointer$argument_stack - (5 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|xxxx", xxoverxxxx
   ;; << a b | c d e f -- a b | c d e f | a b >>
   mov  rax, [pointer$argument_stack - (6 * jo_size)]
   push_argument_stack rax
   mov  rax, [pointer$argument_stack - (6 * jo_size)]
   push_argument_stack rax
   next

}

over

match =32bit, machine {

define_primitive_function "over", over
   ;; << a b -- a b | a >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (2 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xx", xoverxx
   ;; << a | b c -- a | b c | a >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (3 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|x", xxoverx
   ;; << a b | c -- a b | c | a b >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (3 * jo_size)]
   push_argument_stack rax
   mov rax, [rbx - (2 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|xx", xxoverxx
   ;; << a b | c d -- a b | c d | a b >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (4 * jo_size)]
   push_argument_stack rax
   mov rax, [rbx - (3 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xxx", xoverxxx
   ;; << a | b c d -- a | b c d | a >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (4 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "x|over|xxxx", xoverxxxx
   ;; << a | b c d -- a | b c d | a >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (5 * jo_size)]
   push_argument_stack rax
   next

define_primitive_function "xx|over|xxxx", xxoverxxxx
   ;; << a b | c d e f -- a b | c d e f | a b >>
   mov rbx, [pointer$argument_stack]
   mov rax, [rbx - (6 * jo_size)]
   push_argument_stack rax
   mov rax, [rbx - (5 * jo_size)]
   push_argument_stack rax
   next

}

tuck

define_primitive_function "tuck", tuck
   ;; << a b -- b | a b >>
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rax
   push_argument_stack rbx
   next

define_primitive_function "x|tuck|xx", xtuckxx
   ;; << a | b c -- b c | a | b c >>
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   next

define_primitive_function "xx|tuck|x", xxtuckx
   ;; << a b | c -- c | a b | c >>
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rcx
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   next

define_primitive_function "xx|tuck|xx", xxtuckxx
   ;; << a b | c d -- c d | a b | c d >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rcx
   push_argument_stack rdx
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   next

define_primitive_function "xxx|tuck|x", xxxtuckx
   ;; << a b c | d -- d | a b c | d >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rdx
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   next

swap

match =64bit, machine {

define_primitive_function "swap", swap
   ;; << a b -- b a >>
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rax
   next

define_primitive_function "x|swap|xx", xswapxx
   ;; << a | b c -- b c | a >>
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rax
   next

define_primitive_function "xx|swap|x", xxswapx
   ;; << a b | c -- c | a b >>
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rcx
   push_argument_stack rax
   push_argument_stack rbx
   next

define_primitive_function "x|swap|xxx", xswapxxx
   ;; << a | b c d -- b c d | a >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   push_argument_stack rax
   next

define_primitive_function "xxx|swap|x", xxxswapx
   ;; << a b c | d -- d | a b c >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rdx
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   next

define_primitive_function "xx|swap|xx", xxswapxx
   ;; << a b | c d -- c d | a b >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rcx
   push_argument_stack rdx
   push_argument_stack rax
   push_argument_stack rbx
   next


define_primitive_function "x|swap|xxxx", xswapxxxx
   ;; << a | b c d e -- b c d e | a >>
   pop_argument_stack r8 ;; e
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   push_argument_stack r8 ;; e
   push_argument_stack rax
   next

define_primitive_function "xxxx|swap|x", xxxxswapx
   ;; << a b c d | e --  e | a b c d >>
   pop_argument_stack r8 ;; e
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack r8 ;; e
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   next


define_primitive_function "xx|swap|xxxx", xxswapxxxx
   ;; << a b | c d e f -- c d e f | a b >>
   pop_argument_stack r9 ;; f
   pop_argument_stack r8 ;; e
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack rcx
   push_argument_stack rdx
   push_argument_stack r8 ;; e
   push_argument_stack r9 ;; f
   push_argument_stack rax
   push_argument_stack rbx
   next

define_primitive_function "xxxx|swap|xx", xxxxswapxx
   ;; << a b c d | e f --  e f | a b c d >>
   pop_argument_stack r9 ;; f
   pop_argument_stack r8 ;; e
   pop_argument_stack rdx
   pop_argument_stack rcx
   pop_argument_stack rbx
   pop_argument_stack rax
   push_argument_stack r8 ;; e
   push_argument_stack r9 ;; f
   push_argument_stack rax
   push_argument_stack rbx
   push_argument_stack rcx
   push_argument_stack rdx
   next

}

swap

match =32bit, machine {

define_primitive_function "swap", swap
   ;; << a b -- b a >>
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ebx
   push_argument_stack eax
   next

define_primitive_function "x|swap|xx", xswapxx
   ;; << a | b c -- b c | a >>
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   push_argument_stack eax
   next

define_primitive_function "xx|swap|x", xxswapx
   ;; << a b | c -- c | a b >>
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ecx
   push_argument_stack eax
   push_argument_stack ebx
   next

define_primitive_function "x|swap|xxx", xswapxxx
   ;; << a | b c d -- b c d | a >>
   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   push_argument_stack edx
   push_argument_stack eax
   next

define_primitive_function "xxx|swap|x", xxxswapx
   ;; << a b c | d -- d | a b c >>
   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack edx
   push_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   next

define_primitive_function "xx|swap|xx", xxswapxx
   ;; << a b | c d -- c d | a b >>
   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ecx
   push_argument_stack edx
   push_argument_stack eax
   push_argument_stack ebx
   next


define_primitive_function "x|swap|xxxx", xswapxxxx
   ;; << a | b c d e -- b c d e | a >>
   pop_argument_stack eax ;; e
   push eax

   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   push_argument_stack edx

   pop eax
   push_argument_stack eax ;; e

   push_argument_stack eax
   next

define_primitive_function "xxxx|swap|x", xxxxswapx
   ;; << a b c d | e --  e | a b c d >>
   pop_argument_stack eax ;; e
   push eax

   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax

   pop eax
   push_argument_stack eax ;; e

   push_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   push_argument_stack edx
   next


define_primitive_function "xx|swap|xxxx", xxswapxxxx
   ;; << a b | c d e f -- c d e f | a b >>
   pop_argument_stack eax ;; f
   push eax

   pop_argument_stack eax ;; e
   push eax

   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax
   push_argument_stack ecx
   push_argument_stack edx

   pop eax
   push_argument_stack eax ;; e

   pop eax
   push_argument_stack eax ;; f

   push_argument_stack eax
   push_argument_stack ebx
   next

define_primitive_function "xxxx|swap|xx", xxxxswapxx
   ;; << a b c d | e f --  e f | a b c d >>
   pop_argument_stack eax ;; f
   push eax

   pop_argument_stack eax ;; e
   push eax

   pop_argument_stack edx
   pop_argument_stack ecx
   pop_argument_stack ebx
   pop_argument_stack eax

   pop eax
   push_argument_stack eax ;; e

   pop eax
   push_argument_stack eax ;; f

   push_argument_stack eax
   push_argument_stack ebx
   push_argument_stack ecx
   push_argument_stack edx
   next

}

----------------------------------

address

define_variable "*the-stack*", V__the_stack
   xx address$argument_stack

pointer

match =64bit, machine {

define_variable "*the-stack-pointer-snapshot*", V__the_stack_pointer_snapshot
   xx address$argument_stack

define_primitive_function "snapshot-the-stack-pointer", snapshot_the_stack_pointer
   ;; << -- >>
   mov [V__the_stack_pointer_snapshot + jo_size], pointer$argument_stack
   next

}

pointer

match =32bit, machine {

define_variable "*the-stack-pointer-snapshot*", V__the_stack_pointer_snapshot
   xx address$argument_stack

define_primitive_function "snapshot-the-stack-pointer", snapshot_the_stack_pointer
   ;; << -- >>
   mov eax, [pointer$argument_stack]
   mov [V__the_stack_pointer_snapshot + jo_size], eax
   next

}

----------------------------------

instruction

----------------------------------

note side-effect

  • an instruction is a special primitive function which does special side-effect on return-stack
  • note that side-effect on return-stack should all be done in primitive functions

note naming

  • the naming convention in assembly code of instruction is the same as it of jo
  • the name of an instruction might not be exported to cicada-language as a function but as a variable
  • the name of a special primitive function in assembly code maybe reused as a macro word in cicada-language but the name of the macro in assembly code is prefixed by “M__”

----------------------------------

literal

define_variable "*literal*", V__literal
   xx literal

define_primitive_function "", literal
   ;; << -- fixnum >>
   pop_return_stack rbx
     mov rax, [rbx]
     push_argument_stack rax
   add rbx, jo_size
   push_return_stack rbx
   next

address

define_variable "*address*", V__address
   xx address

define_primitive_function "", address
   ;; << -- address >>
   pop_return_stack rbx
     mov rax, [rbx]
     add rax, jo_size
     push_argument_stack rax
   add rbx, jo_size
   push_return_stack rbx
   next

----------------------------------

branch

define_variable "*branch*", V__branch
   xx branch

define_primitive_function "", branch
   pop_return_stack rbx
   mov rax, [rbx]
   imul rax, jo_size
   add rbx, rax
   push_return_stack rbx
   next

false?branch

define_variable "*false?branch*", V__false?branch
   xx false?branch

define_primitive_function "", false?branch
   ;; << true of false -- >>
   pop_argument_stack rax
   test rax, rax
   jnz help__false?branch__not_to_branch

   pop_return_stack rbx
   mov rax, [rbx]
   imul rax, jo_size
   add rbx, rax
   push_return_stack rbx
   next

help__false?branch__not_to_branch:
   pop_return_stack rbx
   add rbx, jo_size
   push_return_stack rbx
   next

----------------------------------

note return-stack in action

  1. proper exception handling is implemented by doing side-effect on return-stack
  2. when executing the following code block
    xx prepare_for
    xx exception_head
    xx   !exception_1
    xx   !exception_2
    xx   end_of_prepare
    xx function_1
    xx function_2
    xx end_of_prepare
        
  3. return-stack
    - [ (prepare_for) ]
          (exception_head)
          (!exception_1)
          (!exception_2)
          (end_of_prepare)
        (function_1)
        (function_2)
        (end)
        
  4. next
    • this is how the return-stack looks right before exception_head is executed
        (prepare_for)
      - [ (exception_head) ]
          (!exception_1)
          (!exception_2)
          (end_of_prepare)
        (function_1)
        (function_2)
        (end)
              
    • after exception_head is executed
                                               (prepare_for)
                                                 (exception_head)
                                                 (!exception_1)
                                                 (!exception_2)
                      (prepare_for)              (end_of_prepare)
      - [ pointer ] - [ (exception_head) ] - [ (function_1) ]
                        (!exception_1)         (function_2)
                        (!exception_2)         (end)
                        (end_of_prepare)
                      (function_1)
                      (function_2)
                      (end)
      
      the pointer above is into argument-stack
              

prepare_for

  • prepare for a list of exceptions
match =64bit, machine {

define_primitive_function "", prepare_for
   ;; << -- >>
   pop_return_stack rbx
   pop_return_stack rcx
   push_return_stack pointer$argument_stack
   push_return_stack rbx
   push_return_stack rcx
.next:
   add rbx, jo_size
   mov rax, qword [rbx]
   cmp rax, end_of_prepare
   je .then
   jmp .next
.then:
   add rbx, jo_size
   push_return_stack rbx
   next

}

prepare_for

  • prepare for a list of exceptions
match =32bit, machine {

define_primitive_function "", prepare_for
   ;; << -- >>
   pop_return_stack ebx
   pop_return_stack ecx
   mov eax, [pointer$argument_stack]
   push_return_stack eax
   push_return_stack ebx
   push_return_stack ecx
.next:
   add ebx, jo_size
   mov eax, dword [ebx]
   cmp eax, end_of_prepare
   je .then
   jmp .next
.then:
   add ebx, jo_size
   push_return_stack ebx
   next

}

end_of_prepare

  • used as an unique id
define_variable "*end-of-prepare*", V__end_of_prepare

end_of_prepare:
   xx 0

exception_head

  • this jo is served as a label in return-stack when explained it pops the jojo itself in and it pops the argument-stack pointer after it
  • and “explain$exception” will search for them
define_primitive_function "", exception_head
   ;; << -- >>
   pop_return_stack rax
   pop_return_stack rax
   next

----------------------------------

bool

false & true

  • they are defined as function and viewed as constant
define_primitive_function "false", false
   ;; << -- false >>
   xor rax, rax
   push_argument_stack rax
   next

define_primitive_function "true", true
   ;; << -- true >>
   xor rax, rax
   inc rax
   push_argument_stack rax
   next

false? & true?

define_function "false?", false?
   ;; << bool -- bool >>
   xx false, equal?
   xx end

define_function "true?", true?
   ;; << bool -- bool >>
   xx true, equal?
   xx end

bitwise operations

match =64bit, machine {

define_primitive_function "bitwise-and", bitwise_and
   ;; << a, b -- a and b >>
   pop_argument_stack rbx
   and [pointer$argument_stack - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-or", bitwise_or
   ;; << a, b -- a or b >>
   pop_argument_stack rbx
   or  [pointer$argument_stack - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-xor", bitwise_xor
   ;; << a, b -- a xor b >>
   pop_argument_stack rbx
   xor [pointer$argument_stack - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-invert", bitwise_invert
   ;; << a -- invert a >>
   not qword [pointer$argument_stack - (1 * jo_size)]
   next

}

bitwise operations

match =32bit, machine {

define_primitive_function "bitwise-and", bitwise_and
   ;; << a, b -- a and b >>
   pop_argument_stack rbx
   mov rax, [pointer$argument_stack]
   and [rax - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-or", bitwise_or
   ;; << a, b -- a or b >>
   pop_argument_stack rbx
   mov rax, [pointer$argument_stack]
   or  [rax - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-xor", bitwise_xor
   ;; << a, b -- a xor b >>
   pop_argument_stack rbx
   mov rax, [pointer$argument_stack]
   xor [rax - (1 * jo_size)], rbx
   next

define_primitive_function "bitwise-invert", bitwise_invert
   ;; << a -- invert a >>
   mov rax, [pointer$argument_stack]
   not dword [rax - (1 * jo_size)]
   next

}

fixnum

----------------------------------

zero & one

  • they are defined as function and viewed as constant
define_primitive_function "zero", zero
   ;; << -- 0 >>
   xor rax, rax
   push_argument_stack rax
   next

define_primitive_function "one", one
   ;; << -- 1 >>
   xor rax, rax
   inc rax
   push_argument_stack rax
   next

zero? & one?

define_function "zero?", zero?
   ;; << bool -- bool >>
   xx zero, equal?
   xx end

define_function "one?", one?
   ;; << bool -- bool >>
   xx one, equal?
   xx end

----------------------------------

add & sub

match =64bit, machine {

define_primitive_function "add1", add1
   ;; << n -- n+1 >>
   inc qword [pointer$argument_stack - (1 * jo_size)]
   next

define_primitive_function "add2", add2
   ;; << n -- n+2 >>
   add qword [pointer$argument_stack - (1 * jo_size)], 2
   next

define_primitive_function "add3", add3
   ;; << n -- n+3 >>
   add qword [pointer$argument_stack - (1 * jo_size)], 3
   next

define_primitive_function "add4", add4
   ;; << n -- n+4 >>
   add qword [pointer$argument_stack - (1 * jo_size)], 4
   next

define_primitive_function "add8", add8
   ;; << n -- n+8 >>
   add qword [pointer$argument_stack - (1 * jo_size)], 8
   next


define_primitive_function "sub1", sub1
   ;; << n -- n-1 >>
   dec qword [pointer$argument_stack - (1 * jo_size)]
   next

define_primitive_function "sub2", sub2
   ;; << n -- n-2 >>
   sub qword [pointer$argument_stack - (1 * jo_size)], 2
   next

define_primitive_function "sub3", sub3
   ;; << n -- n-3 >>
   sub qword [pointer$argument_stack - (1 * jo_size)], 3
   next

define_primitive_function "sub4", sub4
   ;; << n -- n-4 >>
   sub qword [pointer$argument_stack - (1 * jo_size)], 4
   next

define_primitive_function "sub8", sub8
   ;; << n -- n-8 >>
   sub qword [pointer$argument_stack - (1 * jo_size)], 8
   next


define_primitive_function "add", addition
   ;; << a b -- a+b >>
   pop_argument_stack rax
   add qword [pointer$argument_stack - (1 * jo_size)], rax
   next

define_primitive_function "sub", subtraction
   ;; << a b -- a-b >>
   pop_argument_stack rax
   sub qword [pointer$argument_stack - (1 * jo_size)], rax
   next

}

add & sub

match =32bit, machine {

define_primitive_function "add1", add1
   ;; << n -- n+1 >>
   pop_argument_stack rax
   inc rax
   push_argument_stack rax
   next

define_primitive_function "add2", add2
   ;; << n -- n+2 >>
   pop_argument_stack rax
   inc rax
   inc rax
   push_argument_stack rax
   next

define_primitive_function "add3", add3
   ;; << n -- n+3 >>
   pop_argument_stack rax
   inc rax
   inc rax
   inc rax
   push_argument_stack rax
   next

define_primitive_function "add4", add4
   ;; << n -- n+4 >>
   pop_argument_stack rax
   inc rax
   inc rax
   inc rax
   inc rax
   push_argument_stack rax
   next

define_primitive_function "add8", add8
   ;; << n -- n+8 >>
   pop_argument_stack rax
   add rax, 8
   push_argument_stack rax
   next


define_primitive_function "sub1", sub1
   ;; << n -- n-1 >>
   pop_argument_stack rax
   dec rax
   push_argument_stack rax
   next

define_primitive_function "sub2", sub2
   ;; << n -- n-2 >>
   pop_argument_stack rax
   dec rax
   dec rax
   push_argument_stack rax
   next

define_primitive_function "sub3", sub3
   ;; << n -- n-3 >>
   pop_argument_stack rax
   dec rax
   dec rax
   dec rax
   push_argument_stack rax
   next

define_primitive_function "sub4", sub4
   ;; << n -- n-4 >>
   pop_argument_stack rax
   dec rax
   dec rax
   dec rax
   dec rax
   push_argument_stack rax
   next

define_primitive_function "sub8", sub8
   ;; << n -- n-8 >>
   pop_argument_stack rax
   sub rax, 8
   push_argument_stack rax
   next


define_primitive_function "add", addition
   ;; << a b -- a+b >>
   pop_argument_stack rbx
   pop_argument_stack rax
   add rax, rbx
   push_argument_stack rax
   next

define_primitive_function "sub", subtraction
   ;; << a b -- a-b >>
   pop_argument_stack rbx
   pop_argument_stack rax
   sub rax, rbx
   push_argument_stack rax
   next

}

mul

define_primitive_function "mul", multiple
   ;; << a b -- a*b >>
   pop_argument_stack  rbx ;; 2ed arg
   pop_argument_stack  rax ;; 1st arg
   imul rbx, rax
   ;; imul will ignore overflow
   ;; when there are two registers as arg
   ;; imul will save the result into the first register
   push_argument_stack rbx
   next

negate

define_function "negate", negate
   ;; << n --  -n >>
   xx zero
   xx swap, subtraction
   xx end

power

define_function "power", power
   ;; n must be nature number for now
   ;; << a, n -- a^n >>
   xx literal, 1, swap ;; leave product
   xx help__power
   xx end

define_function "help,power", help__power
   ;; << a, product, n -- a^n >>
   xx dup, zero?, false?branch, 5
   xx   drop, swap, drop
   xx   end
   xx sub1
   xx swap
   xx   xoverxx, multiple
   xx swap
   xx taca, help__power

div & mod

define_primitive_function "moddiv", moddiv
   ;; << a, b -- a mod b, quotient >>
   ;; << dividend, divisor -- remainder, quotient >>
   ;; the arg of idiv is divisor
   ;; the lower half of dividend is taken from rax
   ;; the upper half of dividend is taken from rdx
   xor  rdx, rdx   ;; high-part of dividend is not used
   pop_argument_stack  rbx ;; 2ed arg
   pop_argument_stack  rax ;; 1st arg
   idiv rbx
   ;; the remainder is stored in rdx
   ;; the quotient  is stored in rax
   push_argument_stack rdx ;; remainder
   push_argument_stack rax ;; quotient
   next


define_function "divmod", divmod
   ;; << a, b -- quotient, a mod b >>
   xx moddiv, swap
   xx end

define_function "div", division
   ;; << a, b -- quotient >>
   xx divmod, drop
   xx end

define_function "mod", modulo
   ;; << a, b -- a mod b >>
   xx moddiv, drop
   xx end

----------------------------------

equal? & greater-than? & less-than?

define_primitive_function "equal?", equal?
   ;; << a, b -- a, b, true of false >>
   pop_argument_stack rbx
   pop_argument_stack rax
   cmp   rbx, rax
   sete  al
   movzx rax, al
   push_argument_stack rax
   next

define_primitive_function "less-than?", less_than?
   pop_argument_stack rbx
   pop_argument_stack rax
   cmp   rax, rbx
   setl  al
   movzx rax, al
   push_argument_stack rax
   next

define_primitive_function "greater-than?", greater_than?
   pop_argument_stack rbx
   pop_argument_stack rax
   cmp   rax, rbx
   setg  al
   movzx rax, al
   push_argument_stack  rax
   next

define_primitive_function "less-or-equal?", less_or_equal?
   pop_argument_stack rbx
   pop_argument_stack rax
   cmp   rax, rbx
   setle al
   movzx rax, al
   push_argument_stack rax
   next

define_primitive_function "greater-or-equal?", greater_or_equal?
   pop_argument_stack rbx
   pop_argument_stack rax
   cmp   rax, rbx
   setge al
   movzx rax, al
   push_argument_stack rax
   next

negative? & positive?

define_function "negative?", negative?
   ;; << integer -- bool >>
   xx zero, less_than?
   xx end

define_function "positive?", positive?
   ;; << integer -- bool >>
   xx negative?, false?
   xx end

----------------------------------

memory

note

  • although the following functions are all side-effect but I use “save” instead of “save!”

save

match =64bit, machine {

;; "save" and "fetch" default to a jo_size
;; the rule of "fetch2" and so on are:
;;   in memory:
;;     ||  1 : value-1  ||
;;     ||  1 : value-2  ||
;;     ||  1 : value-3  ||
;;     ...
;;   on stack:
;;     << value-1, value-2, value-3, ... >>
;; of course we have:
;;   fetch2 : memory=copy=>stack
;;   save2  : stack->memory

define_primitive_function "save", save
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov [rbx], rax
   next

define_primitive_function "save-byte", save_byte
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov byte[rbx], al
   next

define_primitive_function "save-two-bytes", save_two_bytes
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov word [rbx], ax
   next

define_primitive_function "save-four-bytes", save_four_bytes
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov dword [rbx], eax
   next

define_primitive_function "n-save", n_save
   ;; << value-n, ..., value-1, address, n -- >>
   pop_argument_stack rcx
   pop_argument_stack rdx
   mov rax, jo_size
   imul rax, rcx
   add rdx, rax
   ;; for address is based on 0
   ;; but n is based on 1
   sub rdx, jo_size
.loop:
   pop_argument_stack rax
   mov qword [rdx], rax
   sub rdx, jo_size
   loop .loop
   next

define_function "save2", save2
   ;; << value-2, value-1, address -- >>
   xx literal, 2
   xx n_save
   xx end

define_primitive_function "n-save-byte", n_save_byte
   ;; << value-n, ..., value-1, address, n -- >>
   pop_argument_stack rcx
   pop_argument_stack rdx
   add rdx, rcx
   dec rdx
.loop:
   pop_argument_stack rax
   mov byte [rdx], al
   dec rdx
   loop .loop
   next

define_primitive_function "add-save", add_save
   ;; ( number to add, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   add qword [rbx], rax
   next

define_primitive_function "sub-save", sub_save
   ;; ( number to add, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   sub qword [rbx], rax
   next

}

fetch

match =64bit, machine {

define_primitive_function "fetch", fetch
   ;; ( address -- value )
   pop_argument_stack  rbx
   mov rax, [rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-byte", fetch_byte
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov al, byte[rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-two-bytes", fetch_two_bytes
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov ax, word [rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-four-bytes", fetch_four_bytes
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov eax, dword [rbx]
   push_argument_stack rax
   next

;;   in memory:
;;     ||  1 : value-1  ||
;;     ...
;;     ||  1 : value-n  ||
define_primitive_function "n-fetch", n_fetch
   ;; << address, n -- value-1, ..., value-n >>
   pop_argument_stack  rcx
   pop_argument_stack  rdx
.loop:
   mov rax, qword [rdx]
   push_argument_stack rax
   add rdx, jo_size
   loop .loop
   next

define_primitive_function "n-fetch-byte", n_fetch_byte
   ;; << address, n -- byte-1, ..., byte-n >>
   pop_argument_stack  rcx
   pop_argument_stack  rdx
   xor rax, rax
.loop:
   mov al, byte [rdx]
   push_argument_stack rax
   inc rdx
   loop .loop
   next

define_function "fetch2", fetch2
   ;; << address -- value-1, value-2 >>
   xx literal, 2
   xx n_fetch
   xx end

}

save

match =32bit, machine {

;; "save" and "fetch" default to a jo_size
;; the rule of "fetch2" and so on are:
;;   in memory:
;;     ||  1 : value-1  ||
;;     ||  1 : value-2  ||
;;     ||  1 : value-3  ||
;;     ...
;;   on stack:
;;     << value-1, value-2, value-3, ... >>
;; of course we have:
;;   fetch2 : memory=copy=>stack
;;   save2  : stack->memory

define_primitive_function "save", save
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov [rbx], rax
   next

define_primitive_function "save-byte", save_byte
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov byte[rbx], al
   next

define_primitive_function "save-two-bytes", save_two_bytes
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov word [rbx], ax
   next

define_primitive_function "save-four-bytes", save_four_bytes
   ;; ( value, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   mov dword [rbx], eax
   next

define_primitive_function "n-save", n_save
   ;; << value-n, ..., value-1, address, n -- >>
   pop_argument_stack rcx
   pop_argument_stack rdx
   mov rax, jo_size
   imul rax, rcx
   add rdx, rax
   ;; for address is based on 0
   ;; but n is based on 1
   sub rdx, jo_size
.loop:
   pop_argument_stack rax
   mov dword [rdx], rax
   sub rdx, jo_size
   loop .loop
   next

define_function "save2", save2
   ;; << value-2, value-1, address -- >>
   xx literal, 2
   xx n_save
   xx end

define_primitive_function "n-save-byte", n_save_byte
   ;; << value-n, ..., value-1, address, n -- >>
   pop_argument_stack rcx
   pop_argument_stack rdx
   add rdx, rcx
   dec rdx
.loop:
   pop_argument_stack rax
   mov byte [rdx], al
   dec rdx
   loop .loop
   next

define_primitive_function "add-save", add_save
   ;; ( number to add, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   add dword [rbx], rax
   next

define_primitive_function "sub-save", sub_save
   ;; ( number to add, address -- )
   pop_argument_stack rbx
   pop_argument_stack rax
   sub dword [rbx], rax
   next

}

fetch

match =32bit, machine {

define_primitive_function "fetch", fetch
   ;; ( address -- value )
   pop_argument_stack  rbx
   mov rax, [rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-byte", fetch_byte
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov al, byte[rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-two-bytes", fetch_two_bytes
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov ax, word [rbx]
   push_argument_stack rax
   next

define_primitive_function "fetch-four-bytes", fetch_four_bytes
   ;; ( address -- value )
   pop_argument_stack rbx
   xor rax, rax
   mov eax, dword [rbx]
   push_argument_stack rax
   next

;;   in memory:
;;     ||  1 : value-1  ||
;;     ...
;;     ||  1 : value-n  ||
define_primitive_function "n-fetch", n_fetch
   ;; << address, n -- value-1, ..., value-n >>
   pop_argument_stack  rcx
   pop_argument_stack  rdx
.loop:
   mov rax, dword [rdx]
   push_argument_stack rax
   add rdx, jo_size
   loop .loop
   next

define_primitive_function "n-fetch-byte", n_fetch_byte
   ;; << address, n -- byte-1, ..., byte-n >>
   pop_argument_stack  rcx
   pop_argument_stack  rdx
   xor rax, rax
.loop:
   mov al, byte [rdx]
   push_argument_stack rax
   inc rdx
   loop .loop
   next

define_function "fetch2", fetch2
   ;; << address -- value-1, value-2 >>
   xx literal, 2
   xx n_fetch
   xx end

}

clear

define_primitive_function "clear-memory", clear_memory
   ;; << size, address -- >>
   pop_argument_stack rdx
   pop_argument_stack rcx
   xor rax, rax
.loop:
   mov byte [rdx], al
   inc rdx
   dec rcx
   loop .loop
   next

-----------------------------------

basic io

----------------------------------

note byte

  • basic io is about byte

----------------------------------

write-byte

match =linux =64bit, platform machine {

buffer$write_byte:
   db 0

define_primitive_function "write-byte", write_byte
   ;; << byte -- >>
   pop_argument_stack rax
   ;; write can not just write the char in al to stdout
   ;; write needs the address of the byte to write
   mov [buffer$write_byte], al
   mov linux64_sys_3_rdx, 1                 ;; max length to be write
   mov linux64_sys_2_rsi, buffer$write_byte ;; address
   mov linux64_sys_1_rdi, 1                 ;; stdout
   mov linux64_sys_n_rax, linux64_syscall_write
   syscall
   next

}

write-byte

match =linux =32bit, platform machine {

buffer$write_byte:
   db 0

define_primitive_function "write-byte", write_byte
   ;; << byte -- >>
   ;; just calls the Linux write system call
   pop_argument_stack rax
   ;; write can not just write the char in al to stdout
   ;; write needs the address of the byte to write
   mov [buffer$write_byte], al
   mov linux32_sys_3_edx, 1                 ;; max length to be write
   mov linux32_sys_2_ecx, buffer$write_byte ;; address
   mov linux32_sys_1_ebx, 1                 ;; stdout
   mov linux32_sys_n_eax, linux32_syscall_write
   syscall
   next

}

write-byte

match =windows =64bit, platform machine {

buffer$write_byte:
   db 0

__counter$write_byte:
   xx 0

define_primitive_function "write-byte", write_byte
   ;; << byte -- >>
   ;; just calls the Linux write system call
   pop_argument_stack rax
   ;; write can not just write the char in al to stdout
   ;; write needs the address of the byte to write
   mov [buffer$write_byte], al

windows64_function 5
   push 0
   sub rsp, 8*4
   mov windows64_fun_4_r9, __counter$write_byte
   mov windows64_fun_3_r8, 1
   mov windows64_fun_2_rdx, buffer$write_byte
   mov windows64_fun_1_rcx, [_output_handle]
   call [WriteFile]
end_windows64_function

   next

}

write-byte

match =windows =32bit, platform machine {

buffer$write_byte:
   db 0

__counter$write_byte:
   xx 0

define_primitive_function "write-byte", write_byte
   ;; << byte -- >>
   ;; just calls the Linux write system call
   pop_argument_stack rax
   ;; write can not just write the char in al to stdout
   ;; write needs the address of the byte to write
   mov [buffer$write_byte], al

   push 0
   push __counter$write_byte
   push 1
   push buffer$write_byte
   mov rax, [_output_handle]
   push rax
   call [WriteFile]

   next

}

----------------------------------

note

  • do not exit the program when meeting <end-of-file> so when you hit <C-d> some you will not exit the interpreter
  • add the feature to unread one ket-char

note factoring

  • reading from file of stdin is slow thus
    1. when reading from file a whole file is readed at a time and saved to a buffer
    2. when reading from stdin a whole line is readed at a time
    3. note that reading line instead of keyboard-code will limit the design of the user interface
  • by factoring out the low-level calls that read a line from stdin we are able to implement eval-string easily

note nested call of eval-string

  • nested call of eval-string is handled by using a eval_string_stack to remember the old string
  • but in my view meta-programming should NOT be achieved by editing string
  • note that this point of view is not conflict with my macro system

memory allocation

max_input_length = 1024 * 1024

buffer$read_byte labeling
   preserve max_input_length

eval_string_stack

note

  • for we do not build border-check into the interface of pop and push we allocation some memory below the stacks
  • the size$eval_string_stack defines the max depth of nested call to eval string
  • cursor and border of a evaled string can be stored in eval_string_stack so when evaling a string the eval_string_stack will be << counter, cursor >> when evaling is nested depth is 2 << counter, cursor, counter, cursor >>

memory allocation

size$eval_string_stack = 1024 * jo_size

   preserve 64 * jo_size
address$eval_string_stack labeling
   preserve size$eval_string_stack

pointer

pointer$eval_string_stack:
   xx address$eval_string_stack

push & pop

match =64bit, machine {

 define_primitive_function "push-eval-string-stack", push_eval_string_stack
    ;; argument-stack -> eval-string-stack
    pop_argument_stack rax
    mov rbx, [pointer$eval_string_stack]
    mov [rbx], rax
    add qword [pointer$eval_string_stack], jo_size
    next

 define_primitive_function "pop-eval-string-stack", pop_eval_string_stack
    ;; eval-string-stack -> argument-stack
    sub qword [pointer$eval_string_stack], jo_size
    mov rbx, [pointer$eval_string_stack]
    mov rax, [rbx]
    push_argument_stack rax
    next

}

push & pop

match =32bit, machine {

 define_primitive_function "push-eval-string-stack", push_eval_string_stack
    ;; argument-stack -> eval-string-stack
    pop_argument_stack rax
    mov rsi, [pointer$eval_string_stack]
    mov [rsi], rax
    add dword [pointer$eval_string_stack], jo_size
    next

 define_primitive_function "pop-eval-string-stack", pop_eval_string_stack
    ;; eval-string-stack -> argument-stack
    sub dword [pointer$eval_string_stack], jo_size
    mov rsi, [pointer$eval_string_stack]
    mov rax, [rsi]
    push_argument_stack rax
    next

}

clear

match =64bit, machine {

define_primitive_function "clear-eval-string-stack", clear_eval_string_stack
   ;; << -- >>
   mov qword [pointer$eval_string_stack], address$eval_string_stack
   next

}

clear

match =32bit, machine {

define_primitive_function "clear-eval-string-stack", clear_eval_string_stack
   ;; << -- >>
   mov eax, address$eval_string_stack
   mov dword [pointer$eval_string_stack], eax;address$eval_string_stack
   next

}

empty?

define_primitive_function "eval-string-stack-empty?", eval_string_stack_empty?
   ;; << -- bool >>
   mov rax, [pointer$eval_string_stack]
   cmp rax, address$eval_string_stack
   ;; less-than is treated as equal
   setle al
   movzx rax, al
   push_argument_stack rax
   next

read-line-from-stdin

match =linux =64bit, platform machine {

define_primitive_function "read-line-from-stdin", read_line_from_stdin
   ;; << buffer address, max length -- counter >>
   pop_argument_stack linux64_sys_3_rdx
   pop_argument_stack linux64_sys_2_rsi
   xor linux64_sys_1_rdi, linux64_sys_1_rdi ;; stdin
   mov linux64_sys_n_rax, linux64_syscall_read
   syscall
   ;; the return value
   ;; is a count of the number of bytes transferred
   push_argument_stack rax
   next

}

read-line-from-stdin

match =linux =32bit, platform machine {

define_primitive_function "read-line-from-stdin", read_line_from_stdin
   ;; << buffer address, max length -- counter >>
   pop_argument_stack linux32_sys_3_edx
   pop_argument_stack linux32_sys_2_ecx
   xor linux32_sys_1_ebx, linux32_sys_1_ebx ;; stdin
   mov linux32_sys_n_eax, linux32_syscall_read
   syscall
   ;; the return value
   ;; is a count of the number of bytes transferred
   push_argument_stack rax
   next

}

read-line-from-stdin

match =windows =64bit, platform machine {

__counter$read_line_from_stdin:
   xx 0

define_primitive_function "read-line-from-stdin", read_line_from_stdin
   ;; << buffer address, max length -- counter >>
windows64_function 5
   push 0
   sub rsp, 8*4
   mov windows64_fun_4_r9, __counter$read_line_from_stdin
   pop_argument_stack windows64_fun_3_r8
   pop_argument_stack windows64_fun_2_rdx
   mov windows64_fun_1_rcx, [_input_handle]
   call [ReadFile]
   ;; the return value
   ;; is a count of the number of bytes transferred
   mov rax, [__counter$read_line_from_stdin]
   push_argument_stack rax
end_windows64_function
   next

}

read-line-from-stdin

match =windows =32bit, platform machine {

__counter$read_line_from_stdin:
   xx 0

define_primitive_function "read-line-from-stdin", read_line_from_stdin
   ;; << buffer address, max length -- counter >>
   push 0
   push __counter$read_line_from_stdin
   pop_argument_stack rax
   push rax
   pop_argument_stack rax
   push rax
   mov rax, [_input_handle]
   push rax
   call [ReadFile]
   ;; the return value
   ;; is a count of the number of bytes transferred
   mov rax, [__counter$read_line_from_stdin]
   push_argument_stack rax

   next

}

test read-line-from-stdin

define_function "", test__read_line_from_stdin
   xx literal, buffer$read_byte
   xx literal, max_input_length
   xx read_line_from_stdin
   xx pretty_write_integer
   xx literal, buffer$read_byte
   xx literal, 10
   xx write_string
   xx exit_with_TOS
   xx end

read-byte

define_function "read-byte", read_byte
   ;; << -- byte >>
   xx have_unreaded_ket_char?, false?branch, 9
   xx   literal, char$unreaded_ket_char, fetch_byte
   xx   zero, literal, flag$unreaded_ket_char
   xx   save
   xx   end
   xx read_byte__without_unread
   xx end

define_function "read-byte,without-unread", read_byte__without_unread
   ;; << -- byte >>
   xx eval_string_stack_empty?, false?branch, (.not_empty-$)/jo_size
   xx   literal, buffer$read_byte
   xx   literal, max_input_length
   xx   read_line_from_stdin
   xx     dup, positive?, false?, false?branch, 4
   ;;     ignore <end-of-file>
   ;;     ignore reading error
   xx     drop
   xx     taca, read_byte__without_unread
   xx   push_eval_string_stack
   xx   literal, buffer$read_byte
   xx   push_eval_string_stack
   xx   taca, read_byte__without_unread
   .not_empty:
   xx pop_eval_string_stack
   xx pop_eval_string_stack
   xx dup, zero?, false?branch, 4
   xx   drop2
   xx   taca, read_byte__without_unread
   xx sub1, push_eval_string_stack
   xx dup
   xx add1, push_eval_string_stack
   xx fetch_byte
   xx end

unread-ket-char

flag$unreaded_ket_char:
   xx 0

char$unreaded_ket_char:
   xx 0

define_function "have-unreaded-ket-char?", have_unreaded_ket_char?
   ;; << -- bool >>
   xx literal, flag$unreaded_ket_char
   xx fetch
   xx end

define_function "unread-ket-char", unread_ket_char
   ;; << char -- >>
   xx literal, char$unreaded_ket_char, save
   xx true, literal, flag$unreaded_ket_char
   xx save
   xx end

----------------------------------

eval-string

define_function "eval-string", eval_string
   ;; << string[address, length] -- UNKNOWN >>
   xx push_eval_string_stack
   xx push_eval_string_stack
   xx end

-----------------------------------

file io

----------------------------------

open-file,to-read

match =linux =64bit, platform machine {

name_buffer$open_file__to_read labeling
   preserve 512

define_primitive_function "open-file,to-read", open_file__to_read
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_read
   rep movsb
   xor rax, rax
   mov byte [rdi], al
   mov linux64_sys_2_rsi, open_read ;; read only
   mov linux64_sys_1_rdi, name_buffer$open_file__to_read
   mov linux64_sys_n_rax, linux64_syscall_open
   syscall
   push_argument_stack rax
   next

}

open-file,to-write

match =linux =64bit, platform machine {

name_buffer$open_file__to_write labeling
   preserve 512

define_primitive_function "open-file,to-write", open_file__to_write
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_write
   rep movsb
   xor rax, rax
   mov byte [rdi], al
   mov linux64_sys_3_rdx, 110100100b
   mov linux64_sys_2_rsi, open_readAndWrite or open_creat or open_rewrite
   mov linux64_sys_1_rdi, name_buffer$open_file__to_write
   mov linux64_sys_n_rax, linux64_syscall_open
   syscall
   push_argument_stack rax
   next

}

close-file

match =linux =64bit, platform machine {

define_primitive_function "close-file", close_file
   ;; << file-handle -- >>
   pop_argument_stack linux64_sys_1_rdi
   mov linux64_sys_n_rax, linux64_syscall_close
   syscall
   next

}

read-file

  • from disk to memory
match =linux =64bit, platform machine {

define_primitive_function "read-file", read_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
   pop_argument_stack linux64_sys_3_rdx
   pop_argument_stack linux64_sys_2_rsi
   pop_argument_stack linux64_sys_1_rdi
   mov linux64_sys_n_rax, linux64_syscall_read
   syscall
   push_argument_stack rax
   next

}

write-file

  • from memory to disk
match =linux =64bit, platform machine {

define_primitive_function "write-file", write_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
   pop_argument_stack linux64_sys_3_rdx
   pop_argument_stack linux64_sys_2_rsi
   pop_argument_stack linux64_sys_1_rdi
   mov linux64_sys_n_rax, linux64_syscall_write
   syscall
   push_argument_stack rax
   next

}

----------------------------------

open-file,to-read

match =linux =32bit, platform machine {

name_buffer$open_file__to_read labeling
   preserve 512

define_primitive_function "open-file,to-read", open_file__to_read
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_read
   rep movsb
   xor rax, rax
   mov byte [rdi], al
   mov linux32_sys_2_ecx, open_read ;; read only
   mov linux32_sys_1_ebx, name_buffer$open_file__to_read
   mov linux32_sys_n_eax, linux32_syscall_open
   syscall
   push_argument_stack rax
   next

}

open-file,to-write

match =linux =32bit, platform machine {

name_buffer$open_file__to_write labeling
   preserve 512

define_primitive_function "open-file,to-write", open_file__to_write
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_write
   rep movsb
   xor rax, rax
   mov byte [rdi], al
   mov linux32_sys_3_edx, 110100100b
   mov linux32_sys_2_ecx, open_readAndWrite or open_creat or open_rewrite
   mov linux32_sys_1_ebx, name_buffer$open_file__to_write
   mov linux32_sys_n_eax, linux32_syscall_open
   syscall
   push_argument_stack rax
   next

}

close-file

match =linux =32bit, platform machine {

define_primitive_function "close-file", close_file
   ;; << file-handle -- >>
   pop_argument_stack linux32_sys_1_ebx
   mov linux32_sys_n_eax, linux32_syscall_close
   syscall
   next

}

read-file

  • from disk to memory
match =linux =32bit, platform machine {

define_primitive_function "read-file", read_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
   pop_argument_stack linux32_sys_3_edx
   pop_argument_stack linux32_sys_2_ecx
   pop_argument_stack linux32_sys_1_ebx
   mov linux32_sys_n_eax, linux32_syscall_read
   syscall
   push_argument_stack rax
   next

}

write-file

  • from memory to disk
match =linux =32bit, platform machine {

define_primitive_function "write-file", write_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
   pop_argument_stack linux32_sys_3_edx
   pop_argument_stack linux32_sys_2_ecx
   pop_argument_stack linux32_sys_1_ebx
   mov linux32_sys_n_eax, linux32_syscall_write
   syscall
   push_argument_stack rax
   next

}

----------------------------------

header

match =windows =64bit, platform machine {

; Access rights

DELETE_RIGHT              = 00010000h
READ_CONTROL              = 00020000h
WRITE_DAC                 = 00040000h
WRITE_OWNER               = 00080000h
SYNCHRONIZE               = 00100000h
STANDARD_RIGHTS_READ      = READ_CONTROL
STANDARD_RIGHTS_WRITE     = READ_CONTROL
STANDARD_RIGHTS_EXECUTE   = READ_CONTROL
STANDARD_RIGHTS_REQUIRED  = 000F0000h
STANDARD_RIGHTS_ALL       = 001F0000h
SPECIFIC_RIGHTS_ALL       = 0000FFFFh
ACCESS_SYSTEM_SECURITY    = 01000000h
MAXIMUM_ALLOWED           = 02000000h
GENERIC_READ              = 80000000h
GENERIC_WRITE             = 40000000h
GENERIC_EXECUTE           = 20000000h
GENERIC_ALL               = 10000000h
PROCESS_TERMINATE         = 00000001h
PROCESS_CREATE_THREAD     = 00000002h
PROCESS_VM_OPERATION      = 00000008h
PROCESS_VM_READ           = 00000010h
PROCESS_VM_WRITE          = 00000020h
PROCESS_DUP_HANDLE        = 00000040h
PROCESS_CREATE_PROCESS    = 00000080h
PROCESS_SET_QUOTA         = 00000100h
PROCESS_SET_INFORMATION   = 00000200h
PROCESS_QUERY_INFORMATION = 00000400h
PROCESS_ALL_ACCESS        = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or 0FFFh
FILE_SHARE_READ           = 00000001h
FILE_SHARE_WRITE          = 00000002h
FILE_SHARE_DELETE         = 00000004h

; CreateFile actions

CREATE_NEW        = 1
CREATE_ALWAYS     = 2
OPEN_EXISTING     = 3
OPEN_ALWAYS       = 4
TRUNCATE_EXISTING = 5

; File attributes

FILE_ATTRIBUTE_READONLY   = 001h
FILE_ATTRIBUTE_HIDDEN     = 002h
FILE_ATTRIBUTE_SYSTEM     = 004h
FILE_ATTRIBUTE_DIRECTORY  = 010h
FILE_ATTRIBUTE_ARCHIVE    = 020h
FILE_ATTRIBUTE_NORMAL     = 080h
FILE_ATTRIBUTE_TEMPORARY  = 100h
FILE_ATTRIBUTE_COMPRESSED = 800h

}

open-file,to-read

match =windows =64bit, platform machine {

name_buffer$open_file__to_read labeling
   preserve 512

define_primitive_function "open-file,to-read", open_file__to_read
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_read
   rep movsb
   xor rax, rax
   mov byte [rdi], al
windows64_function 7
   push 0 ;; null
   push FILE_ATTRIBUTE_NORMAL
   push OPEN_EXISTING
   sub rsp, 8*4
   mov windows64_fun_4_r9, 0 ;; null
   mov windows64_fun_3_r8, 0 ;; no sharing
   mov windows64_fun_2_rdx, GENERIC_READ
   mov windows64_fun_1_rcx, name_buffer$open_file__to_read
   call [CreateFileA]
   push_argument_stack rax
end_windows64_function
   next

}

open-file,to-write

match =windows =64bit, platform machine {

name_buffer$open_file__to_write labeling
   preserve 512

define_primitive_function "open-file,to-write", open_file__to_write
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_write
   rep movsb
   xor rax, rax
   mov byte [rdi], al
windows64_function 7
   push 0 ;; null
   push FILE_ATTRIBUTE_NORMAL
   push CREATE_ALWAYS
   sub rsp, 8*4
   mov windows64_fun_4_r9, 0 ;; null
   mov windows64_fun_3_r8, 0 ;; no sharing
   mov windows64_fun_2_rdx, GENERIC_WRITE
   mov windows64_fun_1_rcx, name_buffer$open_file__to_write
   call [CreateFileA]
   push_argument_stack rax
end_windows64_function
   next

}

close-file

match =windows =64bit, platform machine {

define_primitive_function "close-file", close_file
   ;; << file-handle -- >>
windows64_function 4
   sub rsp, 8*4
   pop_argument_stack windows64_fun_1_rcx
   call [CloseHandle]
end_windows64_function
   next

}

read-file

match =windows =64bit, platform machine {

__counter$read_file:
   xx 0

define_primitive_function "read-file", read_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
windows64_function 5
   push 0
   sub rsp, 8*4
   mov windows64_fun_4_r9, __counter$read_file
   pop_argument_stack windows64_fun_3_r8
   pop_argument_stack windows64_fun_2_rdx
   pop_argument_stack windows64_fun_1_rcx
   call [ReadFile]
end_windows64_function

   mov rax, [__counter$read_file]
   push_argument_stack rax

   next

}

write-file

match =windows =64bit, platform machine {

__counter$write_file:
   xx 0

define_primitive_function "write-file", write_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>
windows64_function 5
   push 0
   sub rsp, 8*4
   mov windows64_fun_4_r9, __counter$write_file
   pop_argument_stack windows64_fun_3_r8
   pop_argument_stack windows64_fun_2_rdx
   pop_argument_stack windows64_fun_1_rcx
   call [WriteFile]
   mov rax, [__counter$write_file]
   push_argument_stack rax
end_windows64_function

   next

}

----------------------------------

header

match =windows =32bit, platform machine {

; Access rights

DELETE_RIGHT              = 00010000h
READ_CONTROL              = 00020000h
WRITE_DAC                 = 00040000h
WRITE_OWNER               = 00080000h
SYNCHRONIZE               = 00100000h
STANDARD_RIGHTS_READ      = READ_CONTROL
STANDARD_RIGHTS_WRITE     = READ_CONTROL
STANDARD_RIGHTS_EXECUTE   = READ_CONTROL
STANDARD_RIGHTS_REQUIRED  = 000F0000h
STANDARD_RIGHTS_ALL       = 001F0000h
SPECIFIC_RIGHTS_ALL       = 0000FFFFh
ACCESS_SYSTEM_SECURITY    = 01000000h
MAXIMUM_ALLOWED           = 02000000h
GENERIC_READ              = 80000000h
GENERIC_WRITE             = 40000000h
GENERIC_EXECUTE           = 20000000h
GENERIC_ALL               = 10000000h
PROCESS_TERMINATE         = 00000001h
PROCESS_CREATE_THREAD     = 00000002h
PROCESS_VM_OPERATION      = 00000008h
PROCESS_VM_READ           = 00000010h
PROCESS_VM_WRITE          = 00000020h
PROCESS_DUP_HANDLE        = 00000040h
PROCESS_CREATE_PROCESS    = 00000080h
PROCESS_SET_QUOTA         = 00000100h
PROCESS_SET_INFORMATION   = 00000200h
PROCESS_QUERY_INFORMATION = 00000400h
PROCESS_ALL_ACCESS        = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or 0FFFh
FILE_SHARE_READ           = 00000001h
FILE_SHARE_WRITE          = 00000002h
FILE_SHARE_DELETE         = 00000004h

; CreateFile actions

CREATE_NEW        = 1
CREATE_ALWAYS     = 2
OPEN_EXISTING     = 3
OPEN_ALWAYS       = 4
TRUNCATE_EXISTING = 5

; File attributes

FILE_ATTRIBUTE_READONLY   = 001h
FILE_ATTRIBUTE_HIDDEN     = 002h
FILE_ATTRIBUTE_SYSTEM     = 004h
FILE_ATTRIBUTE_DIRECTORY  = 010h
FILE_ATTRIBUTE_ARCHIVE    = 020h
FILE_ATTRIBUTE_NORMAL     = 080h
FILE_ATTRIBUTE_TEMPORARY  = 100h
FILE_ATTRIBUTE_COMPRESSED = 800h

}

open-file,to-read

match =windows =32bit, platform machine {

name_buffer$open_file__to_read labeling
   preserve 512

define_primitive_function "open-file,to-read", open_file__to_read
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_read
   rep movsb
   xor rax, rax
   mov byte [rdi], al

   push 0 ;; null
   push FILE_ATTRIBUTE_NORMAL
   push OPEN_EXISTING
   push 0 ;; null
   push 0 ;; no sharing
   push GENERIC_READ
   push name_buffer$open_file__to_read
   call [CreateFileA]
   push_argument_stack rax

   next

}

open-file,to-write

match =windows =32bit, platform machine {

name_buffer$open_file__to_write labeling
   preserve 512

define_primitive_function "open-file,to-write", open_file__to_write
   ;; << file-name-string[address, length] --
   ;;    [file handle] or [error code] >>
   pop_argument_stack rcx
   pop_argument_stack rsi
   ;; copy file-name as a null-terminal string
   mov rdi, name_buffer$open_file__to_write
   rep movsb
   xor rax, rax
   mov byte [rdi], al

   push 0 ;; null
   push FILE_ATTRIBUTE_NORMAL
   push CREATE_ALWAYS
   push 0 ;; null
   push 0 ;; no sharing
   push GENERIC_WRITE
   push name_buffer$open_file__to_write
   call [CreateFileA]
   push_argument_stack rax

   next

}

close-file

match =windows =32bit, platform machine {

define_primitive_function "close-file", close_file
   ;; << file-handle -- >>

   pop_argument_stack rax
   push rax
   call [CloseHandle]

   next

}

read-file

match =windows =32bit, platform machine {

__counter$read_file:
   xx 0

define_primitive_function "read-file", read_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>

   push 0
   push __counter$read_file
   pop_argument_stack rax
   push rax
   pop_argument_stack rax
   push rax
   pop_argument_stack rax
   push rax
   call [ReadFile]

   mov rax, [__counter$read_file]
   push_argument_stack rax

   next

}

write-file

match =windows =32bit, platform machine {

__counter$write_file:
   xx 0

define_primitive_function "write-file", write_file
   ;; << [file handle], buffer[address, length] --
   ;;    [number of char] or [error code] >>

   push 0
   push __counter$write_file
   pop_argument_stack rax
   push rax
   pop_argument_stack rax
   push rax
   pop_argument_stack rax
   push rax
   call [WriteFile]
   mov rax, [__counter$write_file]
   push_argument_stack rax

   next

}

----------------------------------

more about file

path-exist?

define_function "path-exist?", path_exist?
   ;; << path[address, length] -- bool >>
   xx open_file__to_read
   xx dup, negative?, false?, false?branch, 4
   xx   close_file
   xx   true
   xx   end
   xx literal, -2, equal?, false?branch, 3
   xx   false
   xx   end
   ;; ><><><
   xx true
   xx end

path-directory?

address$path_directory?:
   db 0

define_function "path-directory?", path_directory?
   ;; << path[address, length] -- bool >>
   xx open_file__to_read
   xx dup, negative?, false?branch, 4
   xx   drop
   xx   false
   xx   end
   xx dup
   xx literal, address$path_directory?
   xx literal, 1
   xx read_file
   xx swap, close_file
   xx dup, positive?, false?branch, 4
   xx   drop
   xx   false
   xx   end
   xx literal, -21, equal?, false?branch, 3
   xx   true
   xx   end
   ;; ><><><
   xx false
   xx end

path-file?

address$path_file?:
   db 0

define_function "path-file?", path_file?
   ;; << path[address, length] -- bool >>
   xx open_file__to_read
   xx dup, negative?, false?branch, 4
   xx   drop
   xx   false
   xx   end
   xx dup
   xx literal, address$path_file?
   xx literal, 1
   xx read_file
   xx swap, close_file
   xx positive?, false?branch, 3
   xx   true
   xx   end
   xx false
   xx end

load-file

  • load-file can not be nested for now a stack of buffer would solve this problem
buffer$load_file labeling
  preserve 1024 * 1024

define_function "report,load-file", report__load_file
   ;; << -- >>
   xx literal, string$report__load_file
   xx literal, length$report__load_file
   xx write_string
   xx end

string$report__load_file:
   db "* LOADING : "
.end:
length$report__load_file = (.end - string$report__load_file)

define_function "load-file", load_file
   ;; << name-string[address, length] -- UNKNOWN >>
   xx report__load_file
   xx dup2, write_string
   xx literal, 10, write_byte

   xx open_file__to_read
   xx dup
   xx   literal, buffer$load_file ;; buffer
   xx   literal, 1024 * 1024      ;; length
   xx   read_file
   xx swap, close_file
   xx dup, positive?, false?branch, (.error-$)/jo_size
   xx   literal, buffer$load_file
   xx   swap
   xx   push_eval_string_stack
   xx   push_eval_string_stack
   xx   end
   .error:
   xx error_report__load_file
   xx write_integer
   xx literal, 10, write_byte
   xx end

define_function "error-report,load-file", error_report__load_file
   ;; << -- >>
   xx literal, string$error_report__load_file
   xx literal, length$error_report__load_file
   xx write_string
   xx end

string$error_report__load_file:
   db "* (load-file) MEETS ERROR  (read-file) ERROR CODE : "
.end:
length$error_report__load_file = (.end - string$error_report__load_file)

to load file

----------------------------------

note linux system environment

  • pid is the key to all the linux system environment
  • command-line /proc/<pid>/cmdline
  • environment-string-variable-list /proc/<pid>/environ

----------------------------------

init-operating-system-environment

match =linux, platform {

define_function "init-operating-system-environment", init_operating_system_environment
   ;; << -- >>
   xx init_pid
   xx init_command_line
   xx init_environment_string_variable_list
   xx end

}

----------------------------------

init-pid

match =linux =64bit, platform machine {

define_primitive_function "init-pid", init_pid
   ;; << -- pid >>
   mov linux64_sys_n_rax, linux64_syscall_getpid
   syscall
   mov [value$get_pid], rax
   next

}

init-pid

match =linux =32bit, platform machine {

define_primitive_function "init-pid", init_pid
   ;; << -- pid >>
   mov linux32_sys_n_eax, linux32_syscall_getpid
   syscall
   mov [value$get_pid], rax
   next

}

init-command-line

match =linux, platform {

file$init_command_line:
   db "/cmdline" ;; length of 8

path$init_command_line:
   db "/proc/"   ;; length of 6
pid$init_command_line:
   db "********************************"

address$init_command_line:
   times 512 db 0
length$init_command_line:
   xx 0

define_function "init-command-line", init_command_line
   ;; << -- >>
   xx get_pid
   xx write_nature_number__fill_buffer
   xx tuck
   xx literal, pid$init_command_line
   xx string_to_buffer!
   xx literal, file$init_command_line
   xx literal, 8
   xx literal, pid$init_command_line
   xx xoverxxx, addition
   xx string_to_buffer!
   xx literal, path$init_command_line
   xx swap
   xx literal, 8, addition
   xx literal, 6, addition
   xx open_file__to_read
   xx literal, address$init_command_line
   xx literal, 512
   xx read_file
   xx literal, length$init_command_line
   xx save
   xx end

}

init-environment-string-variable-list

  • the size of /proc/<pid>/environ is limited to 4k
match =linux, platform {

file$init_environment_string_variable_list:
   db "/environ" ;; length of 8

path$init_environment_string_variable_list:
   db "/proc/"   ;; length of 6
pid$init_environment_string_variable_list:
   db "********************************"

address$init_environment_string_variable_list:
   times (4 * 1024) db 0
length$init_environment_string_variable_list:
   xx 0

define_function "init-environment-string-variable-list", init_environment_string_variable_list
   ;; << -- >>
   xx get_pid
   xx write_nature_number__fill_buffer
   xx tuck
   xx literal, pid$init_environment_string_variable_list
   xx string_to_buffer!
   xx literal, file$init_environment_string_variable_list
   xx literal, 8
   xx literal, pid$init_environment_string_variable_list
   xx xoverxxx, addition
   xx string_to_buffer!
   xx literal, path$init_environment_string_variable_list
   xx swap
   xx literal, 8, addition
   xx literal, 6, addition
   xx open_file__to_read
   xx literal, address$init_environment_string_variable_list
   xx literal, (4 * 1024)
   xx read_file
   xx literal, length$init_environment_string_variable_list
   xx save
   xx end

}

----------------------------------

get-pid

match =linux, platform {

value$get_pid:
   xx 2

define_function "get-pid", get_pid
   ;; << -- pid >>
   xx literal, value$get_pid, fetch
   xx end

}

get-command-line

match =linux, platform {

define_function "get-command-line", get_command_line
   ;; << -- string[address, length] >>
   xx literal, address$init_command_line
   xx literal, length$init_command_line, fetch
   xx end

}

get-environment-string-variable-list

match =linux, platform {

define_function "get-environment-string-variable-list", get_environment_string_variable_list
   ;; << -- string[address, length] >>
   xx literal, address$init_environment_string_variable_list
   xx literal, length$init_environment_string_variable_list, fetch
   xx end

}

----------------------------------

find-environment-string-variable

  • the string used to find an environment-string-variable can not contain “=” no error handling on this
match =linux, platform {

define_function "find-environment-string-variable", find_environment_string_variable
   ;; << string[address, length]
   ;;    -- string[address, length], true
   ;;    -- false >>
   xx literal, address$init_environment_string_variable_list ;; cursor
   xx find_environment_string_variable__loop
   xx end

define_function "find-environment-string-variable,loop", find_environment_string_variable__loop
   ;; << string[address, length], cursor
   ;;    -- string[address, length], true
   ;;    -- false >>
   xx dup
   xx literal, address$init_environment_string_variable_list
   xx literal, length$init_environment_string_variable_list, fetch
   xx addition
   xx greater_than?, false?branch, 5
   xx   drop, drop2
   xx   false
   xx   end
   xx xxoverx, xoverxx, swap
   xx compare_buffer, false?, false?branch, 7
   xx   literal, 0
   xx   cursor_to_next_matching_byte
   xx   add1
   xx   taca, find_environment_string_variable__loop
   xx dup, xoverxx, addition, fetch_byte
   xx literal, '=', equal?, false?, false?branch, 7
   xx   literal, 0
   xx   cursor_to_next_matching_byte
   xx   add1
   xx   taca, find_environment_string_variable__loop
   xx xswapxx, drop
   xx addition, add1
   xx dup
   xx literal, 0
   xx cursor_to_next_matching_byte
   xx over, subtraction
   xx true
   xx end

}

----------------------------------

>< get-home-path

  • need error handling
match =linux, platform {

string$get_home_path:
   db "HOME"

define_function "get-home-path", get_home_path
   ;; << -- string[address, length] >>
   xx literal, string$get_home_path
   xx literal, 4
   xx find_environment_string_variable
   xx drop
   xx end

}

----------------------------------

load-core-file

match =linux, platform {

path$load_core_file:
   times 512 db 0


string$load_core_file:
   db "/.cicada/core.cn"
.end:
length$load_core_file = (.end - string$load_core_file)

string$load_core_file__system_wide:
   db "/etc/cicada/core.cn"
.end:
length$load_core_file__system_wide = (.end - string$load_core_file__system_wide)


define_function "load-core-file", load_core_file
   ;; << UNKNOWN -- UNKNOWN >>
   xx get_home_path
   xx tuck
   xx literal, path$load_core_file
   xx string_to_buffer!

   xx literal, string$load_core_file
   xx literal, length$load_core_file
   xx xoverxx
   xx literal, path$load_core_file
   xx addition
   xx string_to_buffer!

   xx literal, length$load_core_file
   xx addition
   xx literal, path$load_core_file
   xx swap

   xx dup2, path_file?, false?branch, 3
   xx   load_file
   xx   end
   xx literal, string$load_core_file__report
   xx literal, length$load_core_file__report
   xx write_string
   xx write_string
   xx literal, 10, write_byte

   xx literal, string$load_core_file__system_wide
   xx literal, length$load_core_file__system_wide
   xx dup2, path_file?, false?branch, 3
   xx   load_file
   xx   end
   xx drop2
   xx literal, string$load_core_file__report2
   xx literal, length$load_core_file__report2
   xx write_string
   xx literal, 10, write_byte
   xx end

string$load_core_file__report:
   db "* (load-core-file)", 10
   db "  * FALLING BACK TO SYSTEM-WIDE CORE FILE : /etc/cicada/core.cn", 10
   db "  * BECAUSE CAN NOT LOAD USER'S CORE FILE : "
.end:
length$load_core_file__report = (.end - string$load_core_file__report)

string$load_core_file__report2:
   db "* (load-core-file) ", 10
   db "  * CAN NOT LOAD SYSTEM-WIDE CORE FILE : /etc/cicada/core.cn", 10
   db "  * NO CORE FILE IS LOADED"
.end:
length$load_core_file__report2 = (.end - string$load_core_file__report2)

}

----------------------------------

load-core-file

match =windows, platform {

string$name_of_init_file:
   db "core.cn"
.end:
length$name_of_init_file = (.end - string$name_of_init_file)


define_function "load-core-file", load_core_file
   ;; << -- >>
   xx literal, string$name_of_init_file
   xx literal, length$name_of_init_file
   xx load_file
   xx end

}

----------------------------------

-----------------------------------

char

space-char?

  • as for space-char I only use two ASCII 10 (newline) ASCII 32 (whitespace)
  • note that I use the term “whitespace” to denotes the char I use the term “space” to denotes the set of chars
  • I will simply view number less-or-equal 32 as space-char
define_function "space-char?", space_char?
   ;; << char -- bool >>
   xx literal, 32
   xx less_or_equal?
   xx end

bar-ket-char?

  • () [] {} but not <>
  • double-quote is viewed as special bar-ket-char
define_function "bar-ket-char?", bar_ket_char?
   ;; << char -- bool >>
   xx dup, literal, '(', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, ')', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, '[', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, ']', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, '{', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, '}', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, '"', equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx drop, false
   xx end

decimal-digital-char?

define_function "digital-char?", decimal_digital_char?
   ;; << char -- bool >>
   xx dup, literal, '0', less_than?, false?branch, 4
   xx   drop, false
   xx   end
   xx dup, literal, '9', less_or_equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx drop, false
   xx end

latin-char?

define_function "latin-char?", latin_char?
   ;; << char -- bool >>
   xx dup, literal, 'A', less_than?, false?branch, 4
   xx   drop, false
   xx   end
   xx dup, literal, 'Z', less_or_equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx dup, literal, 'a', less_than?, false?branch, 4
   xx   drop, false
   xx   end
   xx dup, literal, 'z', less_or_equal?, false?branch, 4
   xx   drop, true
   xx   end
   xx drop, false
   xx end

note digital

  • a decimal-digital is number from 0 to 9
  • a binary-digital is number from 0 to 1

char->decimal-digital & decimal-digital->char

define_function "char->decimal-digital", char_to_decimal_digital
   ;; << char -- decimal-digital >>
   xx literal, '0'
   xx subtraction
   xx end

define_function "decimal-digital->char", decimal_digital_to_char
   ;; << decimal-digital -- char >>
   xx literal, '0'
   xx addition
   xx end

buffer

note

  • a buffer is a large vector and some functions do not care about how large it is

compare-buffer

;; return false when length == 0
define_primitive_function "compare-buffer", compare_buffer
   ;; << address, address, length -- bool >>
   pop_argument_stack rcx
   pop_argument_stack rdi
   pop_argument_stack rsi
   repe cmpsb
   sete al
   movzx rax, al
   push_argument_stack rax
   next

cursor->next-matching-byte

  • note that it is the NEXT matching-byte
define_function "cursor->next-matching-byte", cursor_to_next_matching_byte
   ;; << cursor, byte -- cursor new address >>
   xx over, add1, fetch_byte
   xx over, equal?, false?branch, 4
   xx   drop, add1
   xx   end
   xx swap
   xx add1, swap
   xx taca, cursor_to_next_matching_byte

string

----------------------------------

note io about string

write-string

define_function "write-string", write_string
   ;; << string[address, length] -- >>
   xx dup, zero?, false?branch, 3
   xx   drop2
   xx   end
   xx sub1, swap
   xx dup, fetch_byte, write_byte
   xx add1, swap
   xx taca, write_string

pretty_write_string

define_function ".s", pretty_write_string
   ;; << integer -- >>
   xx write_string
   xx literal, 10
   xx write_byte
   xx end

----------------------------------

string-equal?

define_function "string-equal?", string_equal?
   ;; << string[address, length], string[address, length] -- bool >>
   xx xoverxx, equal?, false?branch, 4
   xx   swap
   xx   compare_buffer
   xx   end
   xx drop, drop2
   xx false
   xx end

string-[head|tail],char

define_function "string-head,char", string_head__char
   ;; << string[address, length] -- char >>
   xx drop, fetch_byte
   xx end

define_function "string-tail,char", string_tail__char
   ;; << string[address, length] -- [address + 1, length + 1] >>
   xx sub1, swap
   xx add1
   xx swap
   xx end

string->buffer!

define_primitive_function "string->buffer!", string_to_buffer!
   ;; ( string[address, length], buffer[address] -- )
   pop_argument_stack rdi ;; destination
   pop_argument_stack rcx ;; counter
   pop_argument_stack rsi ;; source
   rep movsb
   next

string-reverse!

match =64bit, machine {

buffer$string_reverse! labeling
   preserve 1024


define_primitive_function "string-reverse!", string_reverse!
   ;; << string[address, length] -- string[address, length] >>
   mov rdi, buffer$string_reverse!
   mov rcx, [pointer$argument_stack - (1 * jo_size)]
   mov rsi, [pointer$argument_stack - (2 * jo_size)]
   rep movsb

   mov rcx, [pointer$argument_stack - (1 * jo_size)]
   dec rdi ;; cursor back into string in buffer$string_reverse!
   mov rsi, [pointer$argument_stack - (2 * jo_size)]
.loop:
   mov al, byte [rdi]
   mov byte [rsi], al
   dec rdi
   inc rsi
   loop .loop

   next

}

string-reverse!

match =32bit, machine {

buffer$string_reverse! labeling
   preserve 1024


define_primitive_function "string-reverse!", string_reverse!
   ;; << string[address, length] -- string[address, length] >>
   mov rbx, [pointer$argument_stack]
   mov rdi, buffer$string_reverse!
   mov rcx, [rbx - (1 * jo_size)]
   mov rsi, [rbx - (2 * jo_size)]
   rep movsb

   mov rcx, [rbx - (1 * jo_size)]
   dec rdi ;; cursor back into string in buffer$string_reverse!
   mov rsi, [rbx - (2 * jo_size)]
.loop:
   mov al, byte [rdi]
   mov byte [rsi], al
   dec rdi
   inc rsi
   loop .loop

   next

}

digital-string?

define_function "digital-string?", digital_string?
   ;; << string[address, length] -- bool >>
   xx dup, zero?, false?branch, 4
   xx   drop2, true
   xx   end
   xx over, fetch_byte, decimal_digital_char?, false?branch, 4
   xx   string_tail__char
   xx   taca, digital_string?
   xx drop2, false
   xx end

char-string?

define_function "char-string?", char_string?
   ;; << string[address, length], char -- bool >>
   xx xxswapx
   xx dup, one?, false?, false?branch, 5
   xx   drop2, drop
   xx   false
   xx   end
   xx string_head__char, equal?, false?branch, 3
   xx   true
   xx   end
   xx false
   xx end

zero-string?

  • “0” or “-0” 0 is special when compiling literal number for we are using 0 as “end”
define_function "zero-string?", zero_string?
   ;; << string[address, length] -- bool >>
   xx dup2, literal, '0', char_string?, false?branch, 4
   xx   drop2, true
   xx   end
   xx dup2
   xx string_head__char, literal, '-', equal?, false?, false?branch, 4
   xx   drop2, false
   xx   end
   xx string_tail__char, literal, '0', char_string?
   xx end

integer-string?

define_function "integer-string?", integer_string?
   ;; << string[address, length] -- bool >>
   xx dup, zero?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, literal, '-', char_string?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, string_head__char, literal, '-', equal?, false?branch, 4
   xx   string_tail__char
   xx   digital_string?
   xx   end
   xx digital_string?
   xx end

string->integer

define_function "string->integer", string_to_integer
   ;; << string[address, length] -- integer >>
   xx dup2, string_head__char, literal, '-', equal?, false?, false?branch, 3
   xx   digital_string_to_integer
   xx   end
   xx string_tail__char
   xx digital_string_to_integer
   xx negate
   xx end


sum$digital_string_to_integer:
   xx 0

counter$digital_string_to_integer:
   xx 0

define_function "digital-string->integer", digital_string_to_integer
   ;; << string[address, length] -- integer >>
   xx zero, literal, sum$digital_string_to_integer, save
   xx zero, literal, counter$digital_string_to_integer, save

   xx dup2, string_reverse!
   xx   help__digital_string_to_integer
   xx string_reverse!, drop2

   xx literal, sum$digital_string_to_integer
   xx fetch
   xx end

define_function "help,digital-string->integer", help__digital_string_to_integer
   ;; << reversed-string[address, length] -- >>
   xx dup, zero?, false?branch, 3
   xx   drop2
   xx   end

   xx dup2, string_head__char, char_to_decimal_digital
   xx   literal, 10
   xx   literal, counter$digital_string_to_integer, fetch
   xx     one
   xx     literal, counter$digital_string_to_integer
   xx     add_save
   xx   power
   xx multiple

   xx literal, sum$digital_string_to_integer
   xx add_save

   xx string_tail__char
   xx taca, help__digital_string_to_integer

----------------------------------

find-char,string

define_function "find-char,string", find_char__string
  ;; << found:
  ;;      string[address, length], char -- address, true >>
  ;; << not found:
  ;;      string[address, length], char -- false >>
  xx over, zero?, false?branch, 5
  xx   drop, drop2
  xx   false
  xx   end
  xx xoverxx, fetch_byte
  xx over, equal?, false?branch, 4
  xx   drop2
  xx   true
  xx   end
  xx xxswapx
  xx string_tail__char
  xx xswapxx
  xx taca, find_char__string

test

: XIE Yuheng ;
32 find-char,string . << 1 >>
fetch-byte . << 32 >>

----------------------------------

io about number

write-nature-number

;; 2 ^ 64 = 18446744073709551616
;; which is of length 20
;; so
;; I use 32 to align to 16

buffer$write_nature_number labeling
   preserve 32

counter$write_nature_number:
   xx 0

define_function "write-nature-number", write_nature_number
   ;; << nature-number -- >>
   xx write_nature_number__fill_buffer
   xx write_string
   xx end

define_function "write-nature-number,fill-buffer", write_nature_number__fill_buffer
   ;; << nature-number -- >>
   xx zero
   xx literal, counter$write_nature_number, save

   xx write_nature_number__loop

   xx literal, buffer$write_nature_number
   xx literal, counter$write_nature_number, fetch
   xx string_reverse!
   xx end


define_function "write-nature-number,loop", write_nature_number__loop
   ;; << rest-number -- >>
   xx literal, 10, divmod

   xx decimal_digital_to_char
   xx literal, buffer$write_nature_number
   xx literal, counter$write_nature_number, fetch
   xx addition
   xx save_byte

   xx one
   xx literal, counter$write_nature_number
   xx add_save

   xx dup, zero?, false?branch, 3
   xx   drop
   xx   end
   xx taca, write_nature_number__loop

write-integer

define_function "write-integer", write_integer
   ;; << integer -- >>
   xx dup, positive?, false?branch, 3
   xx   write_nature_number
   xx   end
   xx literal, '-', write_byte
   xx negate
   xx write_nature_number
   xx end

pretty_write_integer

define_function ".", pretty_write_integer
   ;; << integer -- >>
   xx write_integer
   xx literal, 32
   xx write_byte
   xx end

word

----------------------------------

note io about word

  • words are separated by spaces
  • a bar-ket is a word even when there are no spaces around it

memory allocation

max_word_length = 1024

buffer$read_word labeling
   preserve max_word_length

buffer$read_word_for_REPL labeling
   preserve max_word_length

read-word-begin-char

define_function "read-word-begin-char", read_word_begin_char
   ;; << -- non-blank-char >>
   xx read_byte
   xx dup, literal, 32 ;; ascii.space
   xx greater_than?, false?branch, 2
   xx   end
   xx drop
   xx taca, read_word_begin_char

read-word->buffer

  1. skip any space-char (whitespace newline)
  2. call read_char to read characters into buffer until it hits a blank
  3. return the address of buffer and length to argument_stack
define_function "read-word->buffer", read_word_to_buffer
   ;; << buffer -- word[address, length] >>
   xx read_word_begin_char
   ;; no metter what the begin char is
   ;; save it into buffer
   xx dup2, swap, save_byte
   xx swap, add1, swap
   xx one, swap ;; leave length counter
   ;; << cursor[address in buffer], counter, begin char >>
   xx dup, bar_ket_char?, false?branch, 4
   xx   drop
   xx   help__read_word_to_buffer__bar_ket
   xx   end
   ;; maybe add other type of chars
   xx drop
   xx help__read_word_to_buffer__regular
   xx end

define_function "help,read-word->buffer,bar-ket", help__read_word_to_buffer__bar_ket
   ;; << cursor[address in buffer], counter -- word[address, length] >>
   xx tuck, subtraction
   xx swap
   xx end


define_function "help,read-word->buffer,regular", help__read_word_to_buffer__regular
   ;; << cursor[address in buffer], counter -- word[address, length] >>
   xx read_byte
   xx dup, bar_ket_char?, false?branch, 6
   xx   unread_ket_char
   xx   tuck, subtraction
   xx   swap
   xx   end
   xx dup, space_char?, false?branch, 6
   xx   drop
   xx   tuck, subtraction
   xx   swap
   xx   end
   xx xoverxx, save_byte
   xx add1
   xx swap, add1, swap
   xx taca, help__read_word_to_buffer__regular

read-word

  • read-word will override the word readed before
define_function "read-word", read_word
   ;; << -- word[address of buffer$read_word, length] >>
   xx literal, buffer$read_word, read_word_to_buffer
   xx end

read-word-for-REPL

define_function "read-word-for-REPL", read_word_for_REPL
   ;; << -- word[address of buffer$read_word_for_REPL, length] >>
   xx literal, buffer$read_word_for_REPL, read_word_to_buffer
   xx end

----------------------------------

note

  • one should use space-string? to make sure that the string is not space-string before apply string-[head|tail],word onto the string

space-string?

define_function "space-string?", space_string?
   ;; << string[address, length] -- bool >>
   xx dup, zero?, false?branch, 4
   xx   drop2, true
   xx   end
   xx dup2, string_head__char, space_char?, false?branch, 4
   xx   string_tail__char
   xx   taca, space_string?
   xx drop2, false
   xx end

string->word-[begin|end]

  • the error is not handled so before calling (string->word-begin) one should make sure that the argument is not a space-string
define_function "string->word-begin", string_to_word_begin
   ;; << string[address, length] -- string[address, length] >>
   xx dup, zero?, false?branch, 2
   ;;   no error handling
   xx   end
   xx dup2, string_head__char
   xx space_char?, false?, false?branch, 2
   xx   end
   xx string_tail__char
   xx taca, string_to_word_begin

define_function "string->word-end", string_to_word_end
   ;; << string[address, length] -- string[address, length] >>
   xx dup, zero?, false?branch, 2
   ;;   no error handling
   xx   end
   xx dup2, string_head__char
   xx bar_ket_char?, false?branch, 3
   xx   string_tail__char
   xx   end
   xx help__string_to_word_end
   xx end

define_function "help,string->word-end", help__string_to_word_end
   ;; << string[address, length] -- address >>
   xx dup, zero?, false?branch, 2
   ;;   no error handling
   xx   end
   xx dup2, string_head__char
   xx space_char?, false?branch, 2
   xx   end
   xx dup2, string_head__char
   xx bar_ket_char?, false?branch, 2
   xx   end
   xx string_tail__char
   xx taca, help__string_to_word_end

string-[head|tail],word

  • note that the following functions do not create new strings
define_function "string-head,word", string_head__word
   ;; << string[address, length] -- word[address, length] >>
   xx string_to_word_begin
   xx dup2, string_to_word_end
   xx swap, drop
   xx subtraction
   xx end

define_function "string-tail,word", string_tail__word
   ;; << string[address, length] -- string[address, length] >>
   xx string_to_word_begin
   xx string_to_word_end
   xx end

----------------------------------

dictionary

note

  • the dictionary is a single-linked-list of word-jo-jojo
  • a jojo is an vector of jo
  • from a jo one can find a jojo for example this is what the “explain$function” will do to help the interpreter to explain the mean of a jo
  • from a word one can find a jo for example this is what the “define-function” will do from source code it defines new function into dictionary by creating new structured data into memory

find

  • as find
  • find jo in dictionary by word but I simply call it “find”
  • a function whoes name is prefixed by “find” maybe fail to find and maybe returns a signal to inform the function who calls it
define_variable "*first-jo-in-dictionary*", V__first_jo_in_dictionary
   xx (last_link + jo_size)

define_function "find", find
   ;; found :
   ;; << word[address, length] -- jo, true >>
   ;; not found :
   ;; << word[address, length] -- false >>
   xx V__first_jo_in_dictionary
   xx help__find
   xx end

define_function "help,find", help__find
   ;; found :
   ;; << word[address, length], jo -- jo, true >>
   ;; not found :
   ;; << word[address, length], jo -- false >>
   xx xxtuckx


   xx jo_to_name, xxoverxx

   ;; for debug
   ;; xx jo_to_name
   ;; xx   dup2
   ;; xx   dup, write_integer, literal, 32, write_byte
   ;; xx   write_string, literal, 10, write_byte
   ;; xx xxoverxx
   ;; xx   dup2
   ;; xx   dup, write_integer, literal, 32, write_byte
   ;; xx   write_string, literal, 10, write_byte


   xx string_equal?, false?branch, 4
   xx   drop2, true
   xx   end
   xx xswapxx
   xx dup, last_jo__dictionary?, false?branch, 5
   xx   drop, drop2
   xx   false
   xx   end
   xx jo_to_pre_jo
   xx taca, help__find

execute-word

define_function "execute-word", execute_word
   ;; << word[address, length] -- unknown >>
   xx dup2, integer_string?, false?branch, 3
   xx   string_to_integer
   xx   end
   ;; maybe more

   xx dup2 ;; for to report undefined word

   xx find, false?branch, 5
   xx   xxswapx, drop2
   xx   execute_jo
   xx   end

   xx write_undefined_word_report__for_execute_word
   xx write_string
   xx literal, 10
   xx write_byte
   xx end


define_function "write-undefined-word-report,for-execute-word", write_undefined_word_report__for_execute_word
   ;; << -- >>
   xx literal, string$undefined_word_report__for_execute_word
   xx literal, length$undefined_word_report__for_execute_word
   xx write_string
   xx end

string$undefined_word_report__for_execute_word:
   db "* (execute-word) MEETS UNDEFINED WORD : "
.end:
length$undefined_word_report__for_execute_word = (.end - string$undefined_word_report__for_execute_word)

basic-REPL

define_function "basic-REPL", basic_REPL
   ;; << UNKNOWN -- UNKNOWN >>
   xx read_word_for_REPL
   xx execute_word
   xx taca, basic_REPL

-----------------------------------

colon semicolon

note

  • from the aesthetics point of view I do NOT think which of the following is better then the other but I choose the second one
  • first:
    define-function factorial
      << n -- n! >>
      dup one? if
        end
      then
      dup sub1 factorial *
      end
    end
        
  • second:
    : factorial
      << n -- n! >>
      dup one? if
        end
      then
      dup sub1 factorial *
      end
    ; define-function
        

[colon|semicolon]-string?

define_function "colon-string?", colon_string?
   ;; << string[address, length] -- bool >>
   xx literal, ':'
   xx char_string?
   xx end

define_function "semicolon-string?", semicolon_string?
   ;; << string[address, length] -- bool >>
   xx literal, ';'
   xx char_string?
   xx end

comment-[begin|end]-string?

string$comment_begin:
   db "<<"

define_function "comment-begin-string?", comment_begin_string?
   ;; << string[address, length] -- bool >>
   xx literal, string$comment_begin
   xx literal, 2
   xx string_equal?
   xx end


string$comment_end:
   db ">>"

define_function "comment-end-string?", comment_end_string?
   ;; << -- >>
   xx literal, string$comment_end
   xx literal, 2
   xx string_equal?
   xx end

colon & semicolon

  • nested : ; is NOT allow and no error check for it
  • nested << >> must be handled
  • comment are handled by : ; comment inside : ; are not readed
  • note that there might be a ; in << >> when this happens the ; must NOT be readed
  • note that a bar-ket is readed as a word double-quote is special bar-ket but “<” & “>” are not viewed as bar-ket
buffer$colon labeling
   preserve 1024 * 1024

cursor$colon:
   xx 0


define_function ":", colon
   ;; << -- string[address of buffer$colon, length] >>
   xx literal, buffer$colon
   xx literal, cursor$colon, save
   xx help__loop__colon
   ;; address
   xx literal, buffer$colon
   ;; length
   xx literal, cursor$colon, fetch
   xx literal, buffer$colon
   xx subtraction
   xx end


define_function "", help__loop__colon
   ;; << -- >>
   xx read_byte
   xx help__save_byte__colon
   xx help__meet_end__colon?, false?branch, 7
   xx   literal, 3 ;; for the string " ; "
   xx   literal, cursor$colon
   xx   sub_save
   xx   end
   xx help__meet_comment__colon?, false?branch, 9
   xx   literal, 4 ;; for the string " << "
   xx   literal, cursor$colon
   xx   sub_save
   xx   ignore_comment
   xx   taca, help__loop__colon
   xx taca, help__loop__colon


define_function "", help__save_byte__colon
   ;; << byte -- >>
   xx literal, cursor$colon, fetch
   xx save_byte
   xx one
   xx literal, cursor$colon
   xx add_save
   xx end


define_function "", help__meet_end__colon?
   ;; << -- bool >>
   xx literal, cursor$colon, fetch
   xx literal, 3, subtraction
   xx fetch_byte, space_char?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx literal, cursor$colon, fetch
   xx literal, 2, subtraction
   xx fetch_byte, literal, ';', equal?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx literal, cursor$colon, fetch
   xx literal, 1, subtraction
   xx fetch_byte, space_char?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx true
   xx end

define_function "", help__meet_comment__colon?
   ;; << -- bool >>
   xx literal, cursor$colon, fetch
   xx literal, 4, subtraction
   xx fetch_byte, space_char?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx literal, cursor$colon, fetch
   xx literal, 3, subtraction
   xx fetch_byte, literal, '<', equal?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx literal, cursor$colon, fetch
   xx literal, 2, subtraction
   xx fetch_byte, literal, '<', equal?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx literal, cursor$colon, fetch
   xx literal, 1, subtraction
   xx fetch_byte, space_char?
   xx false?, false?branch, 3
   xx   false
   xx   end
   xx true
   xx end

ignore-comment

  • this function is for basic-REPL but it is reused by colon
define_function "<<", ignore_comment
   ;; << -- >>
   xx read_word
   xx dup2, comment_begin_string?, false?branch, 5
   xx   drop2
   xx     ignore_comment ;; for the new nested-comment
   xx   taca, ignore_comment ;; for the rest-comment
   xx dup2, comment_end_string?, false?branch, 3
   xx   drop2
   xx   end
   xx drop2
   xx taca, ignore_comment

test

1 << 989 >> 64 add .
<< 65 >>

: kkk << 989 << 989 >> >> ; .s
<< kkk >>

function & jojo

----------------------------------

memory allocation

size$jo_heap = 1024 * 1024 * jo_size

define_variable "*jo-heap*", V__jo_heap
  xx address$jo_heap

define_variable "*size,jo-heap*", V__size__jo_heap
  xx size$jo_heap


address$jo_heap labeling
   preserve size$jo_heap

define_variable "*current-free-address,jo-heap*", V__current_free_address__jo_heap
   xx address$jo_heap

----------------------------------

note

  • the make-jojo is a macro dispatcher it can be viewed as make-function-body it gets next word and use predicates on word to do dispatch
  • note that make-jojo can be viewed as the “compiler” of the cicada-nymph it does NOT (can not) compile file to file but creates structured data directly into memory

!undo-make-jojo

define_exception "!undo-make-jojo", !undo_make_jojo
   ;; << old V__current_free_address__primitive_string
   ;;    old V__current_free_address__jo_heap
   ;;    old V__first_jo_in_dictionary
   ;;    string[address, length]
   ;;    -- >>
   xx literal, string$undo_make_jojo_report
   xx literal, length$undo_make_jojo_report
   xx write_string

   xx write_string
   xx literal, 10, write_byte
   xx literal, ';', write_byte
   xx literal, 10, write_byte

   xx address, V__first_jo_in_dictionary, save
   xx address, V__current_free_address__jo_heap, save
   xx address, V__current_free_address__primitive_string
   xx save
   xx end


string$undo_make_jojo_report:
   db "  THE FOLLOWING JOJO IS NOT MADE :"
   db 10
   db ": "
.end:
length$undo_make_jojo_report = (.end - string$undo_make_jojo_report)

make-jojo

  • 這裏又產生了特殊的一類珠 它木訥雖然以 “M__” 爲前綴 但是沒有作爲字符串的名字 每個這種珠都與一個謂詞相對
define_function "make-jojo", make_jojo
   ;; << string[address, length] -- >>
   xx local_variable_table__clear
   xx make_jojo__loop
   xx end

define_function "make-jojo,loop", make_jojo__loop
   ;; << string[address, length] -- >>
   xx dup2, space_string?, false?branch, 3
   xx   drop2
   xx   end
   xx dup2
   xx string_tail__word
   xx xxswapxx
   xx string_head__word
   ;; << tail[address, length], head[address, length] >>
   xx make_jojo__dispatch_word
   xx taca, make_jojo__loop

define_function "make-jojo,dispatch-word", make_jojo__dispatch_word
   ;; << string[address, length], word[address, length] --
   ;;    string[address, length] >>
   xx dup2
   xx find_dispatch_word_stack, true?, false?branch, 3
   xx   execute_jo
   xx   end
   xx dup2
   xx find, false?
   xx false?branch, 7
   xx   write_undefined_word_report__for_make_jojo
   xx   write_string
   xx   literal, 10, write_byte
   xx   !undo_make_jojo
   xx xxswapx, drop2 ;; word
   xx make_jojo__dispatch_jo
   xx end

define_function "make-jojo,dispatch-jo", make_jojo__dispatch_jo
   ;; << string[address, length], jo --
   ;;    string[address, length] >>
   xx dup, macro_jo?, false?branch, 3
   xx   execute_jo
   xx   end

   ;; the same to
   ;;   function
   ;;   primitive-function
   ;;   variable
   ;;   exception
   xx save_into__jo_heap
   xx end


define_function "write-undefined-word-report,for-make-jojo", write_undefined_word_report__for_make_jojo
   ;; << -- >>
   xx literal, string$undefined_word_report__for_make_jojo
   xx literal, length$undefined_word_report__for_make_jojo
   xx write_string
   xx end

string$undefined_word_report__for_make_jojo:
   db "* (make-jojo) MEETS UNDEFINED WORD : "
.end:
length$undefined_word_report__for_make_jojo = (.end - string$undefined_word_report__for_make_jojo)

dispatch_word_stack

note

  • for we do not build border-check into the interface of pop and push we allocation some memory below the stacks
  • the size$dispatch_word_stack defines the max number of word dispatchers
  • values in dispatch_word_stack are two by two << dispatcher [macro, predicate] >>

memory allocation

size$dispatch_word_stack = 1024 * jo_size

   preserve 64 * jo_size
address$dispatch_word_stack labeling
   preserve size$dispatch_word_stack

pointer

pointer$dispatch_word_stack:
   xx address$dispatch_word_stack

push & pop

match =64bit, machine {

define_primitive_function "push-dispatch-word-stack", push_dispatch_word_stack
   ;; argument-stack -> dispatch-word-stack
   pop_argument_stack rax
   mov rbx, [pointer$dispatch_word_stack]
   mov [rbx], rax
   add qword [pointer$dispatch_word_stack], jo_size
   next

define_primitive_function "pop-dispatch-word-stack", pop_dispatch_word_stack
   ;; dispatch-word-stack -> argument-stack
   sub qword [pointer$dispatch_word_stack], jo_size
   mov rbx, [pointer$dispatch_word_stack]
   mov rax, [rbx]
   push_argument_stack rax
   next

}

push & pop

match =32bit, machine {

define_primitive_function "push-dispatch-word-stack", push_dispatch_word_stack
   ;; argument-stack -> dispatch-word-stack
   pop_argument_stack rax
   mov rsi, [pointer$dispatch_word_stack]
   mov [rsi], rax
   add dword [pointer$dispatch_word_stack], jo_size
   next

define_primitive_function "pop-dispatch-word-stack", pop_dispatch_word_stack
   ;; dispatch-word-stack -> argument-stack
   sub dword [pointer$dispatch_word_stack], jo_size
   mov rsi, [pointer$dispatch_word_stack]
   mov rax, [rsi]
   push_argument_stack rax
   next

}

clear

match =64bit, machine {

define_primitive_function "clear-dispatch-word-stack", clear_dispatch_word_stack
   ;; << -- >>
   mov qword [pointer$dispatch_word_stack], address$dispatch_word_stack
   next

}

clear

match =32bit, machine {

define_primitive_function "clear-dispatch-word-stack", clear_dispatch_word_stack
   ;; << -- >>
   mov eax, address$dispatch_word_stack
   mov dword [pointer$dispatch_word_stack], eax;address$dispatch_word_stack
   next

}

find

define_function "find-dispatch-word-stack", find_dispatch_word_stack
   ;; << word[address, length]
   ;;    -- jo, true
   ;;    -- false >>
   xx literal, pointer$dispatch_word_stack, fetch
   xx literal, cursor$find_dispatch_word_stack, save
   xx find_dispatch_word_stack__loop
   xx end

cursor$find_dispatch_word_stack:
   xx 0

define_function "find-dispatch-word-stack,loop", find_dispatch_word_stack__loop
   ;; << word[address, length]
   ;;    -- jo, true
   ;;    -- false >>
   xx literal, cursor$find_dispatch_word_stack, fetch
   xx literal, address$dispatch_word_stack
   xx equal?, false?branch, 4
   xx   drop2
   xx   false
   xx   end
   xx dup2
   xx literal, cursor$find_dispatch_word_stack, fetch
   xx V__jo_size, subtraction, fetch
   xx execute_jo, true?, false?branch, (.not_found-$)/jo_size
   xx   drop2
   xx   literal, cursor$find_dispatch_word_stack, fetch
   xx   V__jo_size, subtraction
   xx   V__jo_size, subtraction, fetch
   xx   true
   xx   end
.not_found:
   xx literal, cursor$find_dispatch_word_stack, fetch
   xx V__jo_size, subtraction
   xx V__jo_size, subtraction
   xx literal, cursor$find_dispatch_word_stack, save
   xx taca, find_dispatch_word_stack__loop

initialize_dispatch_word_stack

define_function "initialize-dispatch-word-stack", initialize_dispatch_word_stack
   ;; << -- >>
   xx clear_dispatch_word_stack
   xx literal, M__integer_string, push_dispatch_word_stack
   xx literal, integer_string?, push_dispatch_word_stack
   xx end

----------------------------------

note macro in cicada-nymph

  • a macro is a function to be called at compile time with a string to be compiled as one argument and do side-effect to store data into memory and return a shorter string [this can be viewed as moving a cursor forward]
  • a macro should be highlight by text editor in a special way

address

define_macro "address", M__address
   ;; << string[address, length] -- string[address, length] >>
   xx literal, address
   xx save_into__jo_heap

   xx dup2
   xx string_head__word
   xx find, false?branch, 4
   xx   save_into__jo_heap
   xx   string_tail__word
   xx   end

   xx write_undefined_word_report__for_address
   xx dup2, string_head__word, write_string
   xx literal, 10, write_byte
   xx !undo_make_jojo


define_function "write-undefined-word-report,for-address", write_undefined_word_report__for_address
   ;; << -- >>
   xx literal, string$undefined_word_report__for_address
   xx literal, length$undefined_word_report__for_address
   xx write_string
   xx end

string$undefined_word_report__for_address:
   db "* (make-jojo (address)) THE WORD FOLLOWS (address) IS UNDEFINED : "
.end:
length$undefined_word_report__for_address = (.end - string$undefined_word_report__for_address)

branch

define_macro "branch", M__branch
   ;; << string[address, length] -- string[address, length] >>
   xx literal, branch
   xx save_into__jo_heap

   xx dup2
   xx string_head__word
   xx dup2, integer_string?, false?branch, 5
   xx   string_to_integer
   xx   save_into__jo_heap
   xx   string_tail__word
   xx   end

   xx write_not_integer_string_report__for_branch
   xx dup2, string_head__word, write_string
   xx literal, 10, write_byte
   xx !undo_make_jojo


define_function "write-not-integer-string-report,for-branch", write_not_integer_string_report__for_branch
   ;; << -- >>
   xx literal, string$not_integer_string_report__for_branch
   xx literal, length$not_integer_string_report__for_branch
   xx write_string
   xx end

string$not_integer_string_report__for_branch:
   db "* (make-jojo (branch)) THE WORD FOLLOWS (branch) MUST BE A INTEGER STRING : "
.end:
length$not_integer_string_report__for_branch = (.end - string$not_integer_string_report__for_branch)

false?branch

define_macro "false?branch", M__false?branch
   ;; << string[address, length] -- string[address, length] >>
   xx literal, false?branch
   xx save_into__jo_heap

   xx dup2
   xx string_head__word
   xx dup2, integer_string?, false?branch, 5
   xx   string_to_integer
   xx   save_into__jo_heap
   xx   string_tail__word
   xx   end

   xx write_not_integer_string_report__for_false?branch
   xx dup2, string_head__word, write_string
   xx literal, 10, write_byte
   xx !undo_make_jojo


define_function "write-not-integer-string-report,for-false?branch", write_not_integer_string_report__for_false?branch
   ;; << -- >>
   xx literal, string$not_integer_string_report__for_false?branch
   xx literal, length$not_integer_string_report__for_false?branch
   xx write_string
   xx end

string$not_integer_string_report__for_false?branch:
   db "* (make-jojo (false?branch)) THE WORD FOLLOWS (false?branch) MUST BE A INTEGER STRING : "
.end:
length$not_integer_string_report__for_false?branch = (.end - string$not_integer_string_report__for_false?branch)

double-quote

  • primitive-string-heap is used to allocate string literal in function body
  • in ASCII encode double-quote is 34
define_macro '"', M__double_quote
   ;; << string[address, length] -- string[address, length] >>
   xx dup2
   xx literal, '"', find_char__string
   xx false?branch, (.not_found-$)/jo_size
   xx   xoverxx, subtraction
   ;;   << string[address, length], length >>

   ;; address
   xx   literal, literal
   xx     save_into__jo_heap
   xx   V__current_free_address__primitive_string, add2
   xx     save_into__jo_heap
   xx   xoverxx, over
   xx     save_into__primitive_string_heap

   ;; length
   xx   literal, literal
   xx     save_into__jo_heap
   xx   dup
   xx     save_into__jo_heap

   xx   tuck, subtraction
   xx   xxswapx
   xx   addition
   xx   swap

   xx   string_tail__char ;; over the ending double-quote
   xx   end

   .not_found:
   xx write_not_integer_string_report__for_double_quote
   xx literal, 10, write_byte
   xx !undo_make_jojo


define_function "write-not-integer-string-report,for-double-quote", write_not_integer_string_report__for_double_quote
   ;; << -- >>
   xx literal, string$not_integer_string_report__for_double_quote
   xx literal, length$not_integer_string_report__for_double_quote
   xx write_string
   xx end

string$not_integer_string_report__for_double_quote:
   db "* (make-jojo (double-quote)) CAN NOT FIND THE ENDING DOUBLE-QUOTE"
.end:
length$not_integer_string_report__for_double_quote = (.end - string$not_integer_string_report__for_double_quote)

----------------------------------

M__integer_string

define_macro "", M__integer_string
   ;; << string[address, length], word[address, length] --
   ;;    string[address, length] >>
   xx literal, literal
   xx   save_into__jo_heap
   xx string_to_integer
   xx   save_into__jo_heap
   xx end

----------------------------------

note

  • for the following function I add the “CICADA__” as prefix to distinguish from their assembly code version

define-function

define_function "define-function", CICADA__define_function
   ;; << string[address, length] -- >>
   xx V__current_free_address__primitive_string, xxswapx
   xx V__current_free_address__jo_heap, xxswapx
   xx V__first_jo_in_dictionary, xxswapx
   xx prepare_for
   xx   exception_head
   xx   !undo_make_jojo
   xx   end_of_prepare


   xx V__current_free_address__primitive_string
   xx   save_into__jo_heap
   xx dup2, string_head__word
   xx   save_into__primitive_string_heap

   xx V__first_jo_in_dictionary
   xx jo_to_link
   xx   save_into__jo_heap

   xx V__current_free_address__jo_heap
   xx address, V__first_jo_in_dictionary
   xx save

   xx literal, explain$function
   xx   save_into__jo_heap

   xx dup2, string_tail__word
   xx   make_jojo


   xx drop2
   xx drop, drop, drop
   xx end

test

: addadd add add end ; define-function
1 2 3 addadd . << 6 >>

: add1 1 add end ; define-function
1 add1 . << 2 >>

: negate 0 swap sub end ; define-function
1 negate . << -1 >>

----------------------------------

define-macro

define_function "define-macro", CICADA__define_macro
   ;; << string[address, length] -- >>
   xx V__current_free_address__primitive_string, xxswapx
   xx V__current_free_address__jo_heap, xxswapx
   xx V__first_jo_in_dictionary, xxswapx
   xx prepare_for
   xx   exception_head
   xx   !undo_make_jojo
   xx   end_of_prepare


   xx V__current_free_address__primitive_string
   xx   save_into__jo_heap
   xx dup2, string_head__word
   xx   save_into__primitive_string_heap

   xx V__first_jo_in_dictionary
   xx jo_to_link
   xx   save_into__jo_heap

   xx V__current_free_address__jo_heap
   xx address, V__first_jo_in_dictionary
   xx save

   xx literal, explain$macro
   xx   save_into__jo_heap

   xx dup2, string_tail__word
   xx   make_jojo


   xx drop2
   xx drop, drop, drop
   xx end

----------------------------------

define-exception

define_function "define-exception", CICADA__define_exception
   ;; << string[address, length] -- >>
   xx V__current_free_address__primitive_string, xxswapx
   xx V__current_free_address__jo_heap, xxswapx
   xx V__first_jo_in_dictionary, xxswapx
   xx prepare_for
   xx   exception_head
   xx   !undo_make_jojo
   xx   end_of_prepare


   xx V__current_free_address__primitive_string
   xx   save_into__jo_heap
   xx dup2, string_head__word
   xx   save_into__primitive_string_heap

   xx V__first_jo_in_dictionary
   xx jo_to_link
   xx   save_into__jo_heap

   xx V__current_free_address__jo_heap
   xx address, V__first_jo_in_dictionary
   xx save

   xx literal, explain$exception
   xx   save_into__jo_heap

   xx dup2, string_tail__word
   xx   make_jojo


   xx drop2
   xx drop, drop, drop
   xx end

----------------------------------

note

  • not undo is needed for define-variable

define-variable

define_function "define-variable", CICADA__define_variable
   ;; << variable, string[address, length] -- >>
   xx V__current_free_address__primitive_string
   xx   save_into__jo_heap
   xx dup2, string_head__word
   xx   save_into__primitive_string_heap

   xx V__first_jo_in_dictionary
   xx jo_to_link
   xx   save_into__jo_heap

   xx V__current_free_address__jo_heap
   xx address, V__first_jo_in_dictionary
   xx save

   xx literal, explain$variable
   xx   save_into__jo_heap

   ;; when debugging
   ;; instead of drop2
   ;; one may wish to do some thing to the string
   xx drop2
   xx save_into__jo_heap
   xx end

----------------------------------

note

  • you can see how the naming convention is used for functions that create structured data into memory

save-into,primitive-string-heap

define_function "save-into,primitive-string-heap", save_into__primitive_string_heap
   ;; << string[address, length] -- >>
   xx dup, V__current_free_address__primitive_string
   xx save_two_bytes

   xx literal, 2
   xx address, V__current_free_address__primitive_string
   xx add_save

   xx tuck
   xx V__current_free_address__primitive_string
   xx string_to_buffer!

   xx address, V__current_free_address__primitive_string
   xx add_save
   xx end

save-into,jo-heap

define_function "save-into,jo-heap", save_into__jo_heap
   ;; << number -- >>
   xx V__current_free_address__jo_heap
   xx save

   xx literal, jo_size
   xx address, V__current_free_address__jo_heap
   xx add_save
   xx end

----------------------------------

test

233 : *three* ; define-variable
: add-three *three* add end ; define-function
1 add-three . << 234 >>

<< you get the address of the variable *three*
   by add "address" in front of it >>
: fix-*three* 3 address *three* save end ; define-function
fix-*three*
1 add-three . << 4 >>

----------------------------------

-----------------------------------

local-variable

----------------------------------

note to compare readability

example code without local-variable

: name-hash-table,insert,loop
  << string[address, length], number, counter
     -- name, true
     -- name, false >>
  xx|tuck|xx name-hash-table,hash
  xx|tuck|x
  << number, counter, name, string[address, length], name >>
  name,used? false? if
    x|over|xx name,save-string
      xx|tuck|x << name as return value >>
    << name, number, counter, name >>
    x|over|xx 0 name-hash-table,hash
    swap name,save-orbiton
    << name, number, counter >>
    swap 0 name-hash-table,hash
    name,save-orbit-length
    1 address *name-hash-table,counter* add-save
    true
    end
  then
  << number, counter, name, string[address, length] >>
  x|over|xx name,fetch-string
  xx|over|xx string-equal? if
    drop2 xx|swap|x drop2
    true
    end
  then
  << number, counter, name, string[address, length] >>
  x|over|xxx *name-hash-table,size* equal? if
    drop2 xx|swap|x drop2
    false
    end
  then
  << number, counter, name, string[address, length] >>
  x|swap|xx drop
  xx|swap|xx add1
  <> name-hash-table,insert,loop
; define-function

: name-hash-table,insert
  << string[address, length]
     -- name, true
     -- name, false >>
  dup2 string->finite-carry-sum
  0 name-hash-table,insert,loop
  end
; define-function

example code with local-variable

: name-hash-table,insert,loop
  << string[address, length], number, counter
     -- name, true
     -- name, false >>
  >:counter >:number >::string
  :number :counter name-hash-table,hash
  >:name
  :number 0 name-hash-table,hash
  >:orbit
  :name name,used? false? if
    ::string :name
    name,save-string
    :orbit :name
    name,save-orbiton
    :counter :orbit
    name,save-orbit-length
    1 address *name-hash-table,counter* add-save
    :name true
    end
  then
  :name name,fetch-string
  ::string string-equal? if
    :name true
    end
  then
  :counter *name-hash-table,size* equal? if
    :name false
    end
  then
  ::string
  :number :counter add1
  <> name-hash-table,insert,loop
; define-function

: name-hash-table,insert
  << string[address, length]
     -- name, true
     -- name, false >>
  dup2 string->finite-carry-sum
  0 name-hash-table,insert,loop
  end
; define-function

----------------------------------

記 詮釋者 與 收尾詞

  • 在進行時 每次進入一個函數體的執行 即 每次將一串珠珠入棧時 同時在這串珠子底部加上 current_free_address$local_data_heap 即 在 explain$function 中需要做特殊處理 注意 explain$exception explain$macro 等等 和 explain$function 並沒有區別 只是名字不一樣而已 所以也需要做特殊處理
  • 這個值在函數退出時 [即 在 end 這個函數中] 用以重置 current_free_address$local_data_heap 也就是 釋放在這次函數作用過程中所分配的內存
  • 每次 >:name 的時候 都更新 current_free_address$local_data_heap 以分配內存就行了
  • 也就是說 return-stack 中的大多數有效值 都是以兩個值一對的方式存在的
  • 兩個結尾詞是 end 和 <> 對於 <> 即 對於明顯的尾遞歸調用 需要利用棧中的值重置 current_free_address$local_data_heap 但是並不入棧新值

記 語法擴展方面的支持

  • 這裏需要識別 >:name 還有 :name 等等 並對它們做特殊處理 這些東西應該藉助設計良好的語法擴展機制來實現
  • 也就是說 單純的 define-macro 是不充分的 需要讓 make-jojo 維護一個列表 以動態的方式查找 語法謂詞
  • 實際上 我將使用一個 語法謂詞 的棧 可以發現 這樣的話 我就能很容易地臨時改變語法了

記 注意

  • 需要重寫的部分還有 exception-handling

note interface

  • 首先要滿足最基本的 長度爲 jo-size 的倍數的 局部變量的需求 其次 還要能夠在所申請的局部空間裏使用字符串 這兩種長度的數據結構需要共存 使用 offset 就行了
  • 底層 local-data-allocate,byte 這個只讓 current_free_address$local_data_heap 前進 而不後退
  • 注意 最爲重要的特點是 所有的對 局部數據堆 的使用 都必須在編譯時期被靜態地算出來 所以必須設計語法幫助編譯器作計算 >:name :name 用以 分配 和 使用 jo-size 倍數大小的內存 而 16 %>:address 將分配 16 byte 的內存 然後把內存首的地址存放到 :address 這個局部變量中
  • 語義方面 >:name 的重複出現有兩種語義
    1. 更新這個局部變元的值
    2. 覆蓋上一個局部變元綁定

    我選擇第一種 因爲這樣 我就不必設計額外的語法來更新局部變元的值了 比較簡潔

記 語義特點總結

  • 所有有名局部變元的名字與值的對應 都由編譯器處理
  • 每個函數體就是一個非常線性的東西 函數體中不能嵌套別的函數體

記 語用特點總結

  • 所有的函數都是全局的 包括輔助函數
  • 所以設計輔助函數的時候 應該格外小心 儘量使得輔助函數能夠被重用
  • 改代碼並調整對輔助函數的使用 就被稱作是 “re-factoring” 即 函數的因子的重新分解

----------------------------------

memory allocation

size$local_data_heap = 3 * 1024 * 1024

address$local_data_heap labeling
   preserve size$local_data_heap

current_free_address$local_data_heap:
   xx address$local_data_heap

local_data_allocate__[byte,jo]

define_function "local-data-allocate,byte", local_data_allocate__byte
   ;; << number -- >>
   xx literal, current_free_address$local_data_heap
   xx add_save
   xx end

define_function "local-data-allocate,jo", local_data_allocate__jo
   ;; << number -- >>
   xx V__jo_size, multiple
   xx literal, current_free_address$local_data_heap
   xx add_save
   xx end

note many fetch & save

  • in memory
    1 : value-1
    1 : value-2
    1 : value-3
  • on stack << value-1, value-2, value-3, … >>

n-fetch & n-save

match =64bit, machine {

define_primitive_function "n-fetch-local-data", n_fetch_local_data
   ;; << offset, n -- value-1, ..., value-n >>
   mov rbx, [pointer$return_stack - (2 * jo_size)]

   pop_argument_stack rcx
   pop_argument_stack rdx
   add rbx, rdx
.loop:
   mov rax, [rbx]
   push_argument_stack rax
   add rbx, jo_size
   loop .loop
   next

define_primitive_function "n-save-local-data", n_save_local_data
   ;; << value-n, ..., value-1, offset, n -- >>
   mov rbx, [pointer$return_stack - (2 * jo_size)]

   pop_argument_stack rcx
   pop_argument_stack rdx
   add rbx, rdx
     mov rax, jo_size
     imul rax, rcx
     add rbx, rax
     ;; for address is based on 0
     ;; but n is based on 1
     sub rbx, jo_size
.loop:
   pop_argument_stack rax
   mov [rbx], rax
   sub rbx, jo_size
   loop .loop
   next

}

n-fetch & n-save

match =32bit, machine {

define_primitive_function "n-fetch-local-data", n_fetch_local_data
   ;; << offset, n -- value-1, ..., value-n >>
   mov rax, [pointer$return_stack]
   mov rbx, [rax - (2 * jo_size)]

   pop_argument_stack rcx
   pop_argument_stack rdx
   add rbx, rdx
.loop:
   mov rax, [rbx]
   push_argument_stack rax
   add rbx, jo_size
   loop .loop
   next

define_primitive_function "n-save-local-data", n_save_local_data
   ;; << value-n, ..., value-1, offset, n -- >>
   mov rax, [pointer$return_stack]
   mov rbx, [rax - (2 * jo_size)]

   pop_argument_stack rcx
   pop_argument_stack rdx
   add rbx, rdx
     mov rax, jo_size
     imul rax, rcx
     add rbx, rax
     ;; for address is based on 0
     ;; but n is based on 1
     sub rbx, jo_size
.loop:
   pop_argument_stack rax
   mov [rbx], rax
   sub rbx, jo_size
   loop .loop
   next

}

----------------------------------

note example result

  • with >::name without @:address
    : example
      << number1, number2, number3, number4
         -- number1, number2 >>
      >::var2
      >::var2
      ::var2
      end
    ; define-function
        

    define_function "example", example
    
       ;; >::var2
       xx literal, 2, local_data_allocate__jo
       xx literal, 0, literal, 2, n_save_local_data
    
       ;; >::var2
       xx literal, 0, literal, 2, n_save_local_data
    
       ;; ::var2
       xx literal, 0, literal, 2, n_fetch_local_data
    
       xx end
        

note example result 2

  • with @:address without >::name
    : example
      << -- >>
      @:address 16
      @:address 32
      end
    ; define-function
        

    define_function "example", example
    
       ;; @:address 16
       xx literal, 1, local_data_allocate__jo
       xx literal, 16
       xx   literal, current_free_address$local_data_heap
       xx   fetch, swap
       xx local_data_allocate__byte
    
       xx literal, (0 + jo_size + 16), n_save_local_data
    
       ;; @:address 32
       xx literal, 32
       xx   literal, current_free_address$local_data_heap
       xx   fetch, swap
       xx local_data_allocate__byte
       xx literal, (0 + jo_size + 16), n_save_local_data
    
       xx end
        

test

: local-variable,test
  << number1, number2, number3 -- number1 + number2 >>
  >:var2
  >:var2
  >:var1
  :var1
  :var2
  add
  end
; define-function
1 2 4 local-variable,test << 3 >> .


: local-variable,test,2
  << number1, number2 -- number2 + number3 >>
  >::var2
  ::var2
  end
; define-function
1 2 local-variable,test,2 << 1 2 >> . .


: local-variable,test,3
  << number1, number2, number3 -- number2 + number3 >>
  >::var2
  >:var1
  ::var2
  add
  end
; define-function
1 2 4 local-variable,test,3 << 6 >> .

count-front-colon

define_function "count-front-colon", count_front_colon
   ;; << string[address, length] -- number >>
   xx literal, 0 ;; counter
   xx count_front_colon__loop
   xx end

define_function "count-front-colon,loop", count_front_colon__loop
   ;; << string[address, length], counter -- number >>
   xx over, zero?, false?branch, 4
   xx   xxswapx, drop2
   xx   end
   xx xxoverx, string_head__char
   xx literal, ':', equal?, false?, false?branch, 4
   xx   xxswapx, drop2
   xx   end
   xx add1, xxswapx
   xx string_tail__char, xswapxx
   xx taca, count_front_colon__loop

----------------------------------

local-variable-fetch-string?

  • :name ::name
define_function "local-variable-fetch-string?", local_variable_fetch_string?
   ;; << string[address, length] -- bool >>
   xx dup, zero?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, count_front_colon
   xx dup, literal, 0, greater_than?, false?, false?branch, 5
   xx   drop, drop2, false
   xx   end
   xx subtraction
   xx swap, drop
   xx literal, 0, greater_than?
   xx end

M__local_variable_fetch_string

define_macro "", M__local_variable_fetch_string
   ;; << string[address, length], word[address, length] --
   ;;    string[address, length] >>
   xx dup2
   xx local_variable_table__find, false?branch, (.not_found-$)/jo_size
   ;;   literal, <offese>, literal, n, n_fetch_local_data
   xx     literal, literal
   xx       save_into__jo_heap
   ;;     offset
   xx       save_into__jo_heap
   xx     literal, literal
   xx       save_into__jo_heap
   ;;     n
   xx     count_front_colon
   xx       save_into__jo_heap
   xx     literal, n_fetch_local_data
   xx       save_into__jo_heap
   xx   end
.not_found:
   ;; ><><>< exception handling
   xx write_local_variable_not_bound_report
   xx write_string
   xx literal, 10, write_byte
   xx !undo_make_jojo


define_function "write-local-variable-not-bound-report", write_local_variable_not_bound_report
   xx literal, string$local_variable_not_bound_report
   xx literal, length$local_variable_not_bound_report
   xx write_string
   xx end

string$local_variable_not_bound_report:
   db "* LOCAL-VARIABLE NOT BOUND : "
.end:
length$local_variable_not_bound_report = (.end - string$local_variable_not_bound_report)

----------------------------------

local-variable-save-string?

  • >:name >::name
define_function "local-variable-save-string?", local_variable_save_string?
   ;; << string[address, length] -- bool >>
   xx dup, zero?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, string_head__char
   xx literal, '>', equal?, false?, false?branch, 4
   xx   drop2, false
   xx   end
   xx string_tail__char
   xx dup2, count_front_colon
   xx dup, literal, 0, greater_than?, false?, false?branch, 5
   xx   drop, drop2, false
   xx   end
   xx subtraction
   xx swap, drop
   xx literal, 0, greater_than?
   xx end

M__local_variable_save_string

define_macro "", M__local_variable_save_string
   ;; << string[address, length], word[address, length] --
   ;;    string[address, length] >>
   xx string_tail__char
   xx dup2
   xx local_variable_table__find, false?branch, (.not_found-$)/jo_size
   ;;   literal, <offese>, literal, n, n_save_local_data
   xx     literal, literal
   xx       save_into__jo_heap
   ;;     offset
   xx       save_into__jo_heap
   xx     literal, literal
   xx       save_into__jo_heap
   ;;     n
   xx     count_front_colon
   xx       save_into__jo_heap
   xx     literal, n_save_local_data
   xx       save_into__jo_heap
   xx   end
.not_found:
   xx dup2
   xx local_variable_table__insert
   xx xxswapx
   xx count_front_colon
   ;; literal, <number>, local_data_allocate__jo
   xx   literal, literal
   xx     save_into__jo_heap
   ;;   number of jo
   xx     dup, save_into__jo_heap
   xx   literal, local_data_allocate__jo
   xx     save_into__jo_heap
   ;; literal, <offese>, literal, n, save_local_data
   xx   literal, literal
   xx     save_into__jo_heap
   ;;   offset
   xx   swap
   xx     save_into__jo_heap
   xx   literal, literal
   xx     save_into__jo_heap
   ;;   n
   xx     save_into__jo_heap
   xx   literal, n_save_local_data
   xx     save_into__jo_heap
   xx end

----------------------------------

>< local-variable-save-address-string?

  • @:address
define_function "local-variable-save-address-string?", local_variable_save_address_string?
   ;; << string[address, length] -- bool >>
   xx dup, literal, 3, less_than?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, string_head__char
   xx literal, '@', equal?, false?, false?branch, 4
   xx   drop2, false
   xx   end
   xx dup2, string_head__char
   xx literal, ':', equal?, false?, false?branch, 4
   xx   drop2, false
   xx   end
   xx string_head__char
   xx literal, ':', equal?, false?
   xx end

>< M__local_variable_save_address_string

  • @:address <literal-number> <literal-number> must be literal for the amount of memory be allocated must be decided as compile-time
define_macro "", M__local_variable_save_address_string
   ;; << string[address, length], word[address, length] --
   ;;    string[address, length] >>
   xx string_tail__char
   xx dup2

   xx end

----------------------------------

local-variable-table

memory allocation

size$local_variable_table = 100 * 1024

address$local_variable_table labeling
   preserve size$local_variable_table

clear

border$local_variable_table:
   xx address$local_variable_table

offset$local_variable_table:
   xx 0

define_function "local-variable-table,clear", local_variable_table__clear
   ;; << -- >>
   xx literal, address$local_variable_table
   xx literal, border$local_variable_table, save
   xx literal, 0
   xx literal, offset$local_variable_table, save
   xx end

insert

define_function "local-variable-table,insert", local_variable_table__insert
   ;; << string[address, length] -- offset >>

   ;; leave offset
   xx literal, offset$local_variable_table, fetch
   xx   xxtuckx ;; return value
   xx literal, border$local_variable_table, fetch, save
   xx V__jo_size
   xx literal, border$local_variable_table, add_save

   ;; update offset$local_variable_table
   xx dup2
   xx   count_front_colon
   xx   V__jo_size, multiple
   xx   literal, offset$local_variable_table, add_save

   ;; leave length
   xx dup
   xx literal, border$local_variable_table, fetch, save
   xx V__jo_size
   xx literal, border$local_variable_table, add_save

   xx tuck ;; for to update border$local_variable_table

   ;; leave string
   xx literal, border$local_variable_table, fetch
   xx string_to_buffer!

   ;; update border$local_variable_table
   xx literal, border$local_variable_table, add_save

   xx end

find

cursor$local_variable_table:
   xx address$local_variable_table

define_function "local-variable-table,find", local_variable_table__find
   ;; << string[address, length]
   ;;    -- offset, true
   ;;    -- false >>
   xx literal, address$local_variable_table
   xx literal, cursor$local_variable_table, save
   xx local_variable_table__find__loop
   xx end

define_function "local-variable-table,find,loop", local_variable_table__find__loop
   ;; << string[address, length]
   ;;    -- offset, true
   ;;    -- false >>
   xx literal, cursor$local_variable_table, fetch
   xx literal, border$local_variable_table, fetch
   xx greater_or_equal?, false?branch, 4
   xx   drop2
   xx   false
   xx   end
   xx dup2
   xx literal, cursor$local_variable_table, fetch
   xx   V__jo_size, addition
   xx   V__jo_size, addition ;; address of string
   xx literal, cursor$local_variable_table, fetch
   xx   V__jo_size, addition
   xx   fetch ;; length of string
   xx string_equal?, false?branch, 8
   xx   drop2
   xx   literal, cursor$local_variable_table, fetch
   xx     fetch ;; offset
   xx   true
   xx   end
   xx literal, cursor$local_variable_table, fetch
   xx   V__jo_size, addition
   xx   fetch ;; length of string
   xx V__jo_size, addition
   xx V__jo_size, addition
   xx literal, cursor$local_variable_table, add_save
   xx taca, local_variable_table__find__loop

----------------------------------

initialize-local-variable

define_function "initialize-local-variable", initialize_local_variable
   ;; << -- >>
   xx literal, M__local_variable_save_string,  push_dispatch_word_stack
   xx literal, local_variable_save_string?,    push_dispatch_word_stack
   xx literal, M__local_variable_fetch_string, push_dispatch_word_stack
   xx literal, local_variable_fetch_string?,   push_dispatch_word_stack
   xx end

----------------------------------

-----------------------------------

some global variable

platform

  • this word is implemented as a function
define_function "platform", the_platform
   xx literal, string$platform
   xx literal, length$platform
   xx end

string$platform:

match =linux, platform {
   db "linux"
}

match =windows, platform {
   db "windows"
}

.end:
length$platform = (.end - string$platform)

-----------------------------------

epilog

----------------------------------

un-initialized-memory

define_variable "*un-initialized-memory*", V__un_initialized_memory
  xx address$un_initialized_memory

define_variable "*size,un-initialized-memory*", V__size__un_initialized_memory
  xx size$un_initialized_memory

define_variable "*current-free-address,un-initialized-memory*", V__current_free_address__un_initialized_memory
  xx current_free_address$un_initialized_memory

----------------------------------

current-free-address,primitive-string-heap

  • the last_primitive_string_in_assembly is just ”current-free-address,primitive-string-heap
define_variable "*current-free-address,primitive-string-heap*", V__current_free_address__primitive_string
   xx current_free_address$primitive_string_heap

----------------------------------

last_link

  • this word helps to initialize V__first_jo_in_dictionary
last_link = link

----------------------------------

size$un_initialized_memory

size$un_initialized_memory = 64 * 1024 * 1024 ;; (byte)

----------------------------------

un_initialized_memory

match =linux =64bit, platform machine {

segment readable writeable
address$un_initialized_memory:
   rb size$un_initialized_memory

}

----------------------------------

un_initialized_memory

match =linux =32bit, platform machine {

segment readable writeable
address$un_initialized_memory:
   rb size$un_initialized_memory

}

----------------------------------

un_initialized_memory

match =windows =64bit, platform machine {

section '.data' data readable writeable
address$un_initialized_memory:
   rb size$un_initialized_memory

}

macro about import

if platform eq windows
if machine eq 64bit

;; Macroinstructions for making import section (64-bit)

macro library [name,string] {
   common
    import.data:
   forward
    local _label
    if defined name#.redundant
     if ~ name#.redundant
      dd RVA name#.lookup,0,0,RVA _label,RVA name#.address
     finish if
    finish if
    name#.referred = 1
   common
    dd 0,0,0,0,0
   forward
    if defined name#.redundant
     if ~ name#.redundant
      _label db string,0
             rb RVA $ and 1
     finish if
    finish if
}

macro import name,[label,string] {
  common
    rb (- rva $) and 7
    if defined name#.referred
     name#.lookup:
   forward
     if used label
      if string eqtype ''
       local _label
       dq RVA _label
      else
       dq 8000000000000000h + string
      finish if
     finish if
   common
     if $ > name#.lookup
      name#.redundant = 0
      dq 0
     else
      name#.redundant = 1
     finish if
     name#.address:
   forward
     if used label
      if string eqtype ''
       label dq RVA _label
      else
       label dq 8000000000000000h + string
      finish if
     finish if
   common
     if ~ name#.redundant
      dq 0
     finish if
   forward
     if used label & string eqtype ''
     _label dw 0
            db string,0
            rb RVA $ and 1
     finish if
   common
    finish if
}


finish if
finish if

section about import

match =windows =64bit, platform machine {

section '.idata' import data readable writeable

library kernel32,'KERNEL32.DLL'

import kernel32,\
       ExitProcess,'ExitProcess',\
       ReadFile,'ReadFile',\
       WriteFile,'WriteFile',\
       GetStdHandle,'GetStdHandle',\
       CloseHandle, 'CloseHandle',\
       CreateFileA, 'CreateFileA'

}

----------------------------------

un_initialized_memory

match =windows =32bit, platform machine {

section '.data' data readable writeable
address$un_initialized_memory:
   rb size$un_initialized_memory

}

macro about import

if platform eq windows
if machine eq 32bit

; Macroinstructions for making import section

macro library [name,string] {
   common
    import.data:
   forward
    local _label
    if defined name#.redundant
     if ~ name#.redundant
      dd RVA name#.lookup,0,0,RVA _label,RVA name#.address
     finish if
    finish if
    name#.referred = 1
   common
    dd 0,0,0,0,0
   forward
    if defined name#.redundant
     if ~ name#.redundant
      _label db string,0
             rb RVA $ and 1
     finish if
    finish if
}

macro import name,[label,string]
 { common
    rb (- rva $) and 3
    if defined name#.referred
     name#.lookup:
   forward
     if used label
      if string eqtype ''
       local _label
       dd RVA _label
      else
       dd 80000000h + string
      finish if
     finish if
   common
     if $ > name#.lookup
      name#.redundant = 0
      dd 0
     else
      name#.redundant = 1
     finish if
     name#.address:
   forward
     if used label
      if string eqtype ''
       label dd RVA _label
      else
       label dd 80000000h + string
      finish if
     finish if
   common
     if ~ name#.redundant
      dd 0
     finish if
   forward
     if used label & string eqtype ''
     _label dw 0
            db string,0
            rb RVA $ and 1
     finish if
   common
    finish if
}

finish if
finish if

section about import

match =windows =32bit, platform machine {

section '.idata' import data readable writeable

library kernel32,'KERNEL32.DLL'

import kernel32,\
       ExitProcess,'ExitProcess',\
       ReadFile,'ReadFile',\
       WriteFile,'WriteFile',\
       GetStdHandle,'GetStdHandle',\
       CloseHandle, 'CloseHandle',\
       CreateFileA, 'CreateFileA'

}

----------------------------------

===================================