• Jallen's Brainfuck Interpreter
    72 replies, posted
Using size_t doesn't fix it. gparent didn't intend to fix it with that. You just use size_t for array- and container-indices.
I know I was just trying to demonstrate what you get when you subtract 1 from an unsigned type, don't know why your compiler doesn't like that.
[code]+.> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.> +.>[/code] This is fun.
I am not happy about it but here goes. [url]http://i43.tinypic.com/5pef0m.jpg[/url] [highlight]C#[/highlight] [b]Program.cs[/b] [cpp]using System; using System.Collections.Generic; using System.Text; namespace BrainfuckInterpreter { class Program { static void Main(string[] args) { BrainFuck.BFParser p = new BrainFuck.BFParser(); BrainFuck.Instruction[] ins = p.Parse( @"++++++++++ initialises cell zero to 10 [ >+++++++>++++++++++>+++>+<<<<- ] this loop sets the next four cells to 70/100/30/10 >++. print 'H' >+. print 'e' +++++++. 'l' . 'l' +++. 'o' >++. space <<+++++++++++++++. 'W' >. 'o' +++. 'r' ------. 'l' --------. 'd' >+. '!' >. newline "); BrainFuck.BFSystem bfs = new BrainFuck.BFSystem(); bfs.Execute(ins); Console.ReadKey(); } } } [/cpp] [b]BrainFuck.cs[/b] [cpp]using System; using System.Collections.Generic; using System.Text; namespace BrainFuck { public class BFParser { int Idx; public List<Instruction> Instructions; public BFParser() { Idx = 0; } public Instruction[] Parse(string str) { Instructions = new List<Instruction>(); Parse(str, false); if (Instructions.Count > 1) { Instructions[0].Next = Instructions[1]; for (int i = 1; i < Instructions.Count - 1; i++) { Instructions[i].Prev = Instructions[i - 1]; Instructions[i].Next = Instructions[i + 1]; } } return Instructions.ToArray(); } void Parse(string str, bool IsLoop) { for (; Idx < str.Length; Idx++) { if (str[Idx] == '[') { Instruction ins = Instruction.WhileStart.Clone() as Instruction; Instructions.Add(ins); Idx++; Parse(str, true); ins.Data = Instructions[Instructions.Count - 1]; Instructions[Instructions.Count - 1].Data = ins; } else if (str[Idx] == ']') { if (IsLoop) { Instructions.Add(Instruction.WhileEnd.Clone() as Instruction); return; } else { throw new Exception(string.Format("Missing [ before ({0})", Idx)); } } for (int i = 0; i < BFSystem.Instructions.Length; i++) { if (BFSystem.Instructions[i].Symbol == str[Idx].ToString()) { Instructions.Add(BFSystem.Instructions[i].Clone() as Instruction); } } } if (IsLoop) { throw new Exception(string.Format("Missing ] before (EOF)")); } } } public class BFSystem { public Dictionary<uint, byte> Data; public uint Pointer; public Instruction Current; public void Execute(Instruction[] instructs) { if (instructs.Length < 1) return; Data = new Dictionary<uint, byte>(); Pointer = 0; Current = instructs[0]; for (; Current != null; Current = Current.Next) { Current.Execute(this, Current); } } public static readonly Instruction[] Instructions = { Instruction.AddDataPtr, Instruction.SubDataPtr, Instruction.Increment, Instruction.Decrement, Instruction.PutChar, Instruction.GetChar, Instruction.WhileStart, Instruction.WhileEnd, }; } public class Instruction : ICloneable { public object Clone() { Instruction ins = new Instruction(Symbol, Data, Execute); ins.Next = this.Next; ins.Prev = this.Prev; return ins; } public override string ToString() { return Symbol; } public Instruction(string symbol, ExecuteD exe) : this(symbol, null, exe) { } public Instruction(string symbol, object data, ExecuteD exe) { Symbol = symbol; Data = data; Execute = exe; } public Instruction Prev; public Instruction Next; public object Data; public string Symbol; public ExecuteD Execute; public delegate void ExecuteD(BFSystem sys, Instruction self); public static readonly Instruction AddDataPtr = new Instruction(">", delegate(BFSystem sys, Instruction self) { sys.Pointer++; }); public static readonly Instruction SubDataPtr = new Instruction("<", delegate(BFSystem sys, Instruction self) { sys.Pointer--; }); public static readonly Instruction Increment = new Instruction("+", delegate(BFSystem sys, Instruction self) { if (!sys.Data.ContainsKey(sys.Pointer)) { sys.Data.Add(sys.Pointer, 0); } sys.Data[sys.Pointer]++; }); public static readonly Instruction Decrement = new Instruction("-", delegate(BFSystem sys, Instruction self) { if (!sys.Data.ContainsKey(sys.Pointer)) { sys.Data.Add(sys.Pointer, 0); } sys.Data[sys.Pointer]--; }); public static readonly Instruction PutChar = new Instruction(".", delegate(BFSystem sys, Instruction self) { if (!sys.Data.ContainsKey(sys.Pointer)) { Console.Write(0); } else { Console.Write((char)sys.Data[sys.Pointer]); } }); public static readonly Instruction GetChar = new Instruction(",", delegate(BFSystem sys, Instruction self) { if (!sys.Data.ContainsKey(sys.Pointer)) { sys.Data.Add(sys.Pointer, 0); } sys.Data[sys.Pointer] = (byte)Console.Read(); }); public static readonly Instruction WhileStart = new Instruction("[", delegate(BFSystem sys, Instruction self) { if (!sys.Data.ContainsKey(sys.Pointer) || sys.Data[sys.Pointer] == 0) { sys.Current = (self.Data as Instruction); } }); public static readonly Instruction WhileEnd = new Instruction("]", delegate(BFSystem sys, Instruction self) { if (sys.Data.ContainsKey(sys.Pointer) && sys.Data[sys.Pointer] != 0) { sys.Current = (self.Data as Instruction); } else { } }); } } [/cpp] If I was to rewrite it or put more effort into it I would... -Take the methods out of the Instruction class and give them their own class -Include a method that can be provided for special parsing -etc Really was just messing around applying the concept. Never tried it before.
[QUOTE=Sporbie;14216524]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] size_t is a type that can hold the largest size of an array, if I remember correctly. So vector indices, malloc()'s 2nd parameter, the return value of str.size(), everything that deep-down is handled by an array, will return size_t. As for references and pointers, I know the difference between them, however I'm not a great teacher. However, the basic is: A reference is similar to a pointer in that you are accessing an object that is not copied by value. A reference is different to a pointer in that you cannot assign a reference after it is initialized A reference cannot be NULL (Unless you try fairly hard IIRC) You don't need to use the -> operator with a reference, you use . instead. You use references whenever you can, and pointers whenever you can't. Start with a reference, if you can't do what you want with one (or if it requires a lot of extra code), use a pointer. As for the other few things I've changed: -Always use a const variable before using a #define if you can. const variables provide type safety, and they have a scope. -Added default case to the switch to fix a compiler warning -Changed every .at() to [] (Although I missed some, I edited my post to remove some more). The difference between .at() and [] is that .at() will throw an exception if you access an invalid indice. If you're not using try catch, it's pointless to use it. -Changed !file.eof() condition to the state of the stream. More explanation here: [url]http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5[/url] Let me know if you have more questions.
Haha, reminds me that I've made a Brainfuck compiler for my graphical calculator a long time ago. Compiles directly into executable machine code. It's way easier to do than an interpreter because most tokens are simple CPU instructions (increment, decrement), and loops in loops appear naturally when you make use of labels and jumps. On the other hand, console input and output were a pain in the ass to do because the CPU didn't have instructions to call a C function from assembly.
-snip-, nevermind.
[QUOTE=Sporbie;14218254]I know I was just trying to demonstrate what you get when you subtract 1 from an unsigned type, don't know why your compiler doesn't like that.[/QUOTE] It's not weired. If sizeof(unsigned int) is x, then you get the number 2^x-1.
sizeof() returns bytes, not bits.
Right. >.< If sizeof(unsigned int)*8 is x, then you get the number 2^x-1.
Jallen, for some reason your program doesn't work with this 99 bottles of beer program: [url]http://99-bottles-of-beer.net/download/101?PHPSESSID=3e25b4af1261bc9c699d327ee2983544[/url] Oh and I updated my program, now works with all kinds of loops and the above example, and yours doesn't, so that means I'm a better person than you, yeah (also you can just run the program and type in code, you don't have to drag and drop a text file, you can if you want to however): [url]http://www.speedyshare.com/511782933.html[/url]
[QUOTE=ZeekyHBomb;14219174]Right. >.< If sizeof(unsigned int)*8 is x, then you get the number 2^x-1.[/QUOTE] His implementation is entirely wrong anyway. char's signedness is implementation specific, and he's using integer literals instead of the numeric_limits<T>::min() and max() calls. (The latter doesn't matter as much as the former, though, since char is guaranteed to be 1 byte).
[QUOTE=Sporbie;14219178]Jallen, for some reason your program doesn't work with this 99 bottles of beer program: [url]http://99-bottles-of-beer.net/download/101?PHPSESSID=3e25b4af1261bc9c699d327ee2983544[/url] Oh and I updated my program, now works with all kinds of loops and the above example, and yours doesn't, so that means I'm a better person than you, yeah (also you can just run the program and type in code, you don't have to drag and drop a text file, you can if you want to however): [url]http://www.speedyshare.com/511782933.html[/url][/QUOTE] I can't be bothered to go through that whole program trying to find out why it's not working, but the interpreter seems to work for everything else i give to it... I don't know what it is in there that's killing it. Ok, I know why - fixing it.
I think I'll try one of my own interpreters now. Be right back.
Back: [cpp] #include <iostream> #include <fstream> #include <string> #include <vector> typedef std::vector<unsigned char> stack_t; const unsigned STACK_SIZE = 8092; // returns src index to continue running at at int run(const std::string &src, stack_t &stack, size_t &stackIdx, int srcIdx) { if (srcIdx < 0) return -1; // EOF int oldSrcIdx = srcIdx; // for looping while (srcIdx < src.size()) { switch (src[srcIdx]) { case '[': // run inner scope srcIdx = run(src, stack, stackIdx, srcIdx + 1); continue; break; case ']': if (stack[stackIdx]) { // if (not zero) loopp srcIdx = oldSrcIdx; continue; } else // else (zero) return to outer scope return srcIdx + 1; break; case '>': ++stackIdx; break; case '<': assert(stackIdx && "cannot < 0 stack idx"); --stackIdx; break; case '+': ++stack[stackIdx]; break; case '-': --stack[stackIdx]; break; case '.': std::cout << stack[stackIdx]; break; case ',': std::cin >> stack[stackIdx]; break; default: break; } ++srcIdx; } return -1; } int main(int argc, char **argv) { assert(argc == 2 && "usage: bf.exe file_to_interpret.extension"); std::ifstream in(argv[1]); assert(in && "file must be good"); std::string src, temp; // fill the src string from the file while (std::getline(in, temp)) src += temp; stack_t stack(STACK_SIZE, 0); size_t stackIdx = 0; run(src, stack, stackIdx, 0); // pause std::cin.ignore(std::cin.rdbuf()->in_avail() + 1); } [/cpp] Runs two hello world examples fine. [quote="Sporbie"] Jallen, for some reason your program doesn't work with this 99 bottles of beer program: [url]http://99-bottles-of-beer.net/downlo...9d327ee2983544[/url] Oh and I updated my program, now works with all kinds of loops and the above example, and yours doesn't, so that means I'm a better person than you, yeah (also you can just run the program and type in code, you don't have to drag and drop a text file, you can if you want to however): [url]http://www.speedyshare.com/511782933.html[/url] [/quote] Also runs this fine. It's nice and short, and was a good exercise to write. The only fallback to it is that I didn't do the primary non-zero check at the start of a loop, only at the end of a loop. Will add it later. (compile as console app and drag-and-drop a brainfuck source file onto it, like the linked 101-bottles.txt)
[url=http://www.iwriteiam.nl/Ha_bf_inter.html]There[/url]'s a Brainfuck-interpreter in Brainfuck.
[QUOTE=ZeekyHBomb;14225058][url=http://www.iwriteiam.nl/Ha_bf_inter.html]There[/url]'s a Brainfuck-interpreter in Brainfuck.[/QUOTE] Now that's brainfuck...
[QUOTE=BrokenGlass;14225326]Now that's brainfuck...[/QUOTE] No, it's "Brainfuck Brainfuck"
[url]http://forum.lolcode.com/viewtopic.php?id=51[/url] Some guy wrote a brainfuck interpreter in LOLCODE... [code]HAI BTW This is a BrainFuck interpreter written in LOLCode BTW It accepts as input a BF program, followed by a "!", followed by any input to the BF program. BTW Since BrainFuck is turing-complete, this proves that LOLCode is too I HAS A INSTRUCTIONS BTW Array for BF instructions I HAS A IPTR BTW Pointer to first empty element in INSTRUCTIONS LOL IPTR R 0 I HAS A LOOPZ BTW Array of loop start/end addresses I HAS A LOOPSTACKZ BTW Loop stack for building the above two I HAS A LSPTR BTW Pointer to first empty element of LOOPSTACKZ LOL LSPTR R 0 BTW Read in BF instructions, terminated with "!" IM IN YR CODE GIMMEH LETTAR IPTR IN MAH INSTRUCTIONS IZ IPTR IN MAH INSTRUCTIONS LIEK "["? LOL LSPTR IN MAH LOOPSTACKZ R IPTR UPZ LSPTR!! KTHX IZ IPTR IN MAH INSTRUCTIONS LIEK "]"? I HAS A STARTPTR NERFZ LSPTR!! LOL STARTPTR R LSPTR IN MAH LOOPSTACKZ LOL STARTPTR IN MAH LOOPZ R IPTR LOL IPTR IN MAH LOOPZ R STARTPTR KTHX IZ IPTR IN MAH INSTRUCTIONS LIEK "!"? GTFO NOWAI UPZ IPTR!! KTHX KTHX BTW Variables for BF's tape I HAS A LTAPE I HAS A RTAPE I HAS A LPTR LOL LPTR R 0 I HAS A RPTR LOL RPTR R 0 I HAS A CELL LOL CELL R 0 BTW Reset instruction pointer to start LOL IPTR R 0 BTW Start interpreting IM IN YR LOOP I HAS A THING LOL THING R IPTR IN MAH INSTRUCTIONS BTW Move tape head right IZ THING LIEK ">"? LOL LPTR IN MAH LTAPE R CELL UPZ LPTR!! IZ RPTR LIEK 0? LOL CELL R 0 NOWAI NERFZ RPTR!! LOL CELL R RPTR IN MAH RTAPE KTHX KTHX BTW Move tape head left IZ THING LIEK "<"? LOL RPTR IN MAH RTAPE R CELL UPZ RPTR!! IZ LPTR LIEK 0? LOL CELL R 0 NOWAI NERFZ LPTR!! LOL CELL R LPTR IN MAH LTAPE KTHX KTHX BTW Increment IZ THING LIEK "+"? UPZ CELL!! KTHX BTW Decrement IZ THING LIEK "-"? NERFZ CELL!! KTHX BTW Output produces numbers instead of ASCII characters IZ THING LIEK "."? VISIBLE CELL! VISIBLE " "! KTHX BTW Input doesn't work because we can't convert characters to integers BTW Oh well, it doesn't stop it being turing complete BTW Start of loop IZ THING LIEK "[" AND CELL LIEK 0? LOL IPTR R IPTR IN MAH LOOPZ KTHX BTW End of loop IZ THING LIEK "]" AND CELL NOT LIEK 0? LOL IPTR R IPTR IN MAH LOOPZ KTHX BTW End of program! IZ THING LIEK "!"? GTFO KTHX UPZ IPTR!! KTHX KTHXBYE[/code]
[QUOTE=DEADBEEF;14232665][url]http://forum.lolcode.com/viewtopic.php?id=51[/url] Some guy wrote a brainfuck interpreter in LOLCODE... [code]HAI BTW This is a BrainFuck interpreter written in LOLCode BTW It accepts as input a BF program, followed by a "!", followed by any input to the BF program. BTW Since BrainFuck is turing-complete, this proves that LOLCode is too I HAS A INSTRUCTIONS BTW Array for BF instructions I HAS A IPTR BTW Pointer to first empty element in INSTRUCTIONS LOL IPTR R 0 I HAS A LOOPZ BTW Array of loop start/end addresses I HAS A LOOPSTACKZ BTW Loop stack for building the above two I HAS A LSPTR BTW Pointer to first empty element of LOOPSTACKZ LOL LSPTR R 0 BTW Read in BF instructions, terminated with "!" IM IN YR CODE GIMMEH LETTAR IPTR IN MAH INSTRUCTIONS IZ IPTR IN MAH INSTRUCTIONS LIEK "["? LOL LSPTR IN MAH LOOPSTACKZ R IPTR UPZ LSPTR!! KTHX IZ IPTR IN MAH INSTRUCTIONS LIEK "]"? I HAS A STARTPTR NERFZ LSPTR!! LOL STARTPTR R LSPTR IN MAH LOOPSTACKZ LOL STARTPTR IN MAH LOOPZ R IPTR LOL IPTR IN MAH LOOPZ R STARTPTR KTHX IZ IPTR IN MAH INSTRUCTIONS LIEK "!"? GTFO NOWAI UPZ IPTR!! KTHX KTHX BTW Variables for BF's tape I HAS A LTAPE I HAS A RTAPE I HAS A LPTR LOL LPTR R 0 I HAS A RPTR LOL RPTR R 0 I HAS A CELL LOL CELL R 0 BTW Reset instruction pointer to start LOL IPTR R 0 BTW Start interpreting IM IN YR LOOP I HAS A THING LOL THING R IPTR IN MAH INSTRUCTIONS BTW Move tape head right IZ THING LIEK ">"? LOL LPTR IN MAH LTAPE R CELL UPZ LPTR!! IZ RPTR LIEK 0? LOL CELL R 0 NOWAI NERFZ RPTR!! LOL CELL R RPTR IN MAH RTAPE KTHX KTHX BTW Move tape head left IZ THING LIEK "<"? LOL RPTR IN MAH RTAPE R CELL UPZ RPTR!! IZ LPTR LIEK 0? LOL CELL R 0 NOWAI NERFZ LPTR!! LOL CELL R LPTR IN MAH LTAPE KTHX KTHX BTW Increment IZ THING LIEK "+"? UPZ CELL!! KTHX BTW Decrement IZ THING LIEK "-"? NERFZ CELL!! KTHX BTW Output produces numbers instead of ASCII characters IZ THING LIEK "."? VISIBLE CELL! VISIBLE " "! KTHX BTW Input doesn't work because we can't convert characters to integers BTW Oh well, it doesn't stop it being turing complete BTW Start of loop IZ THING LIEK "[" AND CELL LIEK 0? LOL IPTR R IPTR IN MAH LOOPZ KTHX BTW End of loop IZ THING LIEK "]" AND CELL NOT LIEK 0? LOL IPTR R IPTR IN MAH LOOPZ KTHX BTW End of program! IZ THING LIEK "!"? GTFO KTHX UPZ IPTR!! KTHX KTHXBYE[/code][/QUOTE] Now someone just have to write a lolcode interpreter in brainfuck and the circle would be complete.
[QUOTE=noctune9;14234784]Now someone just have to write a lolcode interpreter in brainfuck and the circle would be complete.[/QUOTE] D:!
Flash AS3 BF Intepreter (The program is hard-coded, will post better version tomorrow (it's 1 am here)). UNSUPPORTED MEDIA, use [url]http://spamtheweb.com/ul/upload/230309/4679_BrainFuck.php[/url]
[QUOTE=noctune9;14234784]Now someone just have to write a lolcode interpreter in brainfuck and the circle would be complete.[/QUOTE] And feed the LOLCode Brainfuck interpreter to it and run the LOLCode interpreter in the Brainfuck interpreter written in Brainfuck. But seriously, LOLCode should implement a Brainfuck call, similar to inline assembler in higher-level languages.
[QUOTE=itsbth;14260124]Flash AS3 BF Intepreter (The program is hard-coded, will post better version tomorrow (it's 1 am here)). UNSUPPORTED MEDIA, use [url]http://spamtheweb.com/ul/upload/230309/4679_BrainFuck.php[/url][/QUOTE] Awesome. Slow as hell though.
[QUOTE=DrDaxxy;14271637]And feed the LOLCode Brainfuck interpreter to it and run the LOLCode interpreter in the Brainfuck interpreter written in Brainfuck. But seriously, LOLCode should implement a Brainfuck call, similar to inline assembler in higher-level languages.[/QUOTE] It would probably be quite easily implement inline brainfuck into a lua interpreter.
I've just jumped on the brainfuck band wagon and created an interpreter in python! Though it reads from an input rather than a file. I don't have any ideas on how to implement loops, if anyone could explain how they did it I would be glad too know.
[QUOTE=iPope;14289012]I've just jumped on the brainfuck band wagon and created an interpreter in python! Though it reads from an input rather than a file. I don't have any ideas on how to implement loops, if anyone could explain how they did it I would be glad too know.[/QUOTE] Use recursion. Think of each piece of code as its own runnable piece. When you encounter a loop, that's another runnable piece within the upper 'parent' piece. It'd recurse like so: [code] run [whole] // encounter loop run [loop 0] // encounter another loop run [loop 1] // end condition not met, keep run this loop again and again run [loop 1] ... // end condition not met, run this loop again and again run [loop 0] .. // end condition for loop 0 is met, continue execution wherever loop 0 left off [/code] Notice how each iteration of the loop recurses if the loop must go on. There's no iteration or anything.
If that explanation doesn't do it for you, you can look at either my code (download at the top of the page) or nullsquared's, both use recursion, though nullsquared's method is alot more efficient than mine by the looks of it.
Isn't recursion an inherently bad idea for implementing a [B]loop[/B]? Without optimized tail calls, you can encounter a buffer overflow, and recursion isn't nice on memory usage.
[QUOTE=Robber;14272284]Awesome. Slow as hell though.[/QUOTE] It runs at one instruction per frame, at 30 frames per second. This is the program it's running: [code]++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.[/code] (It was the first result I found when searching for "BrainFuck hello world") PS: [code]def brainfuckize(str): out = ">\n" # Start with a zero to mark the end for c in str[::-1]: # Reverse over the characters in reverse direction out += ">" + ("+" * ord(c)) + "\n" # Write the chars ASCII value out += "[.<]" # The code that actually prints the string return out if __name__ == '__main__': import sys file = sys.stdin if len(sys.argv) == 2: file = open(sys.argv[1], "r") print brainfuckize(file.read())[/code]
Sorry, you need to Log In to post a reply to this thread.