We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.

VoidPtr

From Esolang
Jump to navigation Jump to search
VoidPtr
Paradigm(s) imperative
Designed by User:Basilisk
Appeared in 2026
Memory system Cell-based
Computational class Unknown
Major implementations Original
Influenced by brainfuck
File extension(s) .vptr

VoidPtr (pronounced void pointer) operates on single byte sized cells using only moves and bit-wise logical operations.

The name was inspired by the C data type 'void*' hinting at the language's lack of data differentiation.

Overview

This overview is written based on the VoidPtr specification v.1.2.0.

Comments

Comments are enclosed in semicolons.

 ;This is a comment;

Operations

Operations are performed on individual bytes in memory.

Bytes are addressed as decimal numbers and can be addressed in an infinite range depending on allocated memory.

Operation Description
a -> b Move value at a into byte b.
a & b -> c Apply bit-wise AND and move result to c.
a | b -> c Apply bit-wise OR and move result to c.
a ^ b -> c Apply bit-wise XOR and move result to c.
a < b -> c Apply bit shift left of b to a and move result to c.
a > b -> c Apply bit shift right of b to a and move result to c.
! a -> b Apply bit-wise not on a and move result to c.
? a Compares a to 0 and skips the next instruction if the value at the specified address is not zero.
'label_name Redirects execution to specified label.

Note: double input operations (e.g. and, or) expect a and c to always be an address

Addressing modes

VoidPtr allows constants, direct addressing and indirect addressing.

3 -> 4 ;Direct - Direct. Moves value from address 3 into address 4;
[3] -> 4 ;Indirect - Direct. Moves value from address stored in 3 to address 4;
$65 -> 4 ;Constant - Direct. Writes value 65 to address 4;

Note: Allowed address modes depend on the instruction type. Single input instructions allow constants as first input, double input instructions allow only the second operand to be a constant. All instructions allow indirect and direct addressing at every operand.

Constants

Constant values are denoted by '$' and can range from 0-255.

Strings

Characters and strings enclosed in " are compiled to their ascii representations.

"A" -> 2

Compiles to:

$65 -> 2

Multiple characters:

"ABC"

Compiles to:

$65 $66 $67

Labels

Labels mark program addresses and are used for control flow.

A label is defined by an underscore followed by its name.

_label_name
_another_label

Macros

Macros allow the user to interact with the compiler and ask for text substitution.

All macros start with the '#' character.

def

The 'def' macro is similar to the '#define' macro in C. It allows the user to name code segments and tell the compiler to instantiate them later. Structure of def: #def,macro_name,contents,#end

#def reg5 5 #end
#def print2 
   $2 -> 1
   $1 -> 0
#end

Instantiating a defined name works by writing it at the selected location.

$65 -> 2
print2 ;pastes contents of print2 at this location;

Define macros can be used inside of each other if the used macro is defined before its usage.

#def print2_3
   print2 ;print2 will be instantiated at macro resolution;
   $3 -> 1
   $1 -> 0
#end

Note: Code inside define blocks does not get executed on its own.

stream

The stream macro is a shortcut to writing many values contiguously.

Structure of stream: #stream,direct_start_address,values,#end

#stream 20 $65 $66 $67 #end

Compiles to:

$65 -> 20
$66 -> 21
$67 -> 22

paste

Pastes the contents of a specified file at the macro location (similar to #include in C).

Structure of paste: #paste,file_path

#paste directory/filename.vptr


Note: the file path is provided as raw text

System Calls

System calls are used to communicate with the interpreter or runtime. Addresses 0 and 1 are special addresses used to issue system calls.

Writing a value into 0 automatically triggers a system call. 0 is reset to $0 after every call.

Some system calls expect address 1 to hold arguments or a pointer to arguments for the system call.

Note: System calls and their exact functionality depend highly on the capabilities of the implementation and supported specification version.

Exact system calls are not part of the core language features.


System calls for spec v.1.2.0

n is the byte referenced by address 1

Call number Description
$1 Print byte n as a number.
$2 Print byte n as a character.
$3 Read one character from stdin into byte n.
$4 Allocate n additional bytes.
$5 Deallocate n bytes.
$6 Read a 32-bit address from bytes n through n+3 and load its value into address 1.
$7 Store the value at n into the 32-bit address stored in the next four bytes.
$8 Store the current program counter into four bytes beginning at n.
$9 Read four bytes at n as a 32-bit integer and set the program counter.
$10 Load a file into memory starting at n

Examples

8 bit addition:

#def result 4 #end
#def carry  5 #end
#def byte_a 2 #end
#def byte_b 3 #end

$3 -> byte_a
$1 -> byte_b

_add_loop
? byte_b '_end 

byte_a & byte_b -> carry
byte_a ^ byte_b -> result

carry < $1 -> byte_b

result -> byte_a

'_add_loop

_end
$result -> 1 
$1 -> 0

Hello World:

#stream 10 "Hello World!" $10 $0 #end

#def counter 3 #end
#def data    4 #end
#def bit     5 #end
#def tmp     6 #end

$10 -> counter
_loop
    [counter] -> data

    $ data -> 1
    $2 -> 0

    $1 -> bit
    _add
        counter & bit -> tmp
        counter ^ bit -> counter
        tmp < $1      -> bit
    ? bit '_done
    '_add
    _done

    ? data '_exit
    '_loop
_exit

brainfuck interpreter running a hello world program:

Note: This interpreter is not Turing complete for simplicity. It has a limited program, loop and address space.

;
This is a Brainfuck implementation written in Voidptr.
This version only uses the first 255 bytes for simplicity, 
make sure not to load any programms which exceed programm space.
;

;input program;
#stream 28 "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." $0 #end

;general purpose registers;
#def r0 2 #end
#def r1 3 #end
#def r2 4 #end
#def r3 5 #end
#def r4 6 #end
#def r5 7 #end

;add registers;
#def a0 10 #end
#def a1 11 #end
#def a2 12 #end

;sub register;
#def s0 13 #end

;register mem space end;
#def le 20 #end

;system call;
#def syscall -> 0  #end
#def printNum $1 #end
#def printChar $2 #end
#def getChar $3 #end


;8 bit add;
#def add8

;load args;
r0 -> a0
r1 -> a1

__add_loop
? a1 '__end ;check if carry is 0;

a0 & a1 -> a2
a0 ^ a1 -> a0

a2 < $1 -> a1

'__add_loop

__end
a0 -> r0

#end

;8 bit subtract;
#def sub8 
    ! r1 -> r1
    r0 -> s0
    $1 -> r0
    add8

    r0 -> r1
    s0 -> r0
    add8
#end


#def pointer r3 #end ;byte holding the bf pointer;
#def pc r4 #end
#def stack_ptr r5 #end

;mem layout: 28 - 160 code, 161 - 170 loop stack, 171 - 255 bf memory; 

$171 -> pointer 
$161 -> stack_ptr
$27 -> pc


#def reset_r1 $1 -> r1 #end 
reset_r1


'_main

; ----- OP Labels ----- ;
;> op;
_inc_ptr 
    pointer -> r0
    reset_r1
    add8
    r0 -> pointer

    '_main

;< op;
_dec_ptr 

    pointer -> r0
    reset_r1
    sub8
    r0 -> pointer

    '_main

;+ op;
_plus 

    [pointer] -> r0
    reset_r1
    add8
    r0 -> [pointer]

    '_main

;- op;
_minus
    [pointer] -> r0
    reset_r1
    sub8
    r0 -> [pointer]

    '_main

;. op;
_out 

    pointer -> 1
    printChar syscall 

    '_main


;, op;
_in 

    pointer -> 1
    getChar syscall 

    '_main

;[  op;
_start_loop
    ? [pointer] '__skip_loop

    ;enter loop;
    stack_ptr -> r0
    reset_r1
    add8
    r0 -> stack_ptr
    pc -> [stack_ptr] ;push current pc to loop stack;
    '_main

    ;skip loop, (skip to next ]);
    
    __skip_loop
        ;increase pc;
        pc -> r0
        reset_r1
        add8
        r0 -> pc

        ? [pc] '_end ;end if we reach 0;

        [pc] -> r0
        "]" -> r1
        sub8
        ? r0 '_main
        '__skip_loop
    

;] op;
_end_loop

    ? [pointer] '__pop_loop ;check if current is 0;

    [stack_ptr] -> pc

    '_main

    __pop_loop
    stack_ptr -> r0
    reset_r1
    sub8
    r0 -> stack_ptr
    '_main


__loop_back

'_main

; ----- Main Loop ----- ;

_main

;increase pc;
pc -> r0
reset_r1
add8
r0 -> pc


;print vlaue at r4 ptr (current BF character)
pc -> 1
printChar syscall 
;

[pc] -> r0
">" -> r1 
sub8
? r0 '_inc_ptr

[pc] -> r0
"<" -> r1 
sub8
? r0 '_dec_ptr

[pc] -> r0
"+" -> r1
sub8
? r0 '_plus

[pc] -> r0
"-" -> r1
sub8
? r0 '_minus

[pc] -> r0
"." -> r1
sub8
? r0 '_out

[pc] -> r0
"," -> r1
sub8
? r0 '_in

[pc] -> r0
"[" -> r1
sub8
? r0 '_start_loop

[pc] -> r0
"]" -> r1
sub8
? r0 '_end_loop

? [pc] '_end


_end