/bf.c
-
Star
(137)
You must be signed in to star a gist -
Fork
(8)
You must be signed in to fork a gist
-
-
Save lifthrasiir/596667 to your computer and use it in GitHub Desktop.
/* The world's smallest Brainfuck interpreter in C, by Kang Seonghoon | |
* http://j.mearie.org/post/1181041789/brainfuck-interpreter-in-2-lines-of-c */ | |
s[99],*r=s,*d,c;main(a,b){char*v=1[d=b];for(;c=*v++%93;)for(b=c&2,b=c%7?a&&(c&17 | |
?c&1?(*r+=b-1):(r+=b-1):syscall(4-!b,b,r,1),0):v;b&&c|a**r;v=d)main(!c,&a);d=v;} |
how to compile some bf
@tpglitch you compile the program with GCC
gcc -o bf bf.c
Then you pass the program as an argument
./bf +++++,.--
main is recursive wow
r e c u r s e m a i n
using gcc to compile results in a binary that segfaults on any input
Same here, it does compile, but it always segfaults.
$ /bin/gcc --version | head -n1
gcc (GCC) 12.2.1 20230201
$ expac '%v' gcc
12.2.1-2
$ expac -Ss '%r-%v' '^gcc$'
core-12.2.1-2
Still nice idea, but for some reason just doesn't work.
My compiled binary with gcc also gets segfaults for any input! Anyone have a tip!?
My GCC: gcc (Ubuntu 12.1.0-2ubuntu1~22.04) 12.1.0
See below
you'll need to refactor the bf compiler so that it's not implicitly typing all untyped variables as ints, this only works as-is on platforms where the int width is the same as a char (1 octet/8 bits), which is the case on the pdp11. To run this as-is, your best bet is to see if you can find an emulator for the pdp11, if it exists.
No it isn't. It does assume that int has the same size as a pointer, which no longer holds in modern 64-bit architectures, but I'm pretty sure that you can still compile and run this code in 32-bit architectures by, for example, using -m32
in GCC to force it. (As you can imagine, because I wrote that code. But I'm on a road and I cannot readily test that, so YMMV.)
How does this work? :O
To any newcomers:
Compile using gcc with the flag "-m32"
You may need to install the gcc-multilib package in order to target an x86 binary
After you have the right libraries installed, you should be able to compile like this:
gcc -m32 -o bf bf.c
good stuff.
Here is the clarified version. I used gpt-4 to reconstruct the code, meaning I just wanted to share the clarified version for learning purposes. I don't know C language, but I was curious.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define TAPE_SIZE 30000
// Declare an array to act as the tape for Brainfuck. Initialize all to zero.
unsigned char s[TAPE_SIZE] = {0};
// This will be the data pointer used in Brainfuck
unsigned char* ptr = s;
// Forward declaration of the main function to make it recursive
int main(int argc, char *argv[]);
int main(int argc, char *argv[]) {
char* v;
// Ensure that a Brainfuck program is provided as an argument
if (argc != 2) {
fprintf(stderr, "Usage: %s 'brainfuck_code'\n", argv[0]);
return 1;
}
v = argv[1];
while (*v) {
switch (*v) {
case '>':
ptr++;
// Boundary check to prevent going beyond the tape
if (ptr >= s + TAPE_SIZE) {
fprintf(stderr, "Error: Pointer out of bounds\n");
return 1;
}
break;
case '<':
// Boundary check to prevent going before the tape
if (ptr <= s) {
fprintf(stderr, "Error: Pointer out of bounds\n");
return 1;
}
ptr--;
break;
case '+':
(*ptr)++;
break;
case '-':
(*ptr)--;
break;
case '.':
putchar(*ptr);
break;
case ',':
*ptr = (unsigned char)getchar();
break;
case '[':
if (!*ptr) {
int loop = 1;
while (loop > 0) {
v++;
if (*v == '[') loop++;
if (*v == ']') loop--;
}
}
break;
case ']':
if (*ptr) {
int loop = 1;
while (loop > 0) {
v--;
if (*v == '[') loop--;
if (*v == ']') loop++;
}
}
break;
}
v++;
}
return 0;
}
How to compile?
gcc brainfuck.c
How to run?
./a.out "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
"
This should dispay
Hello world
Here is the clarified version. I used gpt-4 to reconstruct the code, meaning I just wanted to share the clarified version for learning purposes. I don't know C language, but I was curious.
Honestly looks like chat gpt just spat out a generic bf interpreter, it doesn't share many characteristics with the minimal interpreter.
Here is the clarified version. I used gpt-4 to reconstruct the code, meaning I just wanted to share the clarified version for learning purposes. I don't know C language, but I was curious.
Honestly looks like chat gpt just spat out a generic bf interpreter, it doesn't share many characteristics with the minimal interpreter.
Yeah, it doesn't even call main recursively, it just iterates through the string. For some reason, ChatGPT has been upsetting me more and more recently (
After a few back and forth with GPT-4o, I got this:
#include <unistd.h> // for syscall
#define MEMORY_SIZE 99
#define SYSCALL_WRITE 4
#define INCREMENT '+'
#define DECREMENT '-'
#define SHIFT_RIGHT '>'
#define SHIFT_LEFT '<'
#define OUTPUT '.'
#define INPUT ','
#define LOOP_START '['
#define LOOP_END ']'
#define IO_OPERATION_FLAG 2
#define TO_CHAR(x) ((char)(x))
#define TO_INT(x) ((int)(x))
char memory[MEMORY_SIZE], *pointer = memory, *return_address, command;
int main(char argument, char **arguments) {
return_address = arguments;
char *code = return_address[1];
while ((command = TO_CHAR(*code++)) != '\0') {
command = TO_CHAR(TO_INT(command) % 93);
char is_io_operation = TO_CHAR(command & IO_OPERATION_FLAG);
char is_pointer_operation = TO_CHAR(command % 7);
if (is_pointer_operation) {
if (argument) {
if (command == INCREMENT || command == DECREMENT) {
if (command == INCREMENT) {
*pointer += INCREMENT - '0';
} else {
*pointer += DECREMENT + '0';
}
} else if (command == SHIFT_RIGHT || command == SHIFT_LEFT) {
if (command == SHIFT_RIGHT) {
pointer += SHIFT_RIGHT - '>';
} else {
pointer += SHIFT_LEFT - '<';
}
} else if (command == OUTPUT || command == INPUT) {
syscall(SYSCALL_WRITE - !is_io_operation, is_io_operation, pointer, 1);
}
}
} else {
code = return_address; // Set code pointer back to the start of the current command
}
while (is_io_operation && (command | argument ** pointer)) {
code = return_address;
main(!command, &argument); // Toggle argument based on the command
}
return_address = code;
}
return 0;
}
Wow. wow.
To any newcomers:
Compile using gcc with the flag "-m32"
You may need to install the gcc-multilib package in order to target an x86 binary
After you have the right libraries installed, you should be able to compile like this:
gcc -m32 -o bf bf.c
Cheers!
Og code using an online C beautifier: https://codebeautify.org/c-formatter-beautifier/y255f5fa5
s[99], * r = s, * d, c;
main(a, b) {
char * v = 1[d = b];
for (; c = * v++ % 93;)
for (b = c & 2, b = c % 7 ? a && (c & 17 ?
c & 1 ? ( * r += b - 1) : (r += b - 1) : syscall(4 - !b, b, r, 1), 0) : v; b && c | a ** r; v = d) main(!c, & a);
d = v;
}
Awesome!!! 🥇 🥇 🥇
But can you explain it? pls!!!
By the way, this can be collected in TCCC. If you agree, please check the collaborate invitation.
Awesome!!! 🥇 🥇 🥇 But can you explain it? pls!!!
I did some C tutorials so I'll take a shot.
The code is heavily obfuscated and most variables are untyped. Hell even main
is untyped. SO I asked a GPT and it spat out this
This is an example of obfuscated C code — it’s intentionally written in a cryptic, unreadable way using obscure pointer arithmetic, operator overloading, and terse expressions. Let's break it down to figure out what it’s doing.
Step-by-step Breakdown
Declaration:
s[99], *r = s, *d, c;
s[99]
declares an array of 99 integers.*r = s
setsr
as a pointer tos
(i.e., beginning of array).*d, c
declaresd
as a pointer,c
as an int.So
s
is the data buffer,r
is the current pointer into it,d
will be a pointer,c
is a char/int used in the main loop.
Main function signature
```c
main(a, b)
```Old-style K&R function declaration.
a
andb
are parameters.
a
is treated like anint
b
is treated likechar **
in some places
Initial pointer setup
```c
char *v = 1[d = b];
```This means:
d = b
assignsb
tod
1[d]
is the same asd[1]
(pointer syntax)- So
v = d[1]
Assuming
b
ischar **argv
, thenv = argv[1]
So
v
now points to the first command-line argument string
Outer for loop
```c
for (; c = *v++ % 93;)
```
- This reads each character from
v
(i.e. the command-line argument)- Takes ASCII value mod 93
- Stores result in
c
- Continues loop while
c
is non-zero
Inner for loop
```c
for (b = c & 2, b = c % 7 ? a && (c & 17 ?
c & 1 ? ( * r += b - 1) : (r += b - 1) : syscall(4 - !b, b, r, 1), 0) : v;
b && c | a ** r;
v = d)
main(!c, &a);
```This is where things get dense. Here's a breakdown:
b = c & 2
extracts bit 1 ofc
b = c % 7 ? ... : v
:
- If
c % 7
is true:
- If
a
and(c & 17)
:
- If
c & 1
:*r += b - 1
- Else:
r += b - 1
- Else:
syscall(4 - !b, b, r, 1)
- Then comma operator evaluates to 0 (meaning no change to b)
The loop condition:
b && (c | a ** r)
— continues looping ifb
is nonzero and expression doesn't short-circuitIn loop body:
```c
main(!c, &a);
```
Recursively callsmain
After loop:
d = v;
Summary of What It Does
This is a small ASCII-art or brainf*ck-style interpreter, often used in programming contests or obfuscation competitions like the IOCCC.
It:
- Reads characters from command-line input
- Interprets them as a kind of bytecode
- Manipulates a data tape (
s[]
via pointerr
)- Uses recursion, pointer arithmetic, and the
syscall()
to possibly output charactersThis kind of code is often used to execute a tiny self-contained language or generate output from a compressed string.
Likely Behavior When Run
If you compile and run this with:
```bash
./a.out 'encoded_string'
```It would process each character, updating memory and maybe writing output to
stdout
usingsyscall(4, ...)
— which is a direct write system call on Unix/Linux.
TL;DR
This code:
- Takes a command-line string
- Interprets each character with custom logic
- Modifies a buffer
- Possibly outputs characters via syscall
- Uses heavy recursion and obfuscation tricks
It’s likely an interpreter or decoder, possibly producing ASCII art or executing some esoteric code. Would you like me to deobfuscate and rewrite it clearly?
A lot of pointer arithmatic and untyped variables. Maybe gcc -m32
means 32-bit ints? I guess I have to phone ask the GPT to answer this one.
This is an example of obfuscated C code — it’s intentionally written in a cryptic, unreadable way using obscure pointer arithmetic, operator overloading, and terse expressions. Let's break it down to figure out what it’s doing.
Step-by-step Breakdown
Declaration:
s[99], *r = s, *d, c;
s[99]
declares an array of 99 integers.*r = s
setsr
as a pointer tos
(i.e., beginning of array).*d, c
declaresd
as a pointer,c
as an int.So
s
is the data buffer,r
is the current pointer into it,d
will be a pointer,c
is a char/int used in the main loop.
Main function signature
main(a, b)Old-style K&R function declaration.
a
andb
are parameters.
a
is treated like anint
b
is treated likechar **
in some places
Initial pointer setup
char *v = 1[d = b];This means:
d = b
assignsb
tod
1[d]
is the same asd[1]
(pointer syntax)- So
v = d[1]
Assuming
b
ischar **argv
, thenv = argv[1]
So
v
now points to the first command-line argument string
Outer for loop
for (; c = *v++ % 93;)
- This reads each character from
v
(i.e. the command-line argument)- Takes ASCII value mod 93
- Stores result in
c
- Continues loop while
c
is non-zero
Inner for loop
for (b = c & 2, b = c % 7 ? a && (c & 17 ? c & 1 ? ( * r += b - 1) : (r += b - 1) : syscall(4 - !b, b, r, 1), 0) : v; b && c | a ** r; v = d) main(!c, &a);This is where things get dense. Here's a breakdown:
b = c & 2
extracts bit 1 ofc
b = c % 7 ? ... : v
:
- If
c % 7
is true:
- If
a
and(c & 17)
:
- If
c & 1
:*r += b - 1
- Else:
r += b - 1
- Else:
syscall(4 - !b, b, r, 1)
- Then comma operator evaluates to 0 (meaning no change to b)
The loop condition:
b && (c | a ** r)
— continues looping ifb
is nonzero and expression doesn't short-circuitIn loop body:
main(!c, &a);Recursively calls
main
After loop:
d = v;
Summary of What It Does
This is a small ASCII-art or brainf*ck-style interpreter, often used in programming contests or obfuscation competitions like the IOCCC.
It:
- Reads characters from command-line input
- Interprets them as a kind of bytecode
- Manipulates a data tape (
s[]
via pointerr
)- Uses recursion, pointer arithmetic, and the
syscall()
to possibly output charactersThis kind of code is often used to execute a tiny self-contained language or generate output from a compressed string.
Likely Behavior When Run
If you compile and run this with:
./a.out 'encoded_string'
It would process each character, updating memory and maybe writing output to
stdout
usingsyscall(4, ...)
— which is a direct write system call on Unix/Linux.
TL;DR
This code:
- Takes a command-line string
- Interprets each character with custom logic
- Modifies a buffer
- Possibly outputs characters via syscall
- Uses heavy recursion and obfuscation tricks
It’s likely an interpreter or decoder, possibly producing ASCII art or executing some esoteric code. Would you like me to deobfuscate and rewrite it clearly?
Edit: had to get GPT to reveal the original markdown ina code block so it had to escape the ``` with \```
how do i compile with it???