A programming language implementation for fun.
This code uses the most cutting edge feature set of the language. In some cases there is a known bug where one byte isn't returned properly, this is likely a stack misalignment error which I never got around to fixing.
// You can include standard libc functions
extern printf
extern memcpy
// This function returns an array of 13 bytes
#gen_arr:->u8(13):
// Declare an array of 13 bytes with uninitialized data
buf : u8(13) = _
// Typical C style three section for loop
for (i : i32 = 0, i < 13, i++):
// This uses some pointer arithmetic to assign values to the bytes in the array
$(@buf + i) = i
end
// return the buffer from the function
ret buf
// This function takes two arrays of 13 bytes each and prints them
#printarr:(arr: u8(13)),(arr2:u8(13)):
for (i : i32 = 0, i < 13, i++):
// Call the standard printf using all the normal format specifiers.
// Use some pointer arithmetic to get the values from the byte arrays
[printf "arr %d => %d :: %d\n", i, $(@arr+i), $(@arr2 + i)]
end
// Print out the memory address differences as an example
[printf "address difference: %d\n", (@arr2 - @arr)]
ret
// This is the typical C equivalent main function.
#main:
// Call the printarr function passing in the return value of gen_arr for each argument.
// The compiler handles moving all the memory around for us!
[printarr [gen_arr], [gen_arr]]
ret
This then can be converted into executable machine code using the nasm tool. NOTE: The comments are auto generated by the compiler based on the source code.
BITS 32
global main
extern memcpy ; Make sure we always have this
extern printf
extern memcpy
section .data
__str0: db 'arr %d => %d :: %d', 0xA, 0
__str1: db 'address difference: %d', 0xA, 0
section .text
;function declaration gen_arr
gen_arr:
push ebp
mov ebp, esp
sub esp, 16
;variable i=0
push DWORD 0 ; Push 0
pop eax
mov [ebp-20], eax
sub esp, 4 ; make room for scope variables
.__for_0:
; loop condition
push DWORD [ebp-20] ; Push i value
push DWORD 13 ; Push 13
; LSS expression
pop edx
pop eax
cmp eax,edx
setl al
push eax
pop eax
; eax now has result of condition (either 0 or 1)
cmp eax, 0
; check if condition was true or false
je .__forend_natural_0
; for body
;variable defref expr
push DWORD [ebp-20] ; Push i value
lea eax, [ebp-16]; Get address of buf
push eax; push address onto stack
push DWORD [ebp-20] ; Push i value
pop edx ; Get Right
pop eax ; Get left
add eax, edx; Add
push eax ; Push result
pop edx ; Load address
pop eax ; Load value
mov [edx], al ; type sensitive write
; incrementor
.__forinc_0:
inc DWORD [ebp-20] ; Increment i
; jump to start of loop
jmp .__for_0
.__forend_natural_0:
add esp, 4 ; pop natural for scope
.__forend_0:
; copy array onto stack
sub esp, 16
mov edx, esp
push 16
lea eax, [ebp-16]
push eax
push edx
call memcpy
add esp, 12
mov edx, esp ; Compute stack address
push 16 ; Push size
push edx; Push src*
lea edx, [ebp+8] ; Compute address of return space
push edx ; Push dst*
call memcpy
add esp, 12
add esp, 16 ; clean up special stack
mov eax, edx ; Move address of special stack into eax
;return
mov esp, ebp
pop ebp
ret
;end function gen_arr
;function declaration printarr2
printarr2:
push ebp
mov ebp, esp
sub esp, 0
;variable i=0
push DWORD 0 ; Push 0
pop eax
mov [ebp-4], eax
sub esp, 4 ; make room for scope variables
.__for_1:
; loop condition
push DWORD [ebp-4] ; Push i value
push DWORD 13 ; Push 13
; LSS expression
pop edx
pop eax
cmp eax,edx
setl al
push eax
pop eax
; eax now has result of condition (either 0 or 1)
cmp eax, 0
; check if condition was true or false
je .__forend_natural_1
; for body
lea eax, [ebp+20]; Get address of arr2
push eax; push address onto stack
push DWORD [ebp-4] ; Push i value
pop edx ; Get Right
pop eax ; Get left
add eax, edx; Add
push eax ; Push result
pop eax ; Load address
movzx eax, BYTE [eax] ; Type sensitive Read
push eax ; Push Value
lea eax, [ebp+4]; Get address of arr
push eax; push address onto stack
push DWORD [ebp-4] ; Push i value
pop edx ; Get Right
pop eax ; Get left
add eax, edx; Add
push eax ; Push result
pop eax ; Load address
movzx eax, BYTE [eax] ; Type sensitive Read
push eax ; Push Value
push DWORD [ebp-4] ; Push i value
push __str0
call printf
add esp, 16
; incrementor
.__forinc_1:
inc DWORD [ebp-4] ; Increment i
; jump to start of loop
jmp .__for_1
.__forend_natural_1:
add esp, 4 ; pop natural for scope
.__forend_1:
lea eax, [ebp+20]; Get address of arr2
push eax; push address onto stack
lea eax, [ebp+4]; Get address of arr
push eax; push address onto stack
pop edx ; Get Right
pop eax ; Get Left
sub eax, edx ; Subtract
push eax ; Push result
push __str1
call printf
add esp, 8
;return
mov esp, ebp
pop ebp
ret
;end function printarr2
;function declaration main
main:
push ebp
mov ebp, esp
sub esp, 0
sub esp, 16 ; Push space for return type
push esp ; push return space pointer as hidden first parameter
call gen_arr
add esp, 4
sub esp, 16 ; Push space for return type
push esp ; push return space pointer as hidden first parameter
call gen_arr
add esp, 4
call printarr2
add esp, 8
;return
mov esp, ebp
pop ebp
ret
;end function main