1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
//! Simple brainfuck interpreter in Rust. //! //! The brainfuck language was created with the purpose of being a //! very minimal language which is very easy to write an interpreter //! for. This is one such interpreter. For more information on the //! brainfuck language start with the documentation of each //! [instruction in the language][instruction], or //! [some material online][brainfuck]. Brainfuck itself is syntactically //! challenging for humans, but is really not all that complicated. `+.` //! for example increments the value in the first cell and outputs that //! value. The instructions that trip people up the most are the control //! flow contructs `[` and `]`. `+++>,<[>+.<-]` for example prints the 3 //! values after the input value. For more about control flow in brainfuck //! read the section on [control flow][control-flow]. //! //! # Examples //! //! Basic usage. //! //! ``` //! use brainfuck; //! //! // Evaluate a simple brainfuck program from a string. //! brainfuck::eval_string("+>."); //! // Evaluate a brainfuck program from a file. //! brainfuck::eval_file("fixtures/helloworld.rs"); //! ``` //! //! Advanced usage, with specified tape type. //! //! ``` //! use std::io; //! use brainfuck::Interpreter; //! use brainfuck::program::Program; //! use brainfuck::tape::ArrayTape; //! //! let mut stdin = io::stdin(); //! let mut stdout = io::stdout(); //! let program = Program::parse("++>+.").unwrap(); //! let mut interp = Interpreter::<ArrayTape>::new(program, &mut stdin, &mut stdout); //! ``` //! //! # Semantics and Portability //! //! The brainfuck language has a few areas that are undefined behavior. All of //! the undefined behaviors in brainfuck are listed below: //! //! 1. The tape's length. //! 2. Moving the tape's pointer above or below the range of the tape. //! 3. The type of the values of the tape. //! 4. Incrementing or decrementing the value out of range. //! 5. Attempting to read input when there is no more input. //! 6. Programs containing unmatching brackets. //! //! For 1-4 see the tape's [documentation][tape]. New tape's can be created to //! give arbitrary semantics for these points. For 5 and 6, attempts to read //! when there are no more input values are ignored. Programs with unmatched //! brackets are invalid. //! //! [instruction]: enum.Instruction.html //! [brainfuck]: http://www.muppetlabs.com/~breadbox/bf/ //! [control-flow]: enum.Instruction.html#control-flow //! [instruction-docs]: enum.Instruction.html //! [tape]: tape/index.html #![feature(augmented_assignments)] #![deny(warnings)] use std::io; use std::path::Path; use tape::VecTape; use program::Program; /// The number of instructions allowed to execute before the interpreter /// errors with `Error::CycleLimit`. pub const CYCLE_LIMIT: u64 = 10000000; // Re-exports. pub use error::Error; pub use interpreter::Interpreter; pub use instruction::Instruction; /// Run the given program with STDIN and STDOUT as the IO buffers. fn eval(program: Program) -> Result<(), Error> { let mut stdin = io::stdin(); let mut stdout = io::stdout(); Interpreter::<VecTape>::new(program, &mut stdin, &mut stdout).run() } /// Parse a program from the given string and run it. /// /// This uses the dynamic `VecTape` implmentation, and reads and writes /// to `STDIN` and `STDOUT`. This covers the most common use case for brainfuck. /// /// ``` /// use brainfuck; /// /// brainfuck::eval_string("+>."); /// ``` pub fn eval_string(source: &str) -> Result<(), Error> { eval(try!(Program::parse(source))) } /// Parse a program from the given file path and run it. /// /// This uses the dynamic `VecTape` implmentation, and reads and writes /// to `STDIN` and `STDOUT`. This covers the most common use case for brainfuck. /// /// ``` /// use brainfuck; /// /// brainfuck::eval_file("fixtures/helloworld.rs"); /// ``` pub fn eval_file<P: AsRef<Path>>(path: P) -> Result<(), Error> { let program = try!(Program::from_file(path)); eval(program) } /// Brainfuck errors are the best kind of errors. mod error; /// Brainfuck interpreters are my favorite kind of interpreter. mod interpreter; /// Brainfuck instructions are the best kind of instructions. mod instruction; /// Data structure for the logic of a user brainfuck program. pub mod program; /// Underlying data structure for brainfuck programs. pub mod tape;