Stapel is a minimalist, stack-based, concatenative programming language that compiles directly to x86-64 assembly (NASM) for Linux. It provides low-level control over memory and the stack while offering high-level abstractions like procedures, loops, inline macros, and string literals.
Non-ordered todo list:
- Local memory in procedures
- Type and stack checker (web assembly style)
- Importing stapel files
- Pushing
procaddresses to stack, and calling pointers from stacks- Putting
$(E.G.$println)in front of procedure identifier pushes pointer to stack execkeywords calls function from pointer on top of stack
- Putting
- Change procedure label name in generated assembly to some unique identifier
- Assembly does not allow special charactars in label names; Stapel does
- Rust (for compiling the compiler)
- NASM (for assembling the output)
- ld (GNU Linker)
- Build the compiler:
cargo build --release - Compile a Stapel program:
./target/release/stapel build /hello.spl - Run the executable:
./hello
Stapel is a stack machine. All operations consume arguments from the top of the stack and push results back.
- Integers: 64-bit signed integers (
i64). - Strings: Pushed as
[length, address]pairs.
| Literal | Example | Description |
|---|---|---|
| Integer | 123, -45 |
Pushes a 64-bit signed integer. |
| String | "Hello" |
Pushes Length then Address (2 items). |
| Character | 'A', '\n' |
Pushes the ASCII integer value (e.g., 'A' -> 65). |
| Keyword | Effect ( Before -- After ) |
Description |
|---|---|---|
dup |
( a -- a a ) |
Duplicates the top item. |
swap |
( a b -- b a ) |
Swaps the top two items. |
drop |
( a -- ) |
Discards the top item. |
over |
( a b -- a b a ) |
Copies the second item to the top. |
rot |
( a b c -- b c a ) |
Rotates the third item to the top. |
pick |
( a b c 2 -- a b c a ) |
copies nth item of stack to top. |
Arithmetic operators consume operands from the stack and push the result.
| Operator | Description |
|---|---|
+, -, *, /, % |
Standard integer math. |
++ |
Increment top of stack (Prefix operator). |
=, !=, <, >, <=, >= |
Comparison. Pushes 1 (true) or 0 (false). |
In Stack languages, the operator appears after the numbers.
Code:
3 10 /Step-by-Step State:
3is pushed. Stack:[ 3 ]10is pushed. Stack:[ 3, 10 ](Top is 10)%runs. It pops 10, then pops 3.- It calculates .
- It pushes 1. Stack:
[ 1 ]
Stapel allows manual memory allocation and access. Note that @ is used for Store and ! is used for Load, which reverses the convention seen in some other stack languages.
Allocation:
memory buffer 1024 end # Reserves 1024 bytes in the .bss sectionAccess:
| Op | Usage | Description |
|---|---|---|
@ |
addr val @size |
Store. Writes val into memory at addr. |
! |
addr !size |
Load. Reads a value from memory at addr. |
- Sizes:
1(byte),2(word),4(dword),8(qword).
Example:
memory buf 64 end
# Storing a character
buf 'A' @1 # Store 'A' (65) at the start of 'buf'
# Loading it back
buf !1 # Push buf address, Load 1 byte. Stack: [ 65 ]Conditionals:
<condition> if
"True" print
else
"False" print
end
Loops:
0 while <condition> do
dup put # Print current number
1 + # Increment
endThe condition of the loop can contain a lot more than just the condition. However, once the program is a the
dokeyword what is at the to counts as the conditional value
proc: Defines a reusable subroutine.inline: Defines a block of code injected directly where called (macros).
proc square do
dup *
end
inline INC 1 + end # Replaced at compile time
proc main do
5 square put # Output: 25
10 INC put # Output: 11
endDirect Linux syscalls are supported via syscall<N> where N is the argument count (0-6).
Arguments are popped from the stack in reverse order (rdi, rsi, rdx, r10, r8, r9).
# Example: write(stdout, "Hi", 2)
# Syscall ID for write is 1
proc print do
1 1 syscall4 # Pops: ID (1), FD (1), Buffer, Length
endResults (normally in RAX) of syscall is pushed to stack
main.rs: CLI entry point and build pipeline.compiler.rs: Generates x86-64 NASM assembly. Handles string constants and BSS layout.lexer.rs: Tokenizes inputparser.rs: Recursive descent parser that constructs the AST (Procedures, Loops, Ifs, Memory definitions).program.rs: Handles AST optimization and inlining passes.tokens.rs: Defines Token types and Span (source location) for error reporting.