This document specifies the keywords and syntax of brainlite.
Any line that begins with a hashtag (#) is a comment. The compiler ignores the whole line.
You cannot write multi-line comments. To do so, use multiple lines that start with hashtag.
NOTE: The line must begin with hashtag. If it is encountered in between the code, it will be marked as an invalid token and an error will be printed.
A cool feature but one that is not recommended is the skip errors feature.
Usually, if any invalid token is encountered within the code then the compiler will print an error message, stop the compilation and exit.
However, if a line ends with question mark (?), then the compiler will ignore errors and continue to compile regardless.
I don’t remember why I made this feature but it exists, and I don’t think its a good feature to use.
# Ignore errors in this line:
set 15 not_a_token?
A string that is followed by a space, semi-colon or a newline will be considered a ‘token’. Each token should either be an argument to a keyword or a keyword itself.
Writing multiple keywords in a single line is supported but not recommended.
All arguments to keywords but adhere to the same syntax. So, a good rule is to extensively use spaces after every keyword, argument and string.
All keywords must be in lowercase.
The keyword set is used to set a value into current memory address. Brainlite doesn’t provide a single instruction to set a specific value into a memory address.
Syntax: set <value>
The value must be numerical and within zero and 255, Otherwise it will be decremented until it fits the limit.
set 15;
set 22
set 32 set 15; set 92
Set doesn’t increase the value of memory pointer. Be careful not to overwrite the same memory address.
Dev Note: I could have used a modulo operator for doing this, I don’t know what I was thinking lol. For reference, look at source code of ringBuffer function in utils.cpp.
The keyword front is used to move the memory pointer by one unit.
Syntax: front
Memory layout: [—,—,—,…] ^^^ Memory pointer
set 15
front
set 30
Memory layout: [15,30,—,…] ^^^ Memory pointer
The keyword back is used to move the memory pointer back by one unit.
Syntax: back
Memory layout: [15,—,—,…] ^^^ Memory pointer
set 15
back
set 30
Memory layout: [30,15,—,…] ^^^ Memory pointer
The keyword inc is used to increase the value pointed by the current memory pointer by one unit.
Syntax: inc
Memory layout: [15,—,—,…] ^^^ Memory pointer
inc
Memory layout: [16,—,—,…] ^^^ Memory pointer
The keyword dec is used to decrease the value pointed by the current memory pointer by one unit.
Syntax: dec
Memory layout: [15,—,—,…] ^^^ Memory pointer
dec
Memory layout: [14,—,—,…] ^^^ Memory pointer
The keyword inctill is used to continuously increase the value pointed by the current memory pointer until it hits a certain value.
Syntax: inctill <limit>
Limit must be a numerical value within zero to 255. Otherwise it will be decremented until it fits the limit
Memory layout: [15,—,—,…] ^^^ Memory pointer
inctill 32
Memory layout: [32,—,—,…] ^^^ Memory pointer
The keyword decctill is used to continuously decrease the value pointed by the current memory pointer until it hits a certain value.
Syntax: dectill <limit>
Limit must be a numerical value within zero to 255. Otherwise it will be decremented until it fits the limit
Memory layout: [15,—,—,…] ^^^ Memory pointer
dectill 10
Memory layout: [10,—,—,…] ^^^ Memory pointer
The keyword move is used to move the memory pointer by N units specified.
Syntax: move <limit>
Limit must be a integer value within -37999 to 37999. The value can exceed depending on where the final executable is being run on. However, if using the interpreter bundled with brainlite, the hard-limit enforced by interpreter is 37999.
The keyword print is used to display content onto the screen.
Syntax: print "Your statement goes here"
Do note that the quotation marks are necessary and single-quotes do not work. The compiler will print an error if violated.
print "Hello World"
The keyword input is used to collect input from users.
Syntax: input N
N must be a positive numerical value that specifies the number of letters of input to collect from users.
The keyword loop is used to loop through a set of instructions/statements. Loop keyword requires a numerical value to specify the number of times to loop.
It must follow with an end keyword.
Syntax:
loop <times>
# Statements
end
The value of times must be a positive integer value specifying the amount of times the loop should run. It cannot be a conditional statement.
Take a simple example of increasing the value held by current memory address to 100
Memory layout: [?,—,—,…] ^^^ Memory pointer
set 0
loop 100
inc
end
After set 0: Memory layout: [10,—,—,…] ^^^ Memory pointer
After 10 iterations: Memory layout: [10,—,—,…] ^^^ Memory pointer
After loop ends:
Memory layout: [100,—,—,…] ^^^ Memory pointer
The compiler doesn’t optimize for loop unfolding or removing loops if they are redundant. While a GCD approach is smarter, the code generated by compiler is rather simple and straight-forward.
The keyword whatis is used to print the value of any internal compiler variable. This can be helpful for debugging.
This keyword currently only supports printing the address that memory pointer currently points to.
Syntax: whatis "query"
Currently, the value of query can only be memorypointer verbatim. The value of query is converted to lowercase automatically and any invalid values are ignored.
Memory layout: [10,—,—,…] ^^^ Memory pointer
whatis "memorypointer"
Stdout: 0
Bug: As I am writing this document, I just realized that the print token used by brainfuck converts the numerical value to ASCII. This will cause issues.
The keyword out will print the value held by current memory address converted to ASCII (done by brainfuck).
Syntax: out
That concludes the syntax of this language.
The compiler has many flaws, some obvious, some by design and some by my naive assumptions. If its ever needed that I must maintain this compiler, raise an issue and I shall do so.