• Jallen's Brainfuck Interpreter
    72 replies, posted
  • [B]Jallen's Brainfuck Interpreter[/B] I recently saw someone explain in a post how simple brainfuck actually was, so I wrote an interpreter for it. There is infinite array space as it is written in C++ and uses std::vector, so for crying out loud do not make an infinite loop which continues increasing the current index unless you want it to start using memory like mad. The Exe is about 17kb, and actually weiged in at about 110 lines of C++ including all the debug message stuff. Just drag and drop your brainfuck source files onto either executeable, the debug one has debug messages to make it a little easier to make your programs. [url]http://www.mediafire.com/?23ymeeztznm[/url] [B]And now a simple brainfuck introduction[/B] You have an array. You start at element 0. All elements are initialised to 0. [B]>[/B] goes to the next element in the array (index--;). [B]<[/B] goes to the previous index in the array (index++;). [B]+[/B] adds one to the item you are currently on (items[index]++;) [B]-[/B] subtracts one from the item you are currently on (items[index]--;) [B],[/B] takes a character from the keyboard and puts it in your currently pointed at item. [B].[/B] outputs the currently pointed at item by casting it to a char (so 65 is A). [B][[/B] indicates the start of a loop. [B]][/B] indicates the end of a loop. A loop will continue to run while the currently pointed at object is not 0. For more information: [url]http://en.wikipedia.org/wiki/Brainfuck[/url] The test program in the archive shows how to output ABCDE using both repeated +'s and a loop. So yeah, enjoy programming in brainfuck, be sure to post any cool stuff you make in it, and if you are sure of a problem with the interpreter, it would be nice if you would post that also. Thanks for reading, and hopefully trying out my interpreter :D Tell me what you think :) [highlight]NEW BUG FREE VERSION - ALLOWS LOOPS IN LOOPS AND STUFF[/highlight] [url]http://www.mediafire.com/?zg3othmmfyj[/url] Includes sources :D
  • Funnily enough, I wanted to write my own one in either C or C++ to practice a bit. I'll try working on it today and see how it compares. Good job!
  • Nice job, I wanna try making one in C#. Maybe even a pseudo-compiler for it. Oh and you're missing a right bracket in your OP at the '-' operator's definition.
  • [QUOTE=Xeon06;14176451]Oh and you're missing a right bracket in your OP at the '-' operator's definition.[/QUOTE] Thanks.
  • Hehe this is sweet. I basically ignored brainfuck because of its name... I want to make one too, maybe a "whitespace" interpreter :v:
  • [QUOTE=gilly_54;14187472]Hehe this is sweet. I basically ignored brainfuck because of its name... I want to make one too, maybe a "whitespace" interpreter :v:[/QUOTE] make an LOLcode one please
  • Holy shit this is actually so simple, it looked so fucking complicated when I first saw it, now I'm gonna try to make one too, maybe even add some of my own shit to it. Also this may pick up to be like that raytracer fad.
  • I did this crime against c++ for fun some time ago: [cpp]char* _bf_data = new char[30000]; char* _bf_ptr = _bf_data; #define > ++_bf_ptr; #define < --_bf_ptr; #define + ++*_bf_ptr; #define - --*_bf_ptr; #define . _bf_out(*_bf_ptr); #define , *_bf_ptr = _bf_in(); #define [ while (*_bf_ptr) { #define ] } #define input(x) char (*_bf_in )() = x #define output(x) void (*_bf_out)(char) = x[/cpp] Unfortunately (or fortunately :P), it doesn't compile since MSVC doesn't allow me to define symbols such as + - * etc.
  • [QUOTE=noctune9;14188275]I did this crime against c++ for fun some time ago: [cpp]char* _bf_data = new char[30000]; char* _bf_ptr = _bf_data; #define > ++_bf_ptr; #define < --_bf_ptr; #define + ++*_bf_ptr; #define - --*_bf_ptr; #define . _bf_out(*_bf_ptr); #define , *_bf_ptr = _bf_in(); #define [ while (*_bf_ptr) { #define ] } #define input(x) char (*_bf_in )() = x #define output(x) void (*_bf_out)(char) = x[/cpp] Unfortunately (or fortunately :P), it doesn't compile since MSVC doesn't allow me to define symbols such as + - * etc.[/QUOTE]Of course it won't, You kind of need them.
  • [QUOTE=danharibo;14193778]Of course it won't, You kind of need them.[/QUOTE] Yeah, I see why, but that was more of a test for fun. Anyways, I've made a interpreter while being bored yesterday: [cpp]#include <stack> #include <iostream> #include <vector> #include <string> void brainfuck(std::string code, std::istream& in, std::ostream& out) { std::stack<unsigned int> func; std::vector<char> memory(30000,0); unsigned int memory_index = 0; unsigned int code_index = 0; bool jump = false; while (code_index <= code.size()) { if (!jump) { switch(code[code_index]) { case '>': memory_index++; break; case '<': memory_index--; break; case '+': memory[memory_index]++; break; case '-': memory[memory_index]--; break; case '.': out << memory[memory_index]; break; case ',': in >> memory[memory_index]; break; case '[': func.push(code_index); if(memory[memory_index] == 0) jump = true; break; case ']': if(memory[memory_index] != 0) code_index = func.top(); else func.pop(); break; } } else if(memory[memory_index] == ']') jump = false; code_index++; } }[/cpp]It's much more difficult to write brainfuck than writing the interpreter.
  • [QUOTE=noctune9;14200399]Yeah, I see why, but that was more of a test for fun. Anyways, I've made a interpreter while being bored yesterday: [cpp]#include <stack> #include <iostream> #include <vector> #include <string> void brainfuck(std::string code, std::istream& in, std::ostream& out) { std::stack<unsigned int> func; std::vector<char> memory(30000,0); unsigned int memory_index = 0; unsigned int code_index = 0; bool jump = false; while (code_index <= code.size()) { if (!jump) { switch(code[code_index]) { case '>': memory_index++; break; case '<': memory_index--; break; case '+': memory[memory_index]++; break; case '-': memory[memory_index]--; break; case '.': out << memory[memory_index]; break; case ',': in >> memory[memory_index]; break; case '[': func.push(code_index); if(memory[memory_index] == 0) jump = true; break; case ']': if(memory[memory_index] != 0) code_index = func.top(); else func.pop(); break; } } else if(memory[memory_index] == ']') jump = false; code_index++; } }[/cpp]It's much more difficult to write brainfuck than writing the interpreter.[/QUOTE] That's pretty much identical to mine, except I handled loops a little differently and I have alot of lines taken up by the debug helping code (it's just a preprocessor definition which decides whether debug messages are shown). And mine goes through a file rather than just reading it from a string. And pushes back elements initialised to 0 when they move forward and the element doesn't yet exist. Actually, I'll clean up my code a bit, and then I'll post it.
  • Ok, here's my solution which doesn't use a stack, and has optional debug messages. And it's now OOP. [B]Main.cpp[/B] [cpp]#include "BrainFuck.h" int main(int argc, char *argv[]) { BrainFuck brainfuck; if(argc != 2) { std::cout<< "The file could not be opened - did you not open a file with the executable?\n"; getchar(); return 0; } brainfuck.RunFile(argv[1]); return 0; }[/cpp] [B]BrainFuck.h[/B] [cpp]#ifndef BrainFuck_h #define BrainFuck_h #include <iostream> #include <fstream> #include <vector> #include <string> #include <sstream> //#define DEBUGHELP class BrainFuck { public: void RunFile(std::string filename); protected: void RunCommand(char cmd); void OutputDebug(std::string message); std::ifstream file; std::vector<char> vector; int currentIndex; char command; std::string loopCode; unsigned int loopLength; bool inloop; }; std::string IntToString(int number); #endif[/cpp] [B]BrainFuck.cpp[/B] [cpp]#include "BrainFuck.h" void BrainFuck::RunFile(std::string filename) { inloop = false; vector.push_back(0); currentIndex = 0; command = 'a'; file.open(filename.c_str()); if(!file.is_open()) { std::cout<< "The file could not be opened - did you not to open a file with the executable?\n"; getchar(); return; } while(!file.eof()) { file>> command; if(!file.eof()) { if(!inloop) RunCommand(command); else { while(command != ']') { loopCode += command; if(!file.eof()) file>> command; } while(vector[currentIndex]) { for(int i = 0; i < loopCode.size(); i++) { RunCommand(loopCode[i]); } } inloop = false; OutputDebug("Exiting loop."); } } } OutputDebug("Program finished."); file.close(); getchar(); } void BrainFuck::RunCommand(char cmd) { switch(cmd) { case '>': currentIndex += 1; OutputDebug("Now on index " + IntToString(currentIndex) + "."); if(currentIndex >= vector.size()-1) vector.push_back(0); break; case '<': currentIndex -= 1; OutputDebug("Now on index " + IntToString(currentIndex) + "."); break; case '+': if(vector[currentIndex] < 255) vector[currentIndex]++; else OutputDebug("Could not add to current item - max value reached (255)."); break; case '-': if(vector[currentIndex] > 0) vector[currentIndex]--; else OutputDebug("Could not decrease current item - item is already null."); break; case '.': std::cout<< vector[currentIndex]; OutputDebug("Outputted character at index " + IntToString(currentIndex) + "."); break; case ',': std::cin>> vector[currentIndex]; OutputDebug("Read character to index " + IntToString(currentIndex) + "."); break; case '[': inloop = true; OutputDebug("Entering loop."); break; default: break; } } void BrainFuck::OutputDebug(std::string message) { #ifdef DEBUGHELP std::cout<< "\nDEBUG>>\t" << message << "\n"; #endif return; } std::string IntToString(int number) { std::stringstream stringstream; stringstream<< number; return stringstream.str(); }[/cpp] So yeah, it's not really what you call minimalistic like noctune's is because I made it all OOP and use debug and things, but yeah, it works, and it doesn't use a stack :D
  • [code]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++ [>++++++++++<-]>-.[/code] Do it
  • According to the different sites where I looked, the chars are supposed to 'wrap'. Ie. go to 0 when you increment 255 and go to 255 when you decrement 0. Edit: Whoops, just noticed I forgot to make the vector endless. Edit: Play that funky music, console. [code]+++++++[.][/code]
  • [QUOTE=noctune9;14204507]According to the different sites where I looked, the chars are supposed to 'wrap'. Ie. go to 0 when you increment 255 and go to 255 when you decrement 0.[/QUOTE] Ah ok cool, I'll add that too.
  • That should be automatic because the vector is a vector of chars.
  • I made my own implementation, and it's pretty much the same as yours except the loops code, is your code capable of doing loops in loops? Well anyway here's mine: [url]http://www.speedyshare.com/678677514.html[/url] Here's the code for the lazy: [cpp]#include <iostream> #include <string> #include <fstream> #define START_MEMORY 30000 void runProgram(std::string *program, std::string *memory, int index) { for (int i=0; i<program->size(); i++) switch(program->at(i)) { case '>': index++; if (index>=memory->size()-1) memory->push_back((char)0); break; case '<': index--; break; case '+': memory->at(index)++; break; case '-': memory->at(index)--; break; case '.': std::cout<<memory->at(index); break; case ',': std::cin>>memory->at(index); break; case '[': std::string loop; i++; while (program->at(i)!=']') { loop.push_back(program->at(i)); i++; } while (memory->at(index)) { runProgram(&loop, memory, index); } break; } } int main(int argc, char *argv[]) { std::string memory(START_MEMORY,(char)0); std::string program,temp; std::ifstream file(argv[1]); if (argc!=2) std::cin>>program; else while (!file.eof()) { file>>temp; program+=temp; } runProgram (&program,&memory,0); std::cout<<"\n\nYeah I'm using system(\"PAUSE\") whatcha gonna do you dick?\n"; system("PAUSE"); return 0; } [/cpp] Oh yeah just drag and drop a file like with Jallens or run the program and type the program as a single line. Ah crud just figured out why my code doesn't do loops in loops, I'll sort it out tomorrow.
  • [QUOTE=high6;14205472]That should be automatic because the vector is a vector of chars.[/QUOTE] It doesn't seem to be. My unfixed program throws an debug assertion when incrementing memory_index to a value larger than the size of the vector and I read/write to it.
  • Sporbie, you really should rework how you indent some of your code. [cpp] if (argc!=2) std::cin>>program; else while (!file.eof()) [/cpp] ... really makes people want to kill babies. Also, don't just use pointers because you can. Go with references whenever possible, it simplifies the typing as well. Here's everything I changed, fixing every warning I could find. Checking the diff of your code and mine should show the obvious differences, you'll be able to figure out why I changed it easily: [cpp] #include <iostream> #include <string> #include <fstream> const size_t START_MEMORY = 30000; void runProgram(std::string& program, std::string& memory, size_t index) { for (size_t i = 0; i < program.size(); i++) { switch(program[i]) { default: break; case '>': index++; if (index >= memory.size() - 1) memory.push_back(0); break; case '<': index--; break; case '+': memory[index]++; break; case '-': memory[index]--; break; case '.': std::cout << memory[index]; break; case ',': std::cin >> memory[index]; break; case '[': std::string loop; i++; while (program[i] != ']') { loop.push_back(program[i]); i++; } while (memory[index]) { runProgram(loop, memory, index); } break; } } } int main(int argc, char *argv[]) { std::string memory(START_MEMORY, 0); std::string program, temp; std::ifstream file(argv[1]); if (argc != 2 ) { std::cin >> program; } else { //while (!file.eof()) while (std::getline(file, temp)) { program += temp; } } runProgram (program, memory, 0); cin.ignore(cin.rdbuf()->in_avail() + 1); return 0; } [/cpp] I didn't test everything so there might be minor errors - If you have any questions regarding the changes, let me know.
  • Hmm, I'm going to rewrite mine using a stack. Get the new version in the OP, it works even with loops in loops, and it includes the source files. For the lazy: [B]Main.cpp[/B] [cpp]// Written by James Allen. Use this code as you like, but do not claim it as your own #include "BrainFuckInterpreter.h" int main(int argc, char *argv[]) { BrainFuckInterpreter bf; if(argc != 2) { std::cout<<"The file could not be opened."; return 0; } bf.RunFile(argv[1]); getchar(); return 0; }[/cpp] [B]BrainFuckInterpreter.h[/B] [cpp]// Written by James Allen. Use this code as you like, but do not claim it as your own #ifndef BrainFuckInterpreter_h #define BrainFuckInterpreter_h #include <iostream> #include <fstream> #include <string> #include <vector> class BrainFuckInterpreter { public: void RunFile(std::string filename); protected: void RunLoop(std::string code); void RunChar(char command); std::vector<char> memory; int currentIndex; std::ifstream file; }; #endif[/cpp] [B]BrainFuckInterpreter.cpp[/B] [cpp]// Written by James Allen. Use this code as you like, but do not claim it as your own #include "BrainFuckInterpreter.h" void BrainFuckInterpreter::RunFile(std::string filename) { file.open(filename.c_str()); if(!file.is_open()) { std::cout<<"The file could not be opened."; return; } memory.push_back(0); currentIndex = 0; char cmd; while(!file.eof()) { file>> cmd; if(!file.eof()) RunChar(cmd); } } void BrainFuckInterpreter::RunLoop(std::string code) { while(memory[currentIndex] != 0) { for(int i = 0; i < code.size(); i++) { RunChar(code[i]); } } } void BrainFuckInterpreter::RunChar(char command) { switch(command) { case '+': if(memory[currentIndex] == 255) memory[currentIndex] = 0; else memory[currentIndex] += 1; break; case '-': if(memory[currentIndex] == 0) memory[currentIndex] = 255; else memory[currentIndex] -= 1; break; case '>': if(currentIndex == memory.size()-1) memory.push_back(0); currentIndex += 1; break; case '<': if(currentIndex != 0) currentIndex -= 1; break; case '.': std::cout<< memory[currentIndex]; break; case ',': std::cin>> memory[currentIndex]; break; case '[': std::string loopcode; char nextcmd = 'a'; bool makingLoop = true; while(makingLoop) { file>> nextcmd; if(nextcmd != ']' && nextcmd != '[') loopcode += nextcmd; if(nextcmd == '[') continue; else if( nextcmd == ']') makingLoop = false; } RunLoop(loopcode); break; } }[/cpp]
  • Thanks gparent, that does look prettier, but why use size_t? What exactly is it? Oh and what's the difference between reference and pointer? When do you use pointers and when references?
  • [QUOTE=noctune9;14205883]It doesn't seem to be. My unfixed program throws an debug assertion when incrementing memory_index to a value larger than the size of the vector and I read/write to it.[/QUOTE] Nope it's automatic with mine.
  • Well, noctune9 is using operator[], which doesn't do boundary checks I think. size_t is an unsigned int.
  • That shouldn't matter, try subtracting 1 from an unsigned integer set to 0, you'll just get a huge number, same with chars, don't know he's program doesn't do it.