Backstack is a stack-based programming language with a simple, readable syntax inspired by Forth. This document provides a comprehensive guide to programming in Backstack, with explanations and examples for all major language features.
To run a Backstack program, use the sim (simulate) command:
python src/python/main.py sim your_program.bs
You can compile a Backstack program to a native executable using the com (compile) command:
python src/python/main.py com your_program.bs
This will:
- Parse your Backstack program
- Generate x86-64 assembly code
- Assemble the code using NASM
- Link the object file using GCC
- Create an executable (
outputon Linux/macOS oroutput.exeon Windows)
You can then run the executable directly:
./output # On Linux/macOS
output.exe # On Windows
Here's a simple "Hello World" program in Backstack:
"Hello, World!" # Push string to stack
dump # Print top value from stack
Backstack is a stack-based language, meaning operations work on values stored on a stack.
- Values are pushed onto the stack by writing them directly
- Operations generally pop values from the stack, perform calculations, and push results back
Example:
5 # Push 5 onto stack
3 # Push 3 onto stack
+ # Pop 5 and 3, add them, push 8
dump # Print the result (8)
Key stack manipulation operations:
dup- Duplicate the top value on the stackswap- Swap the top two values on the stackdrop- Remove the top value from the stackover- Copy the second value on the stack to the toprot- Rotate the top three values on the stack
Example:
5 7 # Stack: 5 7
dup # Stack: 5 7 7 (duplicated top value)
swap # Stack: 5 7 7 → 5 7 7 → 7 5 7
drop # Stack: 7 5 (dropped top value)
dump # Prints: 5
Backstack supports standard arithmetic operations:
+- Addition-- Subtraction*- Multiplication/- Division%- Modulus**- Exponentiation
Example:
10 3 + # 13
20 5 - # 15
4 5 * # 20
20 4 / # 5
10 3 % # 1
2 8 ** # 256
Backstack provides robust string operations for working with text data.
Define strings using double quotes:
"Hello, Backstack!"
str_concat- Concatenate two stringsstr_length- Get the length of a stringstr_slice- Extract a substringstr_contains- Check if a string contains another stringstr_split- Split a string by a delimiterstr- Convert a value to a string
Examples:
# String concatenation
"Hello, " "world!" str_concat # "Hello, world!"
# String length
"Backstack" str_length # 9
# String slice (substring)
"Hello, world!" 7 12 str_slice # "world"
# String contains
"Hello, world!" "world" str_contains # 1 (true)
# Convert number to string
42 str # "42"
Backstack allows storing and retrieving values using named variables.
To store a value in a variable, use set:variable_name:
42 set:answer # Store 42 in variable "answer"
To retrieve a value from a variable, use get:variable_name:
get:answer # Push the value of "answer" (42) onto the stack
Example:
10 set:x # Store 10 in x
20 set:y # Store 20 in y
get:x get:y + # Add x and y (10 + 20)
dump # Print the result (30)
Backstack supports conditional branching with if/else/endif structure:
# Basic if statement
condition if
# Code executed if condition is true (non-zero)
endif
# If-else statement
condition if
# Code executed if condition is true
else
# Code executed if condition is false
endif
Example:
# Check if a number is positive
dup 0 > if
"Positive number" dump
else
"Zero or negative number" dump
endif
==- Equal!=- Not equal>- Greater than<- Less than<=- Less than or equal>=- Greater than or equal
Backstack provides two main loop structures:
while
# Loop code
# Leave condition on stack (0 = exit, non-zero = continue)
repeat
Example (counting from 1 to 5):
1 set:counter # Initialize counter
while
get:counter dup # Get counter value and duplicate it
dump # Print current counter
1 + set:counter # Increment counter
get:counter 5 <= # Check if counter <= 5
repeat # Loop back if true
end_value start_value for
# Loop code (current value is on stack)
next
Example (sum numbers 1 to 10):
0 set:sum # Initialize sum
10 1 for # Loop from 1 to 10
dup get:sum + # Add current number to sum
set:sum # Update sum
next
get:sum dump # Print final sum (55)
Define a function using fun:name and fun_end:
fun:function_name
# Function body
return
fun_end
Call a function using call:name:
call:function_name
Example (factorial function):
# Recursive factorial function
fun:factorial
dup 1 <= if
drop 1 return # Base case: return 1
else
dup 1 - call:factorial * return # Recursive case
endif
fun_end
5 call:factorial dump # Calculate and print 5! (120)
Backstack provides operations for creating and manipulating arrays.
Create a new array using array_new with the size:
5 array_new # Create array of size 5
array_set- Set a value at an indexarray_get- Get a value from an indexarray_len- Get the length of an array
Example:
5 array_new set:arr # Create array of size 5 and store reference
# Set values
get:arr 0 10 array_set # arr[0] = 10
get:arr 1 20 array_set # arr[1] = 20
get:arr 2 30 array_set # arr[2] = 30
# Get values
get:arr 1 array_get dump # Print arr[1] (20)
# Get array length
get:arr array_len dump # Print array length (5)
Backstack supports file operations for reading and writing data.
file_open- Open a file (returns a file handle)file_close- Close a filefile_read- Read entire file contentsfile_write- Write to a filefile_append- Append to a file
Example:
# Write to a file
"test.txt" "w" file_open set:file
get:file "Hello, file I/O!" file_write
get:file file_close
# Read from a file
"test.txt" "r" file_open set:file
get:file file_read dump # Print file contents
get:file file_close
Backstack supports various bitwise operations for low-level programming.
&- Bitwise AND|- Bitwise OR^- Bitwise XOR~- Bitwise NOT<<- Shift left>>- Shift right
Example:
# Bitwise AND: 12 & 7 = 4
12 7 & dump # Binary: 1100 & 0111 = 0100 (4)
# Bitwise OR: 12 | 7 = 15
12 7 | dump # Binary: 1100 | 0111 = 1111 (15)
# Bitwise XOR: 12 ^ 7 = 11
12 7 ^ dump # Binary: 1100 ^ 0111 = 1011 (11)
# Bitwise NOT: ~5 = -6
5 ~ dump # Binary (8-bit): ~00000101 = 11111010 (-6)
# Shift left: 5 << 2 = 20
5 2 << dump # Binary: 00101 << 2 = 10100 (20)
# Shift right: 20 >> 2 = 5
20 2 >> dump # Binary: 10100 >> 2 = 00101 (5)
Print a value using dump:
"Hello" dump # Print "Hello"
Get user input using input:
"Enter your name: " input # Shows prompt and gets input
# Recursive Fibonacci function
fun:fibonacci
dup 1 <= if
# Base case for n <= 1
return
else
# Recursive case: fib(n-1) + fib(n-2)
dup 1 - call:fibonacci
swap 2 - call:fibonacci
+ return
endif
fun_end
# Calculate fibonacci(10)
10 call:fibonacci dump # 55
# Initialize random seed
1234567 set:seed
# Function to generate a random number
fun:random
get:seed # Get current seed
1103515245 * 12345 + 2147483647 % # LCG algorithm
dup set:seed # Update seed
return
fun_end
# Function to get a random character from a string
fun:random_char
# Stack: string
dup str_length # Get string length
call:random swap % # Random index between 0 and length-1
# Stack: string index
swap 2dup # Stack: index string index
1 + str_slice # Get char at index
# Return the character
return
fun_end
# Generate password of given length
fun:generate_password
# Stack: length
set:length # Store desired password length
"" set:password # Initialize empty password
# Character sets
"abcdefghijklmnopqrstuvwxyz" set:lowercase
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" set:uppercase
"0123456789" set:numbers
"!@#$%^&*()-_=+[]{}|;:,.<>?" set:symbols
# Ensure at least one character from each set
get:lowercase call:random_char set:password
get:uppercase call:random_char get:password str_concat set:password
get:numbers call:random_char get:password str_concat set:password
get:symbols call:random_char get:password str_concat set:password
# Fill the rest of the password
get:length 4 - set:remaining # 4 characters already added
# Combine all character sets
get:lowercase get:uppercase str_concat
get:numbers str_concat get:symbols str_concat
set:all_chars
# Add remaining characters
0 set:i
while
get:all_chars call:random_char
get:password str_concat
set:password
get:i 1 + set:i
get:i get:remaining <
repeat
get:password return
fun_end
# Generate a 12-character password
12 call:generate_password dump
-
Stack Hygiene: Be mindful of what's on the stack. Clean up unused values with
drop. -
Comments: Use comments (
#) to document your code, especially for complex operations. -
Variable Naming: Use descriptive variable names for readability.
-
Function Structure: Design functions with clear inputs and outputs.
-
Error Handling: Check for error conditions, especially in file operations.
-
Stack Underflow: Trying to pop more values than are on the stack.
-
Type Confusion: Performing operations on values of the wrong type.
-
Infinite Loops: Not providing a proper exit condition in loops.
-
Forgetting Return: Not using
returnin functions, which can lead to unexpected stack behavior.
Backstack is a simple yet powerful language with a focus on clarity and expressiveness. While it follows stack-based principles, its readable syntax and comprehensive feature set make it accessible for various programming tasks.
For more examples, check the examples/ directory in the Backstack repository.