Embedded Brain Fuck (or EBF) is an extension of the Brain Fuck language to allow easier usage on embedded systems. EBF adds a number of extra commands that make writing and manipulating registers and various places in memory simpler. It also provides mechanisms for literal writes into memory.
EBF maps the data array from classic Brain Fuck to the entire system memory (this may be overridden via configuration options). This allows for architecture specific applications to access chip configuration registers.
EBF programs are compiled into portable C code instead of interpreted directly. This allows the user to then compile the application using whatever C compiler works for their system.
EBF follows the same model as original Brain Fuck, with a large, contiguous array of memory which may be accessed a single cell at a time. However, EBF adds several features which enable easier program and data flow on embedded systems. Most instructions allow for these modifiers:
See the Instructions section below for specifics on how each instruction works with these modifiers.
EBF uses a variable to keep track of the current working cell: DP. This pointer is incremented and decremented to access different cells and may be used to access or modify the value inside a cell. User defined functions may access this variable by including ebf.h.
A single configuration block may be inserted into each EBF application which modifies the generated code in particular ways. The configuration block must be contained within a #%(...) expression. It may be multi-lined, and must adhere to YAML formatting. All options are either key/value pairs or sequences. Below is a listing of all options and what they do:
This section describes all of the valid instructions available in EBF, including both the classic and extended commands. The extended commands are a superset of the original commands and thus a classic Brain Fuck program will still be compiled correctly.
Standard instructions are single character (unary) commands that typically operate using the current cell and/or data pointer. These are equivalent to classic Brain Fuck instructions.
Extended instructions are multi-character instructions that have a modifier character and take a number N as an operand. There are three different classes of extended commands: absolute address, relative address, and literal.
The general form of an extended instruction is: IMN, where I is the instruction character, M is the modifier character, and N is a number in either decimal (positive or negative), octal, or hexadecimal.
Absolute address instructions interpret the N parameter as an absolute address. That address is dereferenced and the value at that cell is used to perform the given instruction. For example, +*0xDEADBEEF reads the value at cell 0xDEADBEEF and adds that value to the current cell.
Below is a list of all of the absolute address instructions:
Relative address instructions interpret the N parameter as an offset from the current DP. That address is dereferenced and the value at that cell is used to perform the given instruction. For example, +:0x100 reads the value at cell DP + 256 and adds that value to the current cell.
Below is a list of all of the relative address instructions:
Literal instructions interpret N parameter as a literal value. Similarly to absolute and relative, that value is used to perform the given instruction. For example, +#0x1234 adds 0x1234 to the current cell.
Below is a list of all of the literal instructions:
Jump instructions allow the programmer to jump the instruction pointer to another location in the program. These instructions work the same as C labels and goto. Note, once a jump occurs there is no built-in concept of a return location, unless user defined functions are used.
Comments in the code may be made using two methods, a line comment or non-instruction characters. Non-instruction characters are ignored, therefore, any characters that are not interpreted as an instruction are considered a comment.
A line comment is used to mark the rest of a line as a comment, thus allowing instruction characters and syntax to be used in a comment. All characters on a line after a # (which isn’t part of an instruction) are considered part of a line comment and are ignored by the parser (unless it is a configuration block, which is treated specially).
These tables show the C equivalents of each instruction. DP is a pointer type to the current data cell.
These instructions are equivalent to classic Brain Fuck.
Instruction | Syntax | C Equivalent | Notes |
---|---|---|---|
> | > | DP++ | |
< | < | DP-- | |
+ | + | (*DP)++ | |
- | - | (*DP)-- | |
[ | [ | while(*DP!=0) { | |
] | ] | } // end while | |
. | . | putc(*DP) | |
, | , | *DP=getchar() | |
& | & | *DP=*DP&*(DP+1) | |
| | | | *DP=*DP|*(DP+1) | |
^ | ^ | *DP=*DP^*(DP+1) | |
~ | ~ | *DP=~*DP | |
\ | \ | *DP=*DP<<1 | |
/ | / | *DP=*DP>>1 |
N represents any valid address (in decimal, octal, or hexadecimal notation).
Instruction | Syntax | C Equivalent | Notes |
---|---|---|---|
> | >*N | DP+=*N | |
< | <*N | DP-=*N | |
+ | +*N | *DP+=*N | |
- | -*N | *DP-=*N | |
[ | [*N | while(*N!=0) { | |
] | ]*N | if(*N==0) break; } | Allows extra conditional break. |
. | .*N | putchar(*N) | |
, | ,*N | *N=getchar() | |
& | &*N | *DP=*DP&*N | |
| | |*N | *DP=*DP|*N | |
^ | ^*N | *DP=*DP^*N | |
~ | ~*N | *DP=~*N | |
\ | \*N | *DP=*DP<<*N | |
/ | /*N | *DP=*DP>>*N |
N represents any valid positive or negative number (in decimal, octal, or hexadecimal notation). This number is added to the current DP using C-style pointer arithmetic to determine which cell to operate on.
Instruction | Syntax | C Equivalent | Notes |
---|---|---|---|
> | >:N | DP+=*(DP+N) | |
< | <:N | DP-=*(DP+N) | |
+ | +:N | *DP+=*(DP+N) | |
- | -:N | *DP-=*(DP+N) | |
[ | [:N | while(*(DP+N)!=0) { | |
] | ]:N | if(*(DP+N)==0) break; } | Allows extra conditional break. |
. | .:N | putchar(*(DP+N)) | |
, | ,:N | *(DP+N)=getchar() | |
& | &:N | *DP=*DP&*(DP+N) | |
| | |:N | *DP=*DP|*(DP+N) | |
^ | ^:N | *DP=*DP^*(DP+N) | |
~ | ~:N | *DP=~*(DP+N) | |
\ | \:N | *DP=*DP<<*(DP+N) | |
/ | /:N | *DP=*DP>>*(DP+N) |
N represents any valid positive or negative number (in decimal, octal, or hexadecimal notation). This literal number is used in the operation.
Instruction | Syntax | C Equivalent | Notes |
---|---|---|---|
> | >#N | DP+=N | |
< | <#N | DP-=N | |
+ | +#N | *DP+=N | |
- | -#N | *DP-=N | |
[ | [#N | while(N!=0) { | |
] | ]#N | if(N==0) break; } | Allows forced break (e.g. if() pattern). |
. | .#N | putchar(N) | |
, | ,#N | *DP=N | |
& | &#N | *DP=*DP&N | |
| | |#N | *DP=*DP|N | |
^ | ^#N | *DP=*DP^N | |
~ | ~#N | *DP=~N | |
\ | \#N | *DP=*DP<<N | |
/ | /#N | *DP=*DP>>N |
Instruction | Syntax | C Equivalent | Notes |
---|---|---|---|
@ | @label | label: | Label must conform to C standard. |
! | !label | goto label; | Label must conform to C standard. |
!() | !(func) | func(); | External function call. Function must be defined by the user with signature: void func(void). |
# | # comment | /* comment */ | Everything until the next newline is considered a comment. |
#%() | #%(config) | N/A | Multi-line YAML configuration block (one per application). See Configuration section for more info. |