Stack-based compiled language made in Rust. This project is made for me to learn Rust coming from C++.
Uses only core cargo crates to my knowledge.
How to build and use:
1. Build the Ktnack compiler using cargo:
cargo build
2. Compile your program (using code.ktnck
as example).
target\debug\ktanck.exe code.ktnck
You can also use the build.bat
file by typing build.bat code.ktnck
.
3. Run your compiled program.
code.exe
Ktnack offers a wide variety of keywords and features, here you'll find the general idea of what you can do with the language.
This prints the value 12
onto the terminal:
12 .
Here we first push 12
onto the stack.
Then we use .
which pops 1 i64 off the stack and prints it.
These few examples show how to add, subtract, multiply, divide and modulo
7 5 +
7 5 -
7 5 *
7 5 /
7 5 %
Add .
operator at the end of each line to print the results.
Taking for example 7 5 -
, this is equivalent to 7 - 5
,
it pops 7 and 5 off the stack, subtract 5 from 7, then pushes 2
back onto stack.
The logical operators include <
, >
, <=
>=
, =
and !=
.
Each one pops two values off the stack, and compares the top most item
as the right hand side with the second from top item as the left,
then pushes 1
if it's true, or 0
if it's false.
Here's an example:
5 7 < .
5 7 > .
The output of this would be:
1
0
If statements pop one value off the stack, and if the value
is 0 it jumps past else
if it has one, otherwise to end
.
If it's any other value, it runs its own block, and once it
reaches else
it jumps to end
.
Here's some dummy code:
1 if
1 .
else
2 .
end
The output of this would be 1
.
Take this code:
0 if
1 .
end
This wouldn't have any output, as the value was 0
, thus it jumped past end
.
As you might have guessed, this works with logical operators:
5 7 < if
5
else
7
end
As you can see this roughly translates to a min
ternary in other languages,
which would look like 5 < 4 ? 5 : 4
.
These are 4 operators which manipulate the stack directly.
dup
will pop one value off the stack and push it back twice.
5 7 dup . . .
This will output
7 7 5
over
takes the second value on the stack and copies it to the top.
5 7 over . . .
This will output
5 7 5
swap
takes the top two values on the stack and switch their places.
5 7 swap . .
This will output
5 7
drop
will pop the top value off the stack and discard it.
Basically cleans up no longer needed values off the stack.
You will see this a lot with loops.
5 7 drop .
This will output
5
While loops start with while
, followed by the code which acts as the condition point.
Being stack based, there's no limit on the size to this. This section ends with do
which is where the loop's body is. The loop itself ends with end
, which will
jump back to while
, where the condition is checked.
The condition exactly like if
, where if the value is 0
it jumps past end
,
otherwise it runs the loop's body.
Here's an example of a loop iterating from 0 to 9
0 while dup 10 < do
dup .
1 +
end
drop
This first sets the starting point to 0
.
Now we make the condition is the value less than 10
.
Since we consume the values with any operation, we need to clone it,
which is where dup
comes in. Then inside the loop, we once again
clone the value in order to print it. Then we add 1 to the value.
Lastly after the loop we use drop
as we won't need the value anymore.
Without the use of drop
the stack would be misaligned, so we drop it.
You also got access to a buffer of 640,000 bytes.
This is accessed using two functions, S
for save and L
for load.
These allow you to save single bytes at various locations.
You get the buffer address using @
, and to get an exact address
of for example 5
you'd do @ 5 +
.
Save takes value address S
.
12 @ 6 + S
This saves the value 12
at index 6
in the buffer.
Load takes address L
.
@ 3 + L
This loads from index 3
in the buffer onto the stack.
Accessing the memory allows you to push utf-8 values onto the memory,
which you can then print using P
or p
.
P
places a new line at the end of the string, while
p
prints without a new line.
Printing takes address count P
.
65 @ 0 + S
66 @ 1 + S
67 @ 2 + S
@ 0 + 3 P
This prints ABC
with a new line.
String literals are strings defined in the source code using quotes.
Using string literals pushes its address and character count onto the stack,
in a way where it's ready to print.
String literals are located at its own piece of the executable just like with
other compiled languages, and should thus not be written to.
You can define and print a string literal like this:
"Hello, World!" P
Woo finally hello world!
This prints what you'd expect.