summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Gunger <kgunger12@gmail.com>2023-05-18 23:30:18 -0400
committerKyle Gunger <kgunger12@gmail.com>2023-05-18 23:30:18 -0400
commitfe7d97a0a608398f500b1c64ff885acecf2541d5 (patch)
tree2518859272af7dc0d4e1b0a4b6f16b342d5d35f4
parentb6cd30ba672c64f3d96aa2b0c98bc13f4c603d21 (diff)
File reading/writing
-rw-r--r--tnslc/c_wrap.tnsl153
-rw-r--r--tnslc/enum.tnsl9
-rw-r--r--tnslc/hello.tnsl31
-rw-r--r--tnslc/read_file_test.tnsl40
-rw-r--r--tnslc/tnslc.tnsl71
5 files changed, 256 insertions, 48 deletions
diff --git a/tnslc/c_wrap.tnsl b/tnslc/c_wrap.tnsl
index ee39cdc..d121967 100644
--- a/tnslc/c_wrap.tnsl
+++ b/tnslc/c_wrap.tnsl
@@ -1,23 +1,25 @@
+# Must be included at the top of the file
asm "extern malloc"
asm "extern realloc"
asm "extern free"
+
asm "extern printf"
+asm "extern CreateFileA"
+asm "extern ReadFile"
+asm "extern WriteFile"
+asm "extern CloseHandle"
+
{}uint8 _alert = "Alert!\n\0"
{}uint8 _dec = "%d\n\0"
/; _alloc (uint size) [~void]
~void out
# Mov size into proper register, and set all extras to zero
- asm "mov rax, 0"
- asm "mov rbx, 0"
asm "mov rcx, r8"
asm "mov rdx, 0"
- asm "mov rdi, 0"
- asm "mov rsi, 0"
asm "mov r8, 0"
asm "mov r9, 0"
- asm "mov r10, 0"
asm "call malloc"
# Set out to the returned value
# (The compiler assignes spaces sequentially, and we have a uint in r8)
@@ -28,15 +30,10 @@ asm "extern printf"
/; _realloc (~void ptr, uint new_size) [~void]
~void out
# Mov ptr and new size into proper registers, and set all extras to zero
- asm "mov rax, 0"
- asm "mov rbx, 0"
asm "mov rcx, r8"
asm "mov rdx, r9"
- asm "mov rdi, 0"
- asm "mov rsi, 0"
asm "mov r8, 0"
asm "mov r9, 0"
- asm "mov r10, 0"
# Do call
asm "call realloc"
# Set out to the returned value
@@ -47,15 +44,10 @@ asm "extern printf"
/; _delete (~void ptr)
# setup call by clearing most values
- asm "mov rax, 0"
- asm "mov rbx, 0"
asm "mov rcx, rax"
asm "mov rdx, 0"
- asm "mov rdi, 0"
- asm "mov rsi, 0"
asm "mov r8, 0"
asm "mov r9, 0"
- asm "mov r10, 0"
# do call
asm "call free"
# there's no more to do 'cause free returns nothing
@@ -65,11 +57,8 @@ asm "extern printf"
# setup call by clearing most values
asm "mov rcx, rax"
asm "mov rdx, 0"
- asm "mov rdi, 0"
- asm "mov rsi, 0"
asm "mov r8, 0"
asm "mov r9, 0"
- asm "mov r10, 0"
# do call
asm "call printf"
# there's no more to do 'cause printf returns nothing
@@ -83,13 +72,139 @@ asm "extern printf"
asm "mov rsi, 0"
asm "mov r8, 0"
asm "mov r9, 0"
- asm "mov r10, 0"
# do call
asm "call printf"
# there's no more to do 'cause printf returns nothing
;/
+
+# Create file for writing (overwrite)
+/; _create_file (~void name) [~void]
+ ~void out
+
+ asm "mov rcx, r8" # lpFileName
+ asm "mov rdx, 3" # dwDesiredAccess
+ asm "shl rdx, 30" # (GENERIC_READ 1 << 31 | GENERIC_WRITE 1 << 30)
+ asm "mov r8, 0" # dwShareMode
+ asm "mov r9, 0" # lpSecurityAttributes
+
+ asm "push qword 0" # hTemplateFile
+ asm "push qword 128" # dwFlagsAndAttributes (NORMAL_FILE = 128)
+ asm "push qword 2" # dwCreationDisposition (CREATE_ALWAYS = 2)
+
+ # Shadow space
+ asm "push r9"
+ asm "push r8"
+ asm "push rdx"
+ asm "push rcx"
+
+ # Do call
+ asm "call CreateFileA"
+
+ # Set out to the returned value
+ # (The compiler assignes spaces sequentially. We have a ptr in r8)
+ asm "mov r9, rax"
+
+ return out
+;/
+
+# Open file for reading or writing (no overwrite)
+/; _open_file (~void name) [~void]
+ ~void out
+
+ asm "mov rcx, r8" # lpFileName
+ asm "mov rdx, 3" # dwDesiredAccess
+ asm "shl rdx, 30" # (GENERIC_READ 1 << 31 | GENERIC_WRITE 1 << 30)
+ asm "mov r8, 0" # dwShareMode
+ asm "mov r9, 0" # lpSecurityAttributes
+
+ asm "push qword 0" # hTemplateFile
+ asm "push qword 128" # dwFlagsAndAttributes (NORMAL_FILE = 128)
+ asm "push qword 2" # dwCreationDisposition (CREATE_ALWAYS = 2)
+
+ # Shadow space
+ asm "push r9"
+ asm "push r8"
+ asm "push rdx"
+ asm "push rcx"
+
+ # Do call
+ asm "call CreateFileA"
+
+ # Set out to the returned value
+ # (The compiler assignes spaces sequentially. We have a ptr in r8, and a uint in r9)
+ asm "mov r10, rax"
+
+ return out
+;/
+
+/; _close_file (~void handle)
+ asm "mov rcx, r8" # handle
+ asm "mov rdx, 0"
+ asm "mov r8, 0"
+ asm "mov r9, 0"
+
+ # Shadow space
+ asm "push r9"
+ asm "push r8"
+ asm "push rdx"
+ asm "push rcx"
+
+ asm "call CloseHandle"
+
+ asm "add rsp, 32"
+;/
+
+/; _read_byte (~void handle, ~uint8 byte) [bool]
+ bool out
+
+ asm "mov rcx, r8" # handle
+ asm "mov rdx, r9" # buffer
+ asm "mov r8, 1" # one byte
+ asm "mov r9, 0"
+ asm "push qword 0"
+
+ # Shadow space
+ asm "push r9"
+ asm "push r8"
+ asm "push rdx"
+ asm "push rcx"
+
+ asm "call ReadFile"
+
+ asm "mov r10, rax"
+
+ return out
+;/
+
+/; _write_byte (~void handle, ~uint8 byte) [bool]
+ bool out
+
+ asm "mov rcx, r8" # handle
+ asm "mov rdx, r9" # buffer
+ asm "mov r8, 1" # one byte
+ asm "mov r9, 0"
+ asm "push qword 0"
+
+ # Shadow space
+ asm "push r9"
+ asm "push r8"
+ asm "push rdx"
+ asm "push rcx"
+
+ asm "call WriteFile"
+
+ asm "mov r10, rax"
+
+ return out
+;/
+
/; print_alert
_printf(~_alert{0})
;/
+/; cstr_len (~uint8 cstr) [int]
+ int i = 0
+ /; loop (cstr{i} !== 0) [i++] ;/
+ return i
+;/
diff --git a/tnslc/enum.tnsl b/tnslc/enum.tnsl
new file mode 100644
index 0000000..e8c4932
--- /dev/null
+++ b/tnslc/enum.tnsl
@@ -0,0 +1,9 @@
+# to get working
+
+enum TEST_ENUM [int] {
+ i = 0
+}
+
+/; main [int]
+ return TEST_ENUM.i
+;/ \ No newline at end of file
diff --git a/tnslc/hello.tnsl b/tnslc/hello.tnsl
index 8fb98a3..0742564 100644
--- a/tnslc/hello.tnsl
+++ b/tnslc/hello.tnsl
@@ -1,8 +1,33 @@
:include "c_wrap.tnsl"
-{}uint8 hello = "Hello World!\n\0"
+{}uint8 star = "hello.tnsl\0"
+{}uint8 space = " \0"
+{}uint8 new_line = "\n\0"
-/; main [int]
- _printf(~hello{0})
+/; print_triangle (int argc)
+ /; loop (int i = 0; i < argc) [i++]
+ /; loop (int j = 0; j < argc - i) [j++]
+ _printf(~space{0})
+ ;/
+ /; loop (int j = 0; j < 1 + 2*i) [j++]
+ _printf(~star{0})
+ ;/
+ _printf(~new_line{0})
+ ;/
+;/
+
+/; main (int argc, ~~uint8 argv) [int]
+ # On windows, the first two arguments are passed in RCX and RDX, so we need to
+ # update their positions here or else tnsl will have garbage values in r8 and r9
+ asm "mov r8, rcx"
+ asm "mov r9, rdx"
+
+ # If on linux, you would use rdi and rsi instead of rcx and rdx, respectively
+ # simply comment out the bove asm, and uncomment the below lines
+ # asm "mov r8, rdi"
+ # asm "mov r9, rsi"
+
+ print_triangle(argc)
+
return 0
;/ \ No newline at end of file
diff --git a/tnslc/read_file_test.tnsl b/tnslc/read_file_test.tnsl
new file mode 100644
index 0000000..60c4c5b
--- /dev/null
+++ b/tnslc/read_file_test.tnsl
@@ -0,0 +1,40 @@
+:include "c_wrap.tnsl"
+
+{}uint8 usage_msg = "Usage: read_file.exe [file to read] [file to write]\n\0"
+{}uint8 print_one = "\0\0"
+{}uint8 nl = "\n\0"
+
+/; main (int argc, ~~uint8 argv) [int]
+
+ # On windows, the first two arguments are passed in RCX and RDX, so we need to
+ # update their positions here or else tnsl will have garbage values in r8 and r9
+ asm "mov r8, rcx"
+ asm "mov r9, rdx"
+
+ # If on linux, you would use rdi and rsi instead of rcx and rdx, respectively
+ # simply comment out the bove asm, and uncomment the below lines
+ # asm "mov r8, rdi"
+ # asm "mov r9, rsi"
+
+ /; if (argc < 2)
+ _printf(~usage_msg{0})
+ return 1
+ ;/
+
+ _printf(argv{1})
+ _printf(~nl{0})
+
+ ~void write_handle = _create_file(argv{1})
+
+ _print_num(~_dec{0}, write_handle)
+
+ int ln = cstr_len(argv{1})
+
+ /; loop (int i = 0; i < ln) [i++]
+ _write_byte(write_handle, ~argv{1}{i})
+ ;/
+
+ _close_file(write_handle)
+
+ return 0
+;/ \ No newline at end of file
diff --git a/tnslc/tnslc.tnsl b/tnslc/tnslc.tnsl
index f75284d..a225041 100644
--- a/tnslc/tnslc.tnsl
+++ b/tnslc/tnslc.tnsl
@@ -3719,9 +3719,26 @@
;/
;/
+/; combine_tok_lists (int cut_a, cut_b, {}Token a, b) [{}Token]
+ ;{}Token out = {}
+ /; loop (int i = 0; i < cut_a) [i++]
+ ;out.append(a{i})
+ ;/
+
+ /; loop (int i = 0; i < len b) [i++]
+ ;out.append(b{i})
+ ;/
+
+ /; loop (int i = cut_b; i < len a) [i++]
+ ;out.append(a{i})
+ ;/
+
+ ;return out
+;/
+
# First compiler pass on a file
# Only creates structs, enums, and moduless
-/; compile_file_pass_one (Path f, ~Module current)
+/; compile_file_pass_one (Path f, ~Module current) [{}Token]
;{}Token tok = tokenize(f)
;log_info(string_add("Number of tokens generated: ", int_to_string(len tok)))
@@ -3730,8 +3747,9 @@
/; if (tok{i}.cmp(":"))
;log_debug("INCLUDE")
/; if (tok{i + 2}.type_is(TOKEN.LITERAL))
- ;compile_file_pass_one(f.relative(unquote_str(tok{i + 2}.data)), current)
- ;i = i + 2
+ ;{}Token inc = compile_file_pass_one(f.relative(unquote_str(tok{i + 2}.data)), current)
+ ;tok = combine_tok_lists(i, i + 3, tok, inc)
+ ;i = i + len inc
;/
;continue
;; else if (tok{i}.cmp("/;") || tok{i}.cmp(";;"))
@@ -3744,6 +3762,8 @@
;new_type(~tok, ~i, current)
;/
;/
+
+ ;return tok
;/
/; size_struct (~Type t, ~Module m)
@@ -3784,50 +3804,49 @@
# Second pass of compiler
# Does code generation, ignores structs and enums
-/; compile_file_pass_two (Path f, ~Module current) [CompData]
+/; compile_file_pass_two (~{}Token tok, ~Module current) [CompData]
;CompData out = {"", "", ""}
- ;{}Token tok = tokenize(f)
- /; loop (int i = next_non_nl(~tok, 0); i < len tok) [i = next_non_nl(~tok, i+1)]
+ /; loop (int i = next_non_nl(tok, 0); i < len tok`) [i = next_non_nl(tok, i+1)]
;log_vis(".")
- /; if (tok{i}.cmp(":"))
+ /; if (tok`{i}.cmp(":"))
;log_debug("INCLUDE")
- /; if (tok{i + 2}.type_is(TOKEN.LITERAL))
- ;CompData tmp = compile_file_pass_two(f.relative(unquote_str(tok{i + 2}.data)), current)
+ /; if (tok`{i + 2}.type_is(TOKEN.LITERAL))
+ ;CompData tmp = compile_file_pass_two(f.relative(unquote_str(tok`{i + 2}.data)), current)
;out.hsec = string_add(out.hsec, tmp.hsec)
;out.dsec = string_add(out.dsec, tmp.dsec)
;out.csec = string_add(out.csec, tmp.csec)
;i = i + 2
;/
;continue
- ;; else if (tok{i}.cmp("/;") || tok{i}.cmp(";;"))
+ ;; else if (tok`{i}.cmp("/;") || tok`{i}.cmp(";;"))
;log_debug("Root block")
- /; if (tok{i + 1}.cmp("export") || tok{i + 1}.cmp("module"))
- ;module_pass_two(~tok, ~i, current, ~out, f)
+ /; if (tok`{i + 1}.cmp("export") || tok`{i + 1}.cmp("module"))
+ ;module_pass_two(tok, ~i, current, ~out, f)
;; else
- ;compile_block(~tok, ~i, current, ~out)
+ ;compile_block(tok, ~i, current, ~out)
;/
- ;; else if (tok{i}.cmp("struct"))
+ ;; else if (tok`{i}.cmp("struct"))
;log_debug("File struct")
- ;skip_struct(~tok, ~i)
- ;; else if (tok{i}.cmp("enum"))
+ ;skip_struct(tok, ~i)
+ ;; else if (tok`{i}.cmp("enum"))
;log_debug("File enum")
- ;compile_enum(~tok, ~i, current, ~out)
- ;; else if (is_definition(~tok, ~i, current))
+ ;compile_enum(tok, ~i, current, ~out)
+ ;; else if (is_definition(tok, ~i, current))
;log_debug("File def")
- ;compile_file_def(~tok, ~i, current, ~out)
- ;; else if (tok{i}.cmp("asm"))
+ ;compile_file_def(tok, ~i, current, ~out)
+ ;; else if (tok`{i}.cmp("asm"))
;log_debug("File asm")
/; if (len (out.csec) == 0 && len (out.dsec) == 0)
- ;out.hsec = string_add(out.hsec, unquote_str(tok{i + 1}.data))
+ ;out.hsec = string_add(out.hsec, unquote_str(tok`{i + 1}.data))
;out.hsec.append('\n')
;; else
- ;out.dsec = string_add(out.dsec, unquote_str(tok{i + 1}.data))
+ ;out.dsec = string_add(out.dsec, unquote_str(tok`{i + 1}.data))
;out.dsec.append('\n')
;/
;i++
- ;; else if (!(tok{i}.cmp("\n")))
- ;log_err(string_add("Failed to recognize file-level statement", tok{i}.sprint()))
+ ;; else if (!(tok`{i}.cmp("\n")))
+ ;log_err(string_add("Failed to recognize file-level statement", tok`{i}.sprint()))
;/
;/
@@ -3841,11 +3860,11 @@
;{}uint8 out = ""
;Module root = {0, true, {}, {}, {}, {}, {}}
- ;compile_file_pass_one(f, ~root)
+ ;{}Token tok = compile_file_pass_one(f, ~root)
;flush_structs(~root)
;log_info("First pass DONE")
- ;CompData data = compile_file_pass_two(f, ~root)
+ ;CompData data = compile_file_pass_two(~tok, ~root)
;log_info("Second pass DONE")
;out = string_join({