EBFC(1)

πŸ’… EBFC(1) β€” like, the ELF Brainfuck compiler bestie πŸ’–

okay so bestie, sit DOWN, because this is the ebfc manual page from section 1 of the General Commands Manual and it's genuinely iconic. it's the ELF Brainfuck compiler, and yes, that is exactly as powerful as it sounds. 🧚✨


✨ NAME ✨

ebfc β€” the ELF Brainfuck compiler. that's it, that's the whole name, no cap. πŸ‘‘


🌸 SYNOPSIS 🌸

ebfc [OPTIONS] SRCFILE

like, options first, then your source file. simple. gorgeous. periodt. πŸŽ€


πŸ’œ DESCRIPTION πŸ’œ

ebfc is a compiler for the Brainfuck programming language, and the way that it creates 64-bit ELF files targeted for the Intel x86-64 architecture? it's giving main character energy, fr fr. πŸ˜­πŸ’–

and it's not a one-trick pony either β€” ebfc can create:

  • standalone executables
  • shared libraries
  • object files

and those object files can themselves be targeted for a standalone executable, a shared library, or a module in a larger program. versatility! we love to see it. πŸ¦‹


🎯 COMPILATION TARGET OPTIONS 🎯

these options control what type of source file gets created. for all of these, the manpage assumes your source file is named foo.b. (yes, foo.b, iconic name, no notes. πŸ™ˆ)

  • -x β€” compiles the source code into a standalone executable file, named foo.
  • -l β€” compiles the source code into a shared library file, named libfoo.so. the program gets exported as a function named foo().
  • -c β€” compiles the source code into a function, named foo(), inside an object file named foo.o. this object file is targeted for a module in an executable.
  • -xc β€” compiles the source code into an object file, named foo.o, that can then be linked as a standalone executable.
  • -lc β€” compiles the source code into a function, named foo(), inside an object file named foo.o, that can then be linked as a shared library.
⚠️ okay important bit: if the SRCFILE argument doesn't have a .b or .bf suffix, then the entire filename gets used when creating the name of the target file and function. and for -x specifically? the target file is named a.out instead. slay but make sure you know which one you're getting. πŸ’…

πŸ› οΈ OTHER OPTIONS πŸ› οΈ

  • -a, --arg β€” compiles the function so it takes an argument, namely a pointer to the byte array. by default, ebfc compiles its code to a function that takes no arguments, and that one uses an internal byte array. when this option is used, there's no difference between the object file created by -c and the one created by -lc. (also β€” this option is not applicable to a standalone executable.) 🫢
  • -f, --function=FUNCTION β€” uses FUNCTION as the name of the function that contains the compiled program. if you don't pass this argument, the function's name gets taken from the source filename, exactly like described in the previous section. ✨
  • -i, --input=FILE β€” uses FILE as the name of the source file to place in the target file. heads up: this option does not supersede the SRCFILE argument β€” it just changes what name gets stored in the object file. (and it's not meaningful if the target isn't an object file, or if the --strip option is used.) 😭
  • -o, --output=FILE β€” uses FILE as the target filename. skip it and the output filename gets generated from the source filename, same as described in the previous section. πŸŽ€
  • -s, --strip β€” suppresses inclusion of unnecessary data in the target file. by default ebfc includes a .comment section and includes a symbol in the symbol table for the source filename. this option removes both of those from the output. additionally, if the output is a standalone executable, this option suppresses inclusion of the section header table. πŸ’€
  • -z, --compressed β€” reads the source file in compressed Brainfuck format (see below, bestie, it's a whole thing). πŸ¦‹
  • --help β€” displays help and exits. 🌈
  • --version β€” displays the version number and exits. ⭐

πŸ”— LINKING πŸ”—

when you're calling a compiled Brainfuck program from inside a C program, the C prototype for the function should look like this:

extern void foo(void);

or, if you used the --arg option, it should look like this instead:

extern void foo(char *buffer);

in that latter case, the buffer pointed to by the function parameter gets used as the initial state of the Brainfuck buffer when the function is invoked, and upon return it'll contain the final state of the buffer. it's giving give-and-take. iykyk. 🫢✨


🧠 THE BRAINFUCK PROGRAMMING LANGUAGE 🧠

a Brainfuck program has an implicit byte pointer, called "the pointer", and that pointer is free to move around within an array of bytes that are initially all set to zero. the pointer itself is initialized to point to the beginning of this array.

πŸ“Œ side note: the size of the array isn't constrained by the language, but it's typically 30000 bytes or more. ebfc programs get an array of 32768 bytes. no cap.

the Brainfuck programming language consists of eight commands, each represented as a single character:

  • > β€” increment the pointer.
  • < β€” decrement the pointer.
  • + β€” increment the byte at the pointer.
  • - β€” decrement the byte at the pointer.
  • . β€” output the byte at the pointer.
  • , β€” input a byte and store it in the byte at the pointer.
  • [ β€” jump to the matching ] if the byte at the pointer is zero.
  • ] β€” jump to the matching [.

any other characters in the source code are treated as comments or whitespace and ignored. so go ahead, write a whole essay in there, it's fine. πŸ’–

the semantics of the Brainfuck commands can also be expressed succinctly in terms of C, like this (assuming p has previously been defined as a char*):

>   becomes  ++p;
<   becomes  --p;
+   becomes  ++*p;
-   becomes  --*p;
.   becomes  putchar(*p);
,   becomes  *p = getchar();
[   becomes  while (*p) {
]   becomes  }
⚠️ and just like with C, the generated program's behavior is undefined if the pointer is moved outside of the byte array. do not do this. i am begging. πŸ’€

πŸ—œοΈ COMPRESSED BRAINFUCK πŸ—œοΈ

there's a compressed format for storing and transmitting Brainfuck programs, and ebfc can read it natively by using the --compressed option. it's giving zip file but for vibes. πŸŽ€

in compressed Brainfuck, the eight commands are encoded in three bits, like this:

+   000
-   001
<   010
>   011
[   100
]   101
,   110
.   111

each byte in a compressed Brainfuck file contains one or more commands. the top two bits select between one of four possible readings of the lower six bits, like this:

  • singleton β€” bits 00 abc abc β€” translation: abc
  • pair β€” bits 00 abc def β€” translation: abc followed by def
  • triplet β€” bits 10 ab cd ef β€” translation: 0ab then 0cd then 0ef
  • repetition β€” bits 01 abc def β€” translation: def repeated 2 + abc times (2-9)
  • repetition β€” bits 11 abcd ef β€” translation: 0ef repeated 2 + abcd times (2-17)

look at that compression. she's efficient. she's compact. she ate. πŸ‘‘


🚨 ERRORS 🚨

the compiler will issue an error message, and the compilation will fail, if:

  • the program contains unbalanced bracket commands, or
  • the level of nested brackets exceeds the compiler's maximum capacity β€” which is arbitrarily set at 256.

so like, nest responsibly bestie. πŸ˜­πŸ’…


Copyright Β© 1999, 2001, 2021 Brian Raiter <breadbox@muppetlabs.com>.

License GPLv2+: GNU GPL version 2 or later. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.


and that's the whole page, bestie!! πŸ’– this was ELF kickers 3.2, dated May 2021, and you just read the EBFC(1) manpage. go compile something unhinged. i'm obsessed with you. πŸŽ€βœ¨πŸ’œ

πŸ“¦ where this page comes from