A Blarb virtual machine
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
editors
examples
src
.editorconfig
.gitattributes
.gitignore
Makefile
README.org
lib.blarb
logo.jpg

README.org

./logo.jpg

BlarbVM

Blarb is designed to be the simplest possible (esoteric) systems programming language. Being as such, there is only one logical operator: NAND. It is an assembly-like, stack & register based language.

Architecture

In Blarb, there is a stack, heap, and registers. On the stack, every element is a 64-bit integer. To increase the heap size, you must use the brk system call.

When you include a file with the ~@~ operator, the tokens in that file will be appended to the parse tree - thus, you should always exit the VM at the end of your programs by calling syscall 60 via 0 0 0 0 0 0 60 %, or call 0 exit if you are using the standard library.

Registers

There are 8 registers, numbered 0-7. The 0th register is the line pointer - that is, the line that is currently being evaluated. Registers 1-3 are short term registers, that may change when you call a function or jump to a label. Registers 4-7 are guaranteed to never be used in lib.blarb (which I’ll explain later), so you can use them for long term storage in your userspace programs.

Setting the line pointer register to a number less than -1 will terminate the VM. Alternatively, see the exit function in the standard library.

Register #Description
0Line Pointer
1-3Temporary Registers
4-7User Registers

Literals

There are only two types of type literals in blarb:

Integers

64-bit singed integers - can be negative.

Strings

In Blarb, a string is simply a null-terminated sequence of numbers on the stack. Typing a string literal in will translate into a null-terminated sequence, for sanity. To escape a quotation, use \"~. To escape backslashes, use ~\\. Newlines and tabs are escaped with \n and \t, as usual.

Characters

Characters are parsed like strings, but get turned into integer types when parsed. Thus, like most other language, a character can only contain a single byte (the character escapes still work).

Operations

There are currently 8 single-letter operations. Additionally, you can type a single number to push that number onto the stack (64-bit signed integer). Space between operators and integers or function calls is optional.

NAND

b a ! NANDS index a with index b and stores the result in index b

Store Register

a b \~ Store the value at index a in register b

Get Register

a$ Push register a onto the stack

Pop from Stack

a^ pop a elements

Conditional

a? if index a is true (non-zero), execute the rest of the line

Include File

~”filename.blarb”@~ Include the given file. Duplicates will be ignored.

System Calls

f e d c b a syscallnum % Execute the system call with the given args

Upon syscall error (returning -1), the Blarb VM will terminate. This may change in the future.

Set Memory Address

a b = Swap the value at memory address at index b to the byte (8 bits) at index a of the stack

The value at stack index b should contain a valid memory address (see examples in lib.blarb, for now..)

Labels

Labels are created by a hash:

#labelname

and called by simply writing their name.

When jumping to a label, the line that the label is on will be executed, ignoring “#labelname”.

No tokens are allowed after a jump to a label, and you will get a parse error if you do so. Thus, a label call must be the last statement on a given line, if present.

Functions

Blarb functions are a loosely defined construct, like in assembly, they are just labels. Thus, you must push the line register to the stack using 0$ (e.g. 0$andi).

Example:

; Pushes the current line to the stack
; The stack will now contain 2, 3, and the current line number
; No token are allowed after a call to a label
2 3 0$andi

0 0 0 0 0 0 60 % ; exit by calling syscall 60

; Bitwise AND the two arguments and push the result to the stack
#andi
    4 3 ! ; A NAND B (the two arguments)
    4 4 ! ; NAND the result with itself to bitwise NOT it

    ; Pop the stack frame and second argument.
    ; The remaining stack data will only include the return value
    ; The "2 0 ~" sets the line pointer to the return address
    ; The "2 ^" pops the return address and the second argument
    2 0 ~ 2 ^

; Run this program with "--debug" to see the result on the stack

Control Statements

Control structures are nothing special in Blarb either - they can be created via labels.

Loop example:

; This program will pop all the numbers on the stack until it hits a 0

; Pushes a bunch of numbers onto the stack
32 52 42 0 1 52 35203 3502462

#loop
    1? 1^ loop

; Pop the NULL for good measure
1^

Args

Args are pushed to the beginning of the VM stack, as “backward strings”, like string literals. The arg count (argc, if you will), is always pushed onto the stack afterwards. Even when there are 0 args.

Standard Library

Note: Without the standard library, it will be extremely difficult to do anything - so you will probably want to include lib.blarb in all your programs.

The standard library includes tons of useful functions - everything from bitwise operations to functions that will print string literals for you!

Recall: Functions are called with <args> 0$functionname.

As of writing this document, the standard library includes:

FunctionArgsDescription
nandiA BBitwise NANDs the two top items on the stack.
andiA BBitwise ANDs the two top items on the stack.
notiABitwise NOTs the top item on the stack.
oriA BBitwise ORs the top two items on the stack.
xoriA BBitwise XORs the top two items on the stack.
lshiftiloneABit shifts the top item left by one bit.
lshiftilA BShift A left by B bits.
rshiftiloneABit shifts the top item right by one bit.
rshiftilA BShift A right by B bits.
addiA BAdds the top two elements on the stack.
subiA BSubtracts B from A (A - B).
multiplyiA BMultiplies the top two elements on the stack.
setiV ISet’s the word on the stack at
index I to value V.
copyICopy the element at stack index I.
swapA BSwap the element at indices A and B.
iseqiA BChecks if A is equal to B.
Returns 1 if true, 0 if false.
isgeiA BChecks if A >= B.
tobooliAReturns A as a boolean (1 or 0).
pushbytetoheapiAPushes a BYTE to the heap.
Returns the address of the byte.
pushbytearraytoheapI LCopy array of length L at index I to the heap.
Returns the initial array index breakpoint.
stackstrlenAPush the length of the string at
stack position A to the stack.
printA BPrints the string at index A of length B.
printlineSPrints a null terminated string S, with a
newline character.
readcharDReads a single character from descriptor D.
brkiBSets the new brk address to B. If B is 0,
the current brk will be returned.
pushstringtoheapIPushes the string at index I to the heap.
Retruns the memory address of the string.
openwithnameS F MOpens the file of the null terminated string S.
F are the open syscall flags, M is the mode.
See the open syscall docs for more information.
Returns the file descriptor number.
closedescriptorACloses file descriptor A
exitCTerminates your program with status code C

Syntax Highlighting

See the editors directory for some syntax highlighting plugins. Currently there are only Vim and Emacs plugins.

Examples

See the examples directory for worked examples. Call them from same directory that has lib.blarb. If you freshly cloned this project, this means running ./blarb --debug example/function.blarb, for instance.