High-Level Brainfuck (HBLF) uses a C-like syntax, with curly braces ({}
) to indicate scope, and statement declarations terminated with a mandatory semicolon (;
). Parentheses (()
) are used for grouping. HLBF intends to minimize boilerplate (but uses semicolons because I'm too lazy to write a JavaScript-style ASI), so an empty file is valid code and can be compiled and executed. HLBF files use the .hlb
or .hlbf
file extension.
If you learn languages by examples, example HLBF code is available in this document, and example files can be found here.
Variables are declared with a primitive datatype keyword, followed by the variable name. Assignment is the variable name, followed by an equal sign (=
) and a value. Variables are statically typed, meaning the value of the variable must correspond to the datatype of the variable. The datatypes currently in HLBF are:
int
: 32-bit signed integerbool
: booleanstr
: variable-length string that can hold all valid ASCII characters
Variable initialization and assignment can be combined to one line, using the syntax <datatype> <name> = <value>;
. Initialized yet unassigned variables are technically not empty, but hold garbage data from previous executions or variables that went out of scope. However, the compiler will stop you from accessing variables until they are assigned, to prevent bugs.
Variables are mutable by default. You can declare a immutable constant by including the const
keyword before your variable intialization. Constants must be assigned on the same line as the initialization, or the compiler will throw an error. Attempting to reassign a constant will cause the compiler to throw an error.
int n;
n = 5;
int m = n;
bool x = false;
const bool y = true;
str hi = "Hello world!";
hi = "Hello, doc reader!";
If-statements are initialized with the if
keyword, followed by a set of parentheses. Inside the parentheses, add a boolean, boolean-containing variable, or conditional statement. The conditional operators currently in HLBF are:
==
- equality>
- greater than<
- less than||
- or&&
- and!=
- not equal>=
- greater than or equal to<=
- less than or equal to
A conditional statement is any statement with a value, conditional operator, and another value. Values can be variables as well as complex values made up of arithmetic. Conditionals evalute to booleans, so a variable set to a conditional either holds true
or false
, not the actual conditional.
The not operator (!
) reverses the value of any boolean it's put in front of, i.e. !true
is false
and !false
is true
. The not operator can be used in front of variables as well as conditionals, but the conditionals must be wrapped in a set of parentheses (ex: !(1 > 5)
evaluates to true
).
import stdio;
if (1 < 5) {
stdio.print("Less than!");
}
# Prints 'Less than!'
import stdio;
const int x = 5;
if (x + 1 > 5) {
print("Math!");
}
# Prints 'Math!'
import stdio;
bool x = !(5 > 6);
bool y = 99 < 0;
if (x && !y) {
print("Not operator!");
}
# Prints 'Not operator!'
Loops are declared with the while
keyword, followed by a set of parentheses and a conditional, and then a set of curly braces. While the conditional evalutes to true, the code inside of the curly braces executes. Loops are thread blocking, meaning that the execution of the program will be halted until the loop finishes. Infinite loops, therefore, will crash the compiler.
There are no for
loops in HLBF.
int i = 0;
while (i < 10) {
print(i);
}
# Prints 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
bool done = false
while (!done) {
user = input();
if (user == "exit") {
done = true;
}
}
Functions are declared with the function
keyword, followed by the name of the function and two parentheses. Functions have static return types, indicated by an ->
operator and the name of a datatype after the parentheses. To return nothing, omit the datatype, but keep the arrow operator. To declare parameters, put the datatype and name of the parameter inside the parentheses, and separate each parameter with a comma. Finally, write an opening and closing curly brace. Any code written inside of the curly braces will be executed when the function is called.
Functions are called by writing the name of the function, followed by a set of parentheses with the required arguments, separated by commas. Functions must be defined before they can be called.
By default, all variables declared outside of a function are global. Global variables can be accessed inside of a function. Variables declared inside of a function are local, and cannot be accessed outside of that function. The memory that local variables use is freed up when the execution of the function ends.
import stdio;
function main() -> {
print("Hello world!");
}
main();
# Prints 'Hello world!'
function add(int a, int b) -> int {
return a + b;
}
three = add(1, 2);
import stdio;
function greeting(str name) -> str {
str greet = "Hello, ";
return greet + name;
}
print(greeting("world"));
# Prints 'Hello, world'
HLBF provides a few built-in functions:
len(str s) -> int
- returns the length of the string passed as the arguments
.bf()
- allows you to write pure Brainfuck code inside the paratheses, using up to 25 cells of Brainfuck memory. Trying to move the pointer past the 25th cell will result in the pointer wrapping around to the first cell.str(int n) -> str
- convertsn
to a string.int(str s) -> int
- attempts to convert strings
to an integer. Ifs
contains non-numeric characters, the compiler will throw an error.
Packages are a collection of user-written functions that can be imported and used in your code. Package source-code files are written in HLBF, and must have the @package
decorator at the top of the file.
To use a package, create a packages
folder in the same directory as your main HLBF file, and put the package source-code into that folder. In your main, file write import
followed by the name of the package file, with the file extension omitted. This imports all the functions declared in the package file. Variables can be used in writing packages, but cannot be imported. To import multiple packages on one line, write the names of all the packages you want to import, separated by commas. To import all the packages in the packages
folder, write import *
.
To use functions from a package in your source code, write the name of the package, .
, and the name of the function.
By default, there are two packages globally installed: stdio
and math
. These two packages can be used by other packages, but non-globally installed packages cannot be used. As of now, extra packages cannot be globally installed.
The stdio
package (short for "standard input/output") is the package to use user input in your program or output values. The package provides the following functions:
input() -> str
- accepts user input and returns itprint(str s)
- prints the parameters
to the console
Unlike all other packages, stdio
does not require you to write stdio.
before calling a function from the package. This is because as of right now, the stdio package cheats in how it works. HLBF variables actually exist in Brainfuck memory, rather than solely existing in the compiler's memory, and everything to do with variables, such as copying one variable to another, uses this memory actually stored in Brainfuck. However, when printing a variable with stdio, the compiler pre-computes the value that needs to be outputted, rather than using the Brainfuck variable memory.
The math
package provides the following useful math-related functions:
abs(int n) -> int
- returns the absolute value ofn
square(int n) -> int
- returns the square ofn
pow(int n, int p) -> int
- returnsn
raised to thep
powerexp(int p) -> int
- returns 10 raised to thep
powerfactorial(int n) -> int
- returnsn!
,n ≥ 0
sin(int n) -> int
- returns the sine ofn
cos(int n) -> int
- returns the cosine ofn
tan(int n) -> int
- returns the tanget ofn
arcsin(int n) -> int
- returns the inverse sine ofn
,0 < n < 1
arcos(int n) -> int
- returns the inverse cosine ofn
,0 < n < 1
arctan(int n) -> int
- returns the inverse tangent ofn
,0 < n < 1
The source code for the math package can be found here.
Excerpt from the math package:
@package
function square(int n) -> int {
return n * n;
}
Usage in an HLBF project:
import stdio, math;
int x = 2;
print(math.square(x));
# Prints 4