Skip to content

FuckBench (FB) is a set of development tools to compile several languages to BrainFuck.

License

Notifications You must be signed in to change notification settings

mzattera/FuckBench

Repository files navigation

FuckBench

What is it?

FuckBench (FB) is a set of Windows batch files and tools to compile from several languages into brainfuck (BF).

Optionally, in addition to creating BF code, FB can compile generated BF code into highly optimized C files using the Esotope BF to C compiler. If a C compiler is available, a Windows executable is also created.

Currently, FB supports compiling the following languages to BF:

As far as the author knows, FuckBench made possible to generate the first multi-threaded program in brainfuck (MultiThreadDemo.bf), from Java source (MultiThreadDemo.java). A compiled version is also available.

How does it work?

FB includes a BF emulator for the 6502 CPU (6502.fbf); this allows using cross-compilers available for the 6502 CPU to create BF code. A "linker" is provided (CodeMerge.jar) to "link" 6502 executable code to the emulator, creating a single BF file that can then be executed by using any available BF compiler or interpreter.

Given the generated code is not the fastest, I strongly suggest configuring a C compiler, as explained below, such that C code generated by Esotope can be turned into a Windows executable.

Usage

Configuration

FB relies on a set of external tools. Some of them need to be installed, as described below. Others are made available under the <root>\redistr folder, for your convenience.

  1. Download latest FuckBench release and unzip it in a folder on your machine. We will refer to this folder as <root>.
  2. I strongly suggest to add <root>\bin to your path, such that FB tools can be invoked from any location in your machine. The below examples assume batch files in the <root>\bin folder are accessible from the command line.
  3. Install Java. FB needs Java 15 or later. Normally, Java installer updates PATH environment variable as required, if not, make sure the folder used by your Java installation is added to the path. FB assumes java command will work when invoked from within any folder.
  4. Download cc65 6502 C cross-compiler and install it as explained in the "Getting Started" page. Notice that the installation folder for cc65 must NOT contain any space.
  5. Edit <root>\bin\config.bat and set FB_CC65 to the folder where you installed cc65.

Optional - the below steps are required if you want to compile generated BF code into C. If you skip the below configuration, BF compilation will stop after generating BF code.

  1. Install Python 2. I suggest using WinPython for easier installation; notice however that WinPython has some limitation on the installation folder name.
  2. Edit <root>\bin\config.bat and set FB_PYTHON to the Python interpreter executable.

Optional - the below steps are required if you want to compile C code generated above into a Windows executable.

  1. Edit <root>\bin\FB_ccompiler.bat and adapt it to your C compiler. This batch file receives the name of a .c file (without extension) to compile and it is assumed to call any installed C compiler to do the job. It is up to you to modify this batch file to properly invoke any C compiler you are using. If you are not using any C compiler, just leave this file blank.

Specifications for the brainfuck environment

To successfully run, BF code created by FB requires a BF interpreter or compiler with below specifications; please notice the section above explains how to use Esotope and any Windows C compiler to create Windows executables out of your BF generated code.

  • Unsigned wrapping 16 bit cells (0-65565).

  • A tape of at least 131193 cells. At the beginning of execution the tape head is assumed to be in the leftmost cell and will move only to cells on its right.

  • The Windows executables created with Esotope + C compiler, when encountering a BF , command will read a string from console until user presses enter. The string is returned with a terminating $0A (LF) char.

    For example, when the generated BF code contains a , execution stops waiting for user input. Users enters "A1!" followed by "enter" key. BF will receive the characters with decimal ASCII code: $41, $31, $21, $0A in this order.

    Notice that the cc65 libraries provided with FB read input until either a $00 (null) or $0A (LF) character is returned; if $00 is read, it is replaced by $0A before being returned.

Compiling brainfuck code

If you followed the above optional steps, you can invoke:

FB_bf f

to compile brainfuck f.bf source file into f.c C code and corresponding executable Windows file f.exe.

Again, if Python or C compiler have not been configured, compilation will stop at some intermediate steps.

Compiling FuckBrainFuck code

You can invoke:

FB_fbf f

to compile FuckBrainFuck f.fbf source file into f.bf brainfuck code, f.c C code and corresponding executable Windows file f.exe.

Again, if Python or C compiler have not been configured, compilation will stop at some intermediate steps.

<root>\notepad++ folder contains a custom language definition for the FuckBrainFuck language, to be used with Notepad++ editor. This is optional but higly recommended if you want to write FuckBrainFuck code.

Compiling 6502 assembly

FB uses ca65, a 6502 assembler contained within cc65 6502 C cross-compiler to compile 6502 assembly code into a 6502 executable that is then linked to the 6502bf BF emulator to produce final BF code.

You can invoke:

FB_asm f

to compile ca65 assembly file f.s source file into f.bf brainfuck code, f.c C code and corresponding executable Windows file f.exe.

Again, if Python or C compiler have not been configured, compilation will stop at some intermediate steps.

The file <root>\cc65\6502bf.inc contains a set of macros that exposes features available in the 6502bf emulator.

The code can use zeropage variables (except for 26 bytes reserved by ca65) and the whole of RAM (starting from $200), with the exception of a software stack located in high memory. For more information, please refer to <root>\cc65\6502bf.cfg configuration file and cc65 documentation.

Compiling ANSI C

FB uses cc65 6502 C cross-compiler to compile C code into a 6502 executable that is then linked to the 6502bf BF emulator to produce final BF code.

You can invoke:

FB_cl f

to compile f.c source file into f_c.bf brainfuck code, f_c.c C code (for f_c.bf) and corresponding executable Windows file f.exe.

Again, if Python or C compiler have not been configured, compilation will stop at some intermediate steps.

Please notice that cc65 somehow differs from ANSI C.

C Libraries

cc65 provides extensive C libraries covering most of the C standard ones, FB adds some (machine-dependent) functions as well. To re-build the libraries used by FB, you can call <root>\bin\FB_build_lib.bat; this will compile all .s (6502 assembler) and .c files under <root>\cc65 folder and add them to the cc65 library.

time.h

All standard library functions in time.h, with the exception of clock_settime (clockid_t, const struct timespec), are available in FB with some limitations, as explained below.

BF has no access to a system clock, however, the 6502bf emulator keeps track of the number of instructions being executed; this is returned by the standard clock() function.

The time() function takes the value returned by clock() and divides it by CLOCKS_PER_SEC to have a (rough) estimate of seconds passed since the program started. The file <root>\examples\watch.c can be used to test the clock; it is supposed to print a line every second, but the timing will depend on how fast your machine is (how many 6502 emulated instructions it executes per second). You can fine tune CLOCKS_PER_SEC for your machine by changing CPS macro in <root>\cc65\fbtime.c (rebuild the libraries if you do so, as explained above). Keep in mind watch can be so slow to not be able to print a line per second, no matter how low CPS is ;-)

srand()

Often, the below construct (or similar) is used to initialize the random number generator:

srand((unsigned) time(NULL));

Please notice that the above will compile successfully but, because time() and clock() are based on the number of 6502 instruction executed up to that point in the code, they will always return same value at each execution, therefore the random number generator will always be initialized with the same seed.

The only way to properly initialize the random number generator in FB is to ask the user to input a random seed.

Compiling Java

FB uses b2fJ tiny Java virtual machine to convert Java code into a 6502 executable that is then linked to the 6502bf BF emulator to produce final BF code.

You can invoke:

FB_java f

to compile f.java source file into f.bf brainfuck code, f.c C code (for f.bf) and corresponding executable Windows file f.exe.

Again, if Python or C compiler have not been configured, compilation will stop at some intermediate steps.

b2fJ supports Java 1.8 but has a smaller standard Java library. Please refer to the project website for details.

Please notice that, since version 0.2.2, b2fJ has a bug that limits the actual usefulness of the code that can be written; it is still provided as a "proof of concept" of object-oriented programming in brainfuck.

The 6502bf emulator

FuckBench uses a 6502 emulator written in FuckBrainFuck (<root>\6502bf.fbf) to translate 6502 code to brainfuck. The emulator implements a standard 6502 CPU, with the below caveats:

  • It does not support "decimal" mode of operations at the moment.
  • It uses the undocumented opcode 66 (hex 42) to implement some "SYSCALLS", that is to expose some functionalities such as brainfuck I/O or to interface with C libraries. Each functionality is identified by the content of the byte following the 66 opcode; functionalities are implemented in the SYSCALL_ block in the emulator and also exposed as 6502 assembly macros in <root>\cc65\6502bf.inc.
  • It implements automatic loop detection for JMP/JSR/BRK/branch instructions; that is the emulator will quit if one of these instructions jumps back to the instruction itself. This is used when testing the emulator.

Changing 6502 emulator

If you change the emulator, please notice that the Java linker (<root>\eclipse\6502bf tools\src\org\mzattera\bf6502\Linker.java needs to know the position of the mem array (this is the emulated 6502 memory) on the tape. This information is provided by the FuckBrainFuck compiler when it compiles the emulator (check the compiler output towards the end).

Compiling 6502 emulator

Run <root>\bin\FB_build_emu.bat to rebuild the 6502bf emulator (<root>\6502bf.bf). The folder <root>\test\ca65 contains code to test the emulator, they are used by FB_run_tests.bat as explained below.

Making a new release

<root>\bin\FB_run_tests.bat runs a battery of tests for FB; in the process, it also rebuilds FB assets. Because of this, it can be used as preparation for a new release. It can also be used to run regression tests, enabling only some checks, as explained below.

  1. It will rebuild 6502bf emulator. This can be skipped with -e option from command line.
  2. It will rebuild and execute 6502 functional tests, in order to verify the emulator runs correctly. This can be skipped with -f option from command line.
  3. It will rebuild cc65 libraries. This can be skipped with -l option from command line.
  4. For each sub folder in <root>\test, it will compile files contained therein, execute them and compare their output with corresponding .ref file, issuing an error when they do not match. This can be skipped with -t option from command line.
  5. Providing the -v option, will print verbose output to console.

If all of the above tests ran successfully, FB will be re-built and it is ready for a release.

Please notice that Python and C compiler must be configured to run regression tests.