Compare commits

..

No commits in common. "master" and "v0.1.0" have entirely different histories.

81 changed files with 930 additions and 18720 deletions

2
.gitattributes vendored
View file

@ -1,2 +0,0 @@
*.bf linguist-vendored
*.b linguist-vendored

View file

@ -1,17 +1,15 @@
# brainfuck # brainfuck
Brainfuck interpreters in different languages Brainfuck interpreters in different languages
Get the releases! Finished:
- Rust
Rust: CLI binary, in the release tab - Rust o1
Typescript: [react website](https://nilstrieb.github.io/brainfuck/) - Java
Finished: WIP:
- Rust - Rust o2
- Java
- Interactive TypeScript To-Do:
- Haskell
WIP: - TypeScript
- (JavaScript)
To-Do:
- Idris

View file

@ -1,2 +1,2 @@
.idea .idea
.stack-work .stack-work

16
bfi-haskell/.idea/.gitignore generated vendored
View file

@ -1,8 +1,8 @@
# Default ignored files # Default ignored files
/shelf/ /shelf/
/workspace.xml /workspace.xml
# Datasource local storage ignored files # Datasource local storage ignored files
/../../../../../../../:\Users\nilsh\IdeaProjects\brainfuck\bfi-haskell\.idea/dataSources/ /../../../../../../../:\Users\nilsh\IdeaProjects\brainfuck\bfi-haskell\.idea/dataSources/
/dataSources.local.xml /dataSources.local.xml
# Editor-based HTTP Client requests # Editor-based HTTP Client requests
/httpRequests/ /httpRequests/

View file

@ -1,11 +1,11 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="base-4.14.1.0"> <library name="base-4.14.1.0">
<CLASSES> <CLASSES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/base-4.14.1.0" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/base-4.14.1.0" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/base-4.14.1.0" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/base-4.14.1.0" />
</SOURCES> </SOURCES>
</library> </library>
</component> </component>

View file

@ -1,11 +1,11 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="ghc-prim-0.6.1"> <library name="ghc-prim-0.6.1">
<CLASSES> <CLASSES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/ghc-prim-0.6.1" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/ghc-prim-0.6.1" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/ghc-prim-0.6.1" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/ghc-prim-0.6.1" />
</SOURCES> </SOURCES>
</library> </library>
</component> </component>

View file

@ -1,11 +1,11 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="integer-gmp-1.0.3.0"> <library name="integer-gmp-1.0.3.0">
<CLASSES> <CLASSES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/integer-gmp-1.0.3.0" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/integer-gmp-1.0.3.0" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/integer-gmp-1.0.3.0" /> <root url="file://$USER_HOME$/AppData/Local/rikvdkleij/intellij-haskell/cache/lib/bfi-haskell/integer-gmp-1.0.3.0" />
</SOURCES> </SOURCES>
</library> </library>
</component> </component>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Haskell Tool Stack" project-jdk-type="Haskell Tool Stack SDK"> <component name="ProjectRootManager" version="2" project-jdk-name="Haskell Tool Stack" project-jdk-type="Haskell Tool Stack SDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/bfi-haskell.iml" filepath="$PROJECT_DIR$/bfi-haskell.iml" /> <module fileurl="file://$PROJECT_DIR$/bfi-haskell.iml" filepath="$PROJECT_DIR$/bfi-haskell.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" /> <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component> </component>
</project> </project>

View file

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="HASKELL_MODULE" version="4"> <module type="HASKELL_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.stack-work" /> <excludeFolder url="file://$MODULE_DIR$/.stack-work" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="base-4.14.1.0" level="project" /> <orderEntry type="library" name="base-4.14.1.0" level="project" />
<orderEntry type="library" name="ghc-prim-0.6.1" level="project" /> <orderEntry type="library" name="ghc-prim-0.6.1" level="project" />
<orderEntry type="library" name="integer-gmp-1.0.3.0" level="project" /> <orderEntry type="library" name="integer-gmp-1.0.3.0" level="project" />
</component> </component>
</module> </module>

View file

@ -1,11 +1,11 @@
++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++ ++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++
++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<++++<++++<++++>>>]++++ ++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<++++<++++<++++>>>]++++
+[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++ +[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++
++++>++++++>++++++++[-<++++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>--> ++++>++++++>++++++++[-<++++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>-->
---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+ ---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+
+++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[ +++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[
->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[-<+]->>>++++++++++<<[- ->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[-<+]->>>++++++++++<<[-
>+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]> >+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]>
+>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++ +>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++
+++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[ +++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[
-<+]-<<] -<+]-<<]

View file

@ -1,111 +1,111 @@
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Brainfuck { public class Brainfuck {
private static final int MEM_SIZE = 0xFFFF; private static final int MEM_SIZE = 0xFFFF;
public List<Character> minify(String program) { public List<Character> minify(String program) {
List<Character> chars = List.of('>', '<', '+', '-', '.', ',', '[', ']'); List<Character> chars = List.of('>', '<', '+', '-', '.', ',', '[', ']');
return program.chars().parallel() return program.chars()
.mapToObj(c -> (char) c) .mapToObj(c -> (char) c)
.filter(chars::contains) .filter(chars::contains)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public String interpret(List<Character> pgm) { public String interpret(List<Character> pgm) {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
int pointer = 0; int pointer = 0;
short[] memory = new short[MEM_SIZE]; short[] memory = new short[MEM_SIZE];
int pc = 0; int pc = 0;
while (pc < pgm.size()) { while (pc < pgm.size()) {
switch (pgm.get(pc)) { switch (pgm.get(pc)) {
case '>' -> { case '>' -> {
if (pointer == MEM_SIZE - 1) { if (pointer == MEM_SIZE - 1) {
pointer = 0; pointer = 0;
} else { } else {
pointer++; pointer++;
} }
} }
case '<' -> { case '<' -> {
if (pointer == 0) { if (pointer == 0) {
pointer = MEM_SIZE - 1; pointer = MEM_SIZE - 1;
} else { } else {
pointer--; pointer--;
} }
} }
case '+' -> increment(memory, pointer); case '+' -> increment(memory, pointer);
case '-' -> decrement(memory, pointer); case '-' -> decrement(memory, pointer);
case '.' -> { case '.' -> {
out.append((char) memory[pointer]); out.append((char) memory[pointer]);
} }
case ',' -> { case ',' -> {
} //todo implement i guess } //todo implement i guess
case '[' -> { case '[' -> {
if (memory[pointer] == 0) { if (memory[pointer] == 0) {
int level = 0; int level = 0;
while (pgm.get(pc) != ']' || level > -1) { while (pgm.get(pc) != ']' || level > -1) {
pc++; pc++;
char instruction = pgm.get(pc); char instruction = pgm.get(pc);
if (instruction == '[') level++; if (instruction == '[') level++;
else if (instruction == ']') level--; else if (instruction == ']') level--;
} }
} }
} }
case ']' -> { //error lies here case ']' -> { //error lies here
if (memory[pointer] != 0) { if (memory[pointer] != 0) {
int level = 0; int level = 0;
while (pgm.get(pc) != '[' || level > -1) { while (pgm.get(pc) != '[' || level > -1) {
pc--; pc--;
char instruction = pgm.get(pc); char instruction = pgm.get(pc);
if (instruction == '[') level--; if (instruction == '[') level--;
else if (instruction == ']') level++; else if (instruction == ']') level++;
} }
} }
} }
} }
pc++; pc++;
} }
return out.toString(); return out.toString();
} }
private void increment(short[] memory, int pointer) { private void increment(short[] memory, int pointer) {
if (memory[pointer] == 0xFF) { if (memory[pointer] == 0xFF) {
memory[pointer] = 0; memory[pointer] = 0;
} else { } else {
memory[pointer]++; memory[pointer]++;
} }
} }
private void decrement(short[] memory, int pointer) { private void decrement(short[] memory, int pointer) {
if (memory[pointer] == 0) { if (memory[pointer] == 0) {
memory[pointer] = 0xFF; memory[pointer] = 0xFF;
} else { } else {
memory[pointer]--; memory[pointer]--;
} }
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
Brainfuck brainfuck = new Brainfuck(); Brainfuck brainfuck = new Brainfuck();
if (args.length < 1) { if (args.length < 1) {
System.out.println("Please specify a path"); System.out.println("Please specify a path");
return; return;
} }
String program = Files.readString(Paths.get(args[0])); String program = Files.readString(Paths.get(args[0]));
List<Character> minified = brainfuck.minify(program); List<Character> minified = brainfuck.minify(program);
long time1 = System.currentTimeMillis(); long time1 = System.currentTimeMillis();
String result = brainfuck.interpret(minified); String result = brainfuck.interpret(minified);
long time = System.currentTimeMillis() - time1; long time = System.currentTimeMillis() - time1;
System.out.println(result); System.out.println(result);
System.out.println("Finished execution in " + time + "ms"); System.out.println("Finished execution in " + time + "ms");
} }
} }

8
bfi-rust/.gitignore vendored
View file

@ -1,3 +1,5 @@
/target /target
.idea .idea
# brainfuck testing code, get your own # brainfuck testing code, get your own
*.b
*.bf

2
bfi-rust/Cargo.lock generated
View file

@ -2,4 +2,4 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "bfinterpreter" name = "bfinterpreter"
version = "0.1.1" version = "0.1.0"

View file

@ -1,15 +1,13 @@
[package] [package]
name = "bfinterpreter" name = "bfinterpreter"
version = "0.1.1" version = "0.1.0"
authors = ["Nilstrieb <nilstrieb@gmail.com>"] authors = ["Nilstrieb <nilstrieb@gmail.com>"]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
[profile.release]
debug = true [profile.dev]
opt-level = 3
[profile.dev]
opt-level = 3

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 437 KiB

View file

@ -1,96 +1,96 @@
use crate::interpreter::optimized::PrintMode; use crate::interpreter::optimized::PrintMode;
use std::str::Chars; use std::str::Chars;
pub mod simple; pub mod simple;
pub mod parsed; pub mod parsed;
pub mod optimized; pub mod optimized;
pub const MEM_SIZE: usize = 0xFFFF; pub const MEM_SIZE: usize = 0xFFFF;
pub type Memory = [u8; MEM_SIZE]; pub type Memory = [u8; MEM_SIZE];
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Clone)] #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Clone)]
pub enum Statement { pub enum Statement {
Inc, Inc,
Dec, Dec,
R, R,
L, L,
Out, Out,
DOut, DOut,
In, In,
Loop(Vec<Statement>), Loop(Vec<Statement>),
} }
const ALLOWED_CHARS: [char; 8] = ['>', '<', '+', '-', '.', ',', '[', ']']; const ALLOWED_CHARS: [char; 8] = ['>', '<', '+', '-', '.', ',', '[', ']'];
pub fn minify(code: &str) -> String { pub fn minify(code: &str) -> String {
code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect() code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect()
} }
pub fn parse(chars: Chars, print_mode: PrintMode) -> Vec<Statement> { pub fn parse(chars: Chars, print_mode: PrintMode) -> Vec<Statement> {
let mut loop_stack = vec![vec![]]; let mut loop_stack = vec![vec![]];
for c in chars { for c in chars {
match c { match c {
'+' => loop_stack.last_mut().unwrap().push(Statement::Inc), '+' => loop_stack.last_mut().unwrap().push(Statement::Inc),
'-' => loop_stack.last_mut().unwrap().push(Statement::Dec), '-' => loop_stack.last_mut().unwrap().push(Statement::Dec),
'>' => loop_stack.last_mut().unwrap().push(Statement::R), '>' => loop_stack.last_mut().unwrap().push(Statement::R),
'<' => loop_stack.last_mut().unwrap().push(Statement::L), '<' => loop_stack.last_mut().unwrap().push(Statement::L),
'.' => { '.' => {
match print_mode { match print_mode {
PrintMode::ToString => loop_stack.last_mut().unwrap().push(Statement::Out), PrintMode::ToString => loop_stack.last_mut().unwrap().push(Statement::Out),
PrintMode::DirectPrint => loop_stack.last_mut().unwrap().push(Statement::DOut) PrintMode::DirectPrint => loop_stack.last_mut().unwrap().push(Statement::DOut)
} }
} }
',' => loop_stack.last_mut().unwrap().push(Statement::In), ',' => loop_stack.last_mut().unwrap().push(Statement::In),
'[' => loop_stack.push(vec![]), '[' => loop_stack.push(vec![]),
']' => { ']' => {
let statement = Statement::Loop(loop_stack.pop().unwrap()); let statement = Statement::Loop(loop_stack.pop().unwrap());
loop_stack.last_mut().unwrap().push(statement); loop_stack.last_mut().unwrap().push(statement);
} }
_ => () _ => ()
} }
} }
loop_stack.pop().unwrap() loop_stack.pop().unwrap()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::interpreter::{parse, minify}; use crate::interpreter::{parse, minify};
use crate::interpreter::Statement::{Dec, In, Inc, L, Loop, Out, R}; use crate::interpreter::Statement::{Dec, In, Inc, L, Loop, Out, R};
#[test] #[test]
fn minify_test() { fn minify_test() {
let program = "sdahf+saga-46<sgbv>a[r]r.hr,e"; let program = "sdahf+saga-46<sgbv>a[r]r.hr,e";
let expected = "+-<>[].,"; let expected = "+-<>[].,";
assert_eq!(String::from(expected), minify(program)); assert_eq!(String::from(expected), minify(program));
} }
#[test] #[test]
fn parse_no_loop() { fn parse_no_loop() {
let program = "+-<>,."; let program = "+-<>,.";
let statements = vec![Inc, Dec, L, R, In, Out]; let statements = vec![Inc, Dec, L, R, In, Out];
let result = parse(program.chars().collect(), false); let result = parse(program.chars().collect(), false);
assert_eq!(statements, result); assert_eq!(statements, result);
} }
#[test] #[test]
fn parse_simple_loop() { fn parse_simple_loop() {
let program = "+[<<]-"; let program = "+[<<]-";
let statements = vec![Inc, Loop(vec![L, L]), Dec]; let statements = vec![Inc, Loop(vec![L, L]), Dec];
let result = parse(program.chars().collect(), false); let result = parse(program.chars().collect(), false);
assert_eq!(statements, result); assert_eq!(statements, result);
} }
#[test] #[test]
fn parse_complex_loops() { fn parse_complex_loops() {
let program = ">[<[][<[<]>]>[>]]"; let program = ">[<[][<[<]>]>[>]]";
let statements = vec![R, Loop(vec![L, Loop(vec![]), Loop(vec![L, Loop(vec![L]), R]), R, Loop(vec![R])])]; let statements = vec![R, Loop(vec![L, Loop(vec![]), Loop(vec![L, Loop(vec![L]), R]), R, Loop(vec![R])])];
let result = parse(program.chars().collect(), false); let result = parse(program.chars().collect(), false);
assert_eq!(statements, result); assert_eq!(statements, result);
} }
} }

View file

@ -1,229 +1,229 @@
//! # optimization time //! # optimization time
//! some better optimizations like set null, repeating and doing more stuff with simplifying stuff //! some better optimizations like set null, repeating and doing more stuff with simplifying stuff
//! //!
mod patterns; mod patterns;
use std::io::{Read, stdin, Write}; use std::io::{Read, stdin, Write};
use crate::interpreter::{minify, parse, Statement, Memory, MEM_SIZE}; use crate::interpreter::{minify, parse, Statement, Memory, MEM_SIZE};
use std::error::Error; use std::error::Error;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fmt; use std::fmt;
use std::ops::Deref; use std::ops::Deref;
#[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Debug)] #[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Debug)]
enum ExStatement { enum ExStatement {
Inc, Inc,
Dec, Dec,
R, R,
L, L,
Out, Out,
DOut, DOut,
In, In,
Loop(Vec<ExStatement>), Loop(Vec<ExStatement>),
SetNull, SetNull,
Repeat(Box<ExStatement>, usize), Repeat(Box<ExStatement>, usize),
_ForLoop(usize, Box<ExStatement>), _ForLoop(usize, Box<ExStatement>),
} }
impl From<Statement> for ExStatement { impl From<Statement> for ExStatement {
fn from(s: Statement) -> Self { fn from(s: Statement) -> Self {
match s { match s {
Statement::L => ExStatement::L, Statement::L => ExStatement::L,
Statement::R => ExStatement::R, Statement::R => ExStatement::R,
Statement::Inc => ExStatement::Inc, Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec, Statement::Dec => ExStatement::Dec,
Statement::In => ExStatement::In, Statement::In => ExStatement::In,
Statement::Out => ExStatement::Out, Statement::Out => ExStatement::Out,
Statement::Loop(v) => ExStatement::Loop( Statement::Loop(v) => ExStatement::Loop(
v.into_iter().map(ExStatement::from).collect() v.into_iter().map(ExStatement::from).collect()
), ),
Statement::DOut => ExStatement::DOut Statement::DOut => ExStatement::DOut
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct BfErr { pub struct BfErr {
msg: &'static str, msg: &'static str,
} }
impl BfErr { impl BfErr {
pub fn new(msg: &'static str) -> BfErr { pub fn new(msg: &'static str) -> BfErr {
BfErr { msg } BfErr { msg }
} }
} }
impl Display for BfErr { impl Display for BfErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Error interpreting brainfuck code: {}", self.msg) write!(f, "Error interpreting brainfuck code: {}", self.msg)
} }
} }
impl Error for BfErr {} impl Error for BfErr {}
pub enum PrintMode { pub enum PrintMode {
ToString, ToString,
DirectPrint, DirectPrint,
} }
pub fn run(pgm: &str, print_mode: PrintMode) -> Result<String, BfErr> { pub fn run(pgm: &str, print_mode: PrintMode) -> Result<String, BfErr> {
let pgm = minify(pgm); let pgm = minify(pgm);
if pgm.is_empty() { return Err(BfErr::new("no program found")); }; if pgm.is_empty() { return Err(BfErr::new("no program found")); };
let pgm = parse(pgm.chars(), print_mode); let pgm = parse(pgm.chars(), print_mode);
let pgm = optimize(&pgm); let pgm = optimize(&pgm);
let out = interpret(&pgm); let out = interpret(&pgm);
Ok(out) Ok(out)
} }
fn optimize(code: &[Statement]) -> Vec<ExStatement> { fn optimize(code: &[Statement]) -> Vec<ExStatement> {
let code = o_set_null(code); let code = o_set_null(code);
o_repeat(code) o_repeat(code)
} }
fn o_set_null(code: &[Statement]) -> Vec<ExStatement> { fn o_set_null(code: &[Statement]) -> Vec<ExStatement> {
code.iter().map(|s| { code.iter().map(|s| {
match s { match s {
Statement::Loop(v) => { Statement::Loop(v) => {
if let [Statement::Dec] = v[..] { if let [Statement::Dec] = v[..] {
ExStatement::SetNull ExStatement::SetNull
} else { } else {
ExStatement::Loop(optimize(v)) ExStatement::Loop(optimize(v))
} }
} }
Statement::Inc => ExStatement::Inc, Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec, Statement::Dec => ExStatement::Dec,
Statement::R => ExStatement::R, Statement::R => ExStatement::R,
Statement::L => ExStatement::L, Statement::L => ExStatement::L,
Statement::Out => ExStatement::Out, Statement::Out => ExStatement::Out,
Statement::DOut => ExStatement::DOut, Statement::DOut => ExStatement::DOut,
Statement::In => ExStatement::In, Statement::In => ExStatement::In,
} }
}).collect() }).collect()
} }
fn o_repeat(code: Vec<ExStatement>) -> Vec<ExStatement> { fn o_repeat(code: Vec<ExStatement>) -> Vec<ExStatement> {
let mut amount = 0; let mut amount = 0;
let mut result: Vec<ExStatement> = vec![]; let mut result: Vec<ExStatement> = vec![];
for i in 0..code.len() { for i in 0..code.len() {
if code.get(i) == code.get(i + 1) { if code.get(i) == code.get(i + 1) {
amount += 1; amount += 1;
} else if amount == 0 { } else if amount == 0 {
result.push(code[i].clone()) result.push(code[i].clone())
} else { } else {
amount += 1; amount += 1;
result.push(ExStatement::Repeat(Box::new(code[i].clone()), amount as usize)); result.push(ExStatement::Repeat(Box::new(code[i].clone()), amount as usize));
amount = 0; amount = 0;
} }
} }
result result
} }
fn interpret(pgm: &[ExStatement]) -> String { fn interpret(pgm: &[ExStatement]) -> String {
let mut out = String::new(); let mut out = String::new();
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE]; let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm { for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out) execute(s, &mut mem, &mut pointer, &mut out)
} }
out out
} }
fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out: &mut String) { fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement { match statement {
ExStatement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 }, ExStatement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
ExStatement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 }, ExStatement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1), ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1), ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
ExStatement::SetNull => mem[*pointer] = 0, ExStatement::SetNull => mem[*pointer] = 0,
ExStatement::Out => out.push(mem[*pointer] as u8 as char), ExStatement::Out => out.push(mem[*pointer] as u8 as char),
ExStatement::DOut => { ExStatement::DOut => {
print!("{}", mem[*pointer] as u8 as char); print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap(); std::io::stdout().flush().unwrap();
} }
ExStatement::In => { ExStatement::In => {
let mut in_buffer = [0, 1]; let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap(); stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8; mem[*pointer] = in_buffer[0] as u8;
} }
ExStatement::Loop(vec) => { ExStatement::Loop(vec) => {
while mem[*pointer] != 0 { while mem[*pointer] != 0 {
for s in vec { for s in vec {
execute(&s, mem, pointer, out); execute(&s, mem, pointer, out);
} }
} }
} }
ExStatement::Repeat(statement, amount) => { ExStatement::Repeat(statement, amount) => {
match statement.deref() { match statement.deref() {
ExStatement::R => { ExStatement::R => {
*pointer += amount; *pointer += amount;
if *pointer > MEM_SIZE { if *pointer > MEM_SIZE {
*pointer %= MEM_SIZE *pointer %= MEM_SIZE
} }
} }
ExStatement::L => *pointer = (*pointer).wrapping_sub(*amount), ExStatement::L => *pointer = (*pointer).wrapping_sub(*amount),
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(*amount as u8), ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(*amount as u8),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(*amount as u8), ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(*amount as u8),
ExStatement::Loop(v) => { ExStatement::Loop(v) => {
for _ in 0..*amount { for _ in 0..*amount {
execute(&ExStatement::Loop(v.clone()), mem, pointer, out) execute(&ExStatement::Loop(v.clone()), mem, pointer, out)
} }
} }
s => { s => {
for _ in 0..*amount { for _ in 0..*amount {
execute(s, mem, pointer, out) execute(s, mem, pointer, out)
} }
} }
} }
} }
ExStatement::_ForLoop(offset, statement) => { ExStatement::_ForLoop(offset, statement) => {
*pointer += offset; *pointer += offset;
while mem[*pointer - offset] != 0 { while mem[*pointer - offset] != 0 {
execute(statement, mem, pointer, out); execute(statement, mem, pointer, out);
} }
} }
}; };
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::interpreter::optimized::{run, o_repeat}; use crate::interpreter::optimized::{run, o_repeat};
use crate::interpreter::optimized::ExStatement::{Inc, Repeat, R, L, Dec}; use crate::interpreter::optimized::ExStatement::{Inc, Repeat, R, L, Dec};
#[test] #[test]
fn run_loop() { fn run_loop() {
let program = "++++++++++[>++++++++++<-]>."; let program = "++++++++++[>++++++++++<-]>.";
let out = run(program, false).unwrap(); let out = run(program, false).unwrap();
assert_eq!(out, String::from("d")); assert_eq!(out, String::from("d"));
} }
#[test] #[test]
fn hello_world() { fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program, false).unwrap(); let out = run(program, false).unwrap();
assert_eq!(out, String::from("Hello World!\n")); assert_eq!(out, String::from("Hello World!\n"));
} }
#[test] #[test]
fn o_repeat_simple() { fn o_repeat_simple() {
let code = vec![Inc, Inc, Inc, R]; let code = vec![Inc, Inc, Inc, R];
let expected = vec![Repeat(Box::new(Inc), 3), R]; let expected = vec![Repeat(Box::new(Inc), 3), R];
println!("{}", code.len()); println!("{}", code.len());
assert_eq!(expected, o_repeat(code)); assert_eq!(expected, o_repeat(code));
} }
#[test] #[test]
fn o_repeat_long() { fn o_repeat_long() {
let code = vec![Inc, Inc, Inc, R, L, L, L, Dec, L, L, Dec]; let code = vec![Inc, Inc, Inc, R, L, L, L, Dec, L, L, Dec];
let expected = vec![Repeat(Box::new(Inc), 3), R, Repeat(Box::new(L), 3), Dec, Repeat(Box::new(L), 2), Dec]; let expected = vec![Repeat(Box::new(Inc), 3), R, Repeat(Box::new(L), 3), Dec, Repeat(Box::new(L), 2), Dec];
assert_eq!(expected, o_repeat(code)); assert_eq!(expected, o_repeat(code));
} }
} }

View file

@ -1,43 +1,43 @@
//! //!
//! # Patterns find and replace //! # Patterns find and replace
//! Pattern-match ExStatements and replace them with optimizations like add, multiply etc //! Pattern-match ExStatements and replace them with optimizations like add, multiply etc
use crate::interpreter::optimized::ExStatement; use crate::interpreter::optimized::ExStatement;
/// ///
/// Replace this: `[>>x<<-]` or `[->>x<<]` with `WhileAdd(2, x)` /// Replace this: `[>>x<<-]` or `[->>x<<]` with `WhileAdd(2, x)`
fn _for_loop(to_test: ExStatement) -> ExStatement { fn _for_loop(to_test: ExStatement) -> ExStatement {
match to_test { match to_test {
ExStatement::Loop(v) => { ExStatement::Loop(v) => {
match v[..] { match v[..] {
[ExStatement::R, ExStatement::Inc, ExStatement::L, ExStatement::Dec] => { [ExStatement::R, ExStatement::Inc, ExStatement::L, ExStatement::Dec] => {
ExStatement::_ForLoop(1, Box::from(ExStatement::Inc)) ExStatement::_ForLoop(1, Box::from(ExStatement::Inc))
} }
_ => ExStatement::Loop(v) _ => ExStatement::Loop(v)
} }
}, },
s => s s => s
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, _ForLoop}; use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, _ForLoop};
use crate::interpreter::optimized::patterns::_for_loop; use crate::interpreter::optimized::patterns::_for_loop;
#[test] #[test]
fn for_loop_false() { fn for_loop_false() {
let statement = Loop(vec![Out, Inc]); let statement = Loop(vec![Out, Inc]);
assert_eq!(statement.clone(), _for_loop(statement)); assert_eq!(statement.clone(), _for_loop(statement));
} }
#[test] #[test]
fn for_loop_simplest() { fn for_loop_simplest() {
let statement = Loop(vec![R, Inc, L, Dec]); let statement = Loop(vec![R, Inc, L, Dec]);
assert_eq!(_ForLoop(1, Box::from(Inc)), _for_loop(statement)); assert_eq!(_ForLoop(1, Box::from(Inc)), _for_loop(statement));
} }
} }

View file

@ -1,122 +1,122 @@
//! //!
//! # optimization time //! # optimization time
//! //!
//! first parse the bf so that it can be executed faster //! first parse the bf so that it can be executed faster
//! most importantly: loop jumps should be immediate //! most importantly: loop jumps should be immediate
#![allow(dead_code)] #![allow(dead_code)]
use std::io::{Read, stdin, Write}; use std::io::{Read, stdin, Write};
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement}; use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement};
use crate::interpreter::optimized::PrintMode; use crate::interpreter::optimized::PrintMode;
use crate::repl::BrainfuckState; use crate::repl::BrainfuckState;
pub fn run(pgm: &str) -> String { pub fn run(pgm: &str) -> String {
let pgm = minify(pgm); let pgm = minify(pgm);
let pgm = parse(pgm.chars(), PrintMode::ToString); let pgm = parse(pgm.chars(), PrintMode::ToString);
interpret(&pgm) interpret(&pgm)
} }
fn interpret(pgm: &[Statement]) -> String { fn interpret(pgm: &[Statement]) -> String {
let mut out = String::new(); let mut out = String::new();
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE]; let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm { for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out) execute(s, &mut mem, &mut pointer, &mut out)
} }
out out
} }
pub fn interpret_with_state(pgm: &[Statement], state: &mut BrainfuckState) { pub fn interpret_with_state(pgm: &[Statement], state: &mut BrainfuckState) {
for s in pgm { for s in pgm {
execute(s, &mut state.memory, &mut state.pointer, &mut String::new()) execute(s, &mut state.memory, &mut state.pointer, &mut String::new())
} }
} }
fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &mut String) { fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement { match statement {
Statement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 }, Statement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 }, Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1), Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1), Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
Statement::Out => out.push(mem[*pointer] as u8 as char), Statement::Out => out.push(mem[*pointer] as u8 as char),
Statement::In => { Statement::In => {
let mut in_buffer = [0, 1]; let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap(); stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8; mem[*pointer] = in_buffer[0] as u8;
} }
Statement::Loop(vec) => { Statement::Loop(vec) => {
while mem[*pointer] != 0 { while mem[*pointer] != 0 {
for s in vec { for s in vec {
execute(&s, mem, pointer, out); execute(&s, mem, pointer, out);
} }
} }
} }
Statement::DOut => { Statement::DOut => {
print!("{}", mem[*pointer] as u8 as char); print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap(); std::io::stdout().flush().unwrap();
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::interpreter::parsed::{execute, run, Statement}; use crate::interpreter::parsed::{execute, run, Statement};
#[test] #[test]
fn execute_simple() { fn execute_simple() {
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535]; let mut mem: [u8; 65535] = [0; 65535];
let mut out = String::new(); let mut out = String::new();
execute(&Statement::R, &mut mem, &mut pointer, &mut out); execute(&Statement::R, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 1); assert_eq!(pointer, 1);
execute(&Statement::L, &mut mem, &mut pointer, &mut out); execute(&Statement::L, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 0); assert_eq!(pointer, 0);
execute(&Statement::Inc, &mut mem, &mut pointer, &mut out); execute(&Statement::Inc, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 1); assert_eq!(mem[pointer], 1);
execute(&Statement::Dec, &mut mem, &mut pointer, &mut out); execute(&Statement::Dec, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 0); assert_eq!(mem[pointer], 0);
} }
#[test] #[test]
fn execute_false_loop() { fn execute_false_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]); let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535]; let mut mem: [u8; 65535] = [0; 65535];
execute(&statement, &mut mem, &mut pointer, &mut String::new()); execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 0); assert_eq!(mem[0], 0);
assert_eq!(mem[1], 0); assert_eq!(mem[1], 0);
} }
#[test] #[test]
fn execute_loop() { fn execute_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]); let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535]; let mut mem: [u8; 65535] = [0; 65535];
mem[0] = 1; mem[0] = 1;
execute(&statement, &mut mem, &mut pointer, &mut String::new()); execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 3); assert_eq!(mem[0], 3);
assert_eq!(mem[1], 0); assert_eq!(mem[1], 0);
} }
#[test] #[test]
fn run_loop() { fn run_loop() {
let program = "++++++++++[>++++++++++<-]>."; let program = "++++++++++[>++++++++++<-]>.";
let out = run(program); let out = run(program);
assert_eq!(out, String::from("d")); assert_eq!(out, String::from("d"));
} }
#[test] #[test]
fn hello_world() { fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program); let out = run(program);
assert_eq!(out, String::from("Hello World!\n")); assert_eq!(out, String::from("Hello World!\n"));
} }
} }

View file

@ -1,71 +1,71 @@
//! //!
//! The very basic interpreter without any optimizations //! The very basic interpreter without any optimizations
#![allow(dead_code)] #![allow(dead_code)]
use crate::interpreter::{MEM_SIZE, minify}; use crate::interpreter::{MEM_SIZE, minify};
use std::io::{stdin, Read}; use std::io::{stdin, Read};
pub fn run(program: &str) -> String{ pub fn run(program: &str) -> String{
let program = minify(program); let program = minify(program);
let out = interpret(program.chars().collect()); let out = interpret(program.chars().collect());
out out
} }
fn interpret(pgm: Vec<char>) -> String { fn interpret(pgm: Vec<char>) -> String {
let mut out = String::new(); let mut out = String::new();
let mut pointer: usize = 0; let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE]; let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
let mut in_buffer = [0; 1]; let mut in_buffer = [0; 1];
let mut pc = 0; let mut pc = 0;
let len = pgm.len(); let len = pgm.len();
while pc < len { while pc < len {
match pgm[pc] { match pgm[pc] {
'>' => if pointer == MEM_SIZE - 1 { pointer = 0 } else { pointer += 1 }, '>' => if pointer == MEM_SIZE - 1 { pointer = 0 } else { pointer += 1 },
'<' => if pointer == 0 { pointer = MEM_SIZE - 1 } else { pointer -= 1 }, '<' => if pointer == 0 { pointer = MEM_SIZE - 1 } else { pointer -= 1 },
'+' => mem[pointer] = mem[pointer].wrapping_add(1), '+' => mem[pointer] = mem[pointer].wrapping_add(1),
'-' => mem[pointer] = mem[pointer].wrapping_sub(1), '-' => mem[pointer] = mem[pointer].wrapping_sub(1),
'.' => out.push(mem[pointer] as u8 as char), '.' => out.push(mem[pointer] as u8 as char),
',' => { ',' => {
stdin().read_exact(&mut in_buffer).unwrap(); stdin().read_exact(&mut in_buffer).unwrap();
mem[pointer] = in_buffer[0] as u8; mem[pointer] = in_buffer[0] as u8;
} }
'[' => { '[' => {
//jump to corresponding ] //jump to corresponding ]
if mem[pointer] == 0 { if mem[pointer] == 0 {
let mut level = 0; let mut level = 0;
while pgm[pc] != ']' || level > -1 { while pgm[pc] != ']' || level > -1 {
pc += 1; pc += 1;
match pgm[pc] { match pgm[pc] {
'[' => { '[' => {
level += 1 level += 1
} }
']' => { ']' => {
level -= 1 level -= 1
} }
_ => (), _ => (),
} }
} }
} }
} }
']' => { ']' => {
if mem[pointer] != 0 { if mem[pointer] != 0 {
//jump to corresponding [ //jump to corresponding [
let mut level = 0; let mut level = 0;
while pgm[pc] != '[' || level > -1 { while pgm[pc] != '[' || level > -1 {
pc -= 1; pc -= 1;
match pgm[pc] { match pgm[pc] {
'[' => level -= 1, '[' => level -= 1,
']' => level += 1, ']' => level += 1,
_ => (), _ => (),
} }
} }
} }
} }
_ => (), _ => (),
} }
pc += 1; pc += 1;
} }
out out
} }

View file

@ -1,37 +1,37 @@
mod interpreter; mod interpreter;
mod repl; mod repl;
use std::{env, fs}; use std::{env, fs};
use std::time::SystemTime; use std::time::SystemTime;
use crate::repl::start_repl; use crate::repl::start_repl;
use crate::interpreter::optimized::{PrintMode}; use crate::interpreter::optimized::{PrintMode};
use std::error::Error; use std::error::Error;
fn main() { fn main() {
let path = env::args().nth(1); let path = env::args().nth(1);
match path { match path {
Some(p) => { Some(p) => {
if let Err(why) = run_program(p) { if let Err(why) = run_program(p) {
eprintln!("An error occurred in the program: {}", why) eprintln!("An error occurred in the program: {}", why)
} }
}, },
None => start_repl() None => start_repl()
}; };
} }
fn run_program(path: String) -> Result<(), Box<dyn Error>> { fn run_program(path: String) -> Result<(), Box<dyn Error>> {
let program = match fs::read_to_string(path) { let program = match fs::read_to_string(path) {
Ok(p) => p, Ok(p) => p,
Err(e) => { Err(e) => {
println!("Error reading file: {}", e); println!("Error reading file: {}", e);
return Err(Box::from(e)); return Err(Box::from(e));
} }
}; };
let start_time = SystemTime::now(); let start_time = SystemTime::now();
let out = interpreter::optimized::run(&*program, PrintMode::DirectPrint)?; let out = interpreter::optimized::run(&*program, PrintMode::DirectPrint)?;
let duration = start_time.elapsed()?; let duration = start_time.elapsed()?;
println!("{}\nFinished execution. Took {}ms", out, duration.as_millis()); println!("{}\nFinished execution. Took {}ms", out, duration.as_millis());
Ok(()) Ok(())
} }

View file

@ -1,111 +1,111 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fmt; use std::fmt;
use std::io::{stdin, stdout, Write}; use std::io::{stdin, stdout, Write};
use crate::interpreter::{minify, parse, parsed, Memory, MEM_SIZE}; use crate::interpreter::{minify, parse, parsed, Memory, MEM_SIZE};
use crate::interpreter::optimized::PrintMode; use crate::interpreter::optimized::PrintMode;
pub struct BrainfuckState { pub struct BrainfuckState {
pub memory: Memory, pub memory: Memory,
pub pointer: usize, pub pointer: usize,
} }
impl Display for BrainfuckState { impl Display for BrainfuckState {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", display_state(self)) write!(f, "{}", display_state(self))
} }
} }
fn display_state(state: &BrainfuckState) -> String { fn display_state(state: &BrainfuckState) -> String {
let start = if state.pointer < 5 { let start = if state.pointer < 5 {
0 0
} else if state.pointer > MEM_SIZE - 10 { } else if state.pointer > MEM_SIZE - 10 {
MEM_SIZE - 10 MEM_SIZE - 10
} else { } else {
state.pointer - 5 state.pointer - 5
}; };
format!("{}-\n|{}|\n{}-\n{}|\n{}|\n{}|\n{}-\n {}^^^^", format!("{}-\n|{}|\n{}-\n{}|\n{}|\n{}|\n{}-\n {}^^^^",
"----------".repeat(10), "----------".repeat(10),
{ {
let mut out = String::new(); let mut out = String::new();
let end = start + 10; let end = start + 10;
for i in start..end { for i in start..end {
out.push_str(&*format!(" {: >5} ", i)); out.push_str(&*format!(" {: >5} ", i));
} }
out out
}, },
"----------".repeat(10), "----------".repeat(10),
"| ".repeat(10), "| ".repeat(10),
{ {
let mut out = String::new(); let mut out = String::new();
let end = start + 10; let end = start + 10;
for i in start..end { for i in start..end {
out.push_str(&*format!("| {: >3} ", state.memory[i])); out.push_str(&*format!("| {: >3} ", state.memory[i]));
} }
out out
}, },
"| ".repeat(10), "| ".repeat(10),
"----------".repeat(10), "----------".repeat(10),
" ".repeat(state.pointer - start)) " ".repeat(state.pointer - start))
} }
pub fn start_repl() { pub fn start_repl() {
println!("Brainfuck REPL"); println!("Brainfuck REPL");
let mut state = BrainfuckState { let mut state = BrainfuckState {
memory: [0; MEM_SIZE], memory: [0; MEM_SIZE],
pointer: 0, pointer: 0,
}; };
println!("Enter Brainfuck programs and they will be executed immediatly."); println!("Enter Brainfuck programs and they will be executed immediatly.");
println!("State is kept."); println!("State is kept.");
println!("{}", state); println!("{}", state);
loop { loop {
print!(">> "); print!(">> ");
stdout().flush().unwrap(); stdout().flush().unwrap();
match read_line() { match read_line() {
Ok(s) => { Ok(s) => {
match &*s { match &*s {
":q" => break, ":q" => break,
":?" | "help" | "?" => print_help(), ":?" | "help" | "?" => print_help(),
":r" => { ":r" => {
reset(&mut state); reset(&mut state);
println!("{}", state); println!("{}", state);
}, },
_ => { _ => {
print!("Output: "); print!("Output: ");
println!(); println!();
parse_input(s, &mut state); parse_input(s, &mut state);
println!("{}", state); println!("{}", state);
} }
} }
} }
Err(why) => println!("Error reading input: {}\nPlease try again.", why) Err(why) => println!("Error reading input: {}\nPlease try again.", why)
} }
} }
} }
fn reset(state: &mut BrainfuckState) { fn reset(state: &mut BrainfuckState) {
state.pointer = 0; state.pointer = 0;
state.memory = [0; MEM_SIZE]; state.memory = [0; MEM_SIZE];
} }
fn print_help() { fn print_help() {
println!("Brainfuck REPL help println!("Brainfuck REPL help
:q => quit :q => quit
:? => help :? => help
:r => reset state"); :r => reset state");
} }
fn parse_input(pgm: String, state: &mut BrainfuckState) { fn parse_input(pgm: String, state: &mut BrainfuckState) {
let pgm = minify(&*pgm); let pgm = minify(&*pgm);
let pgm = parse(pgm.chars(), PrintMode::DirectPrint); let pgm = parse(pgm.chars(), PrintMode::DirectPrint);
parsed::interpret_with_state(&*pgm, state); parsed::interpret_with_state(&*pgm, state);
} }
pub fn read_line() -> Result<String, std::io::Error> { pub fn read_line() -> Result<String, std::io::Error> {
let mut buf = String::new(); let mut buf = String::new();
stdin().read_line(&mut buf)?; stdin().read_line(&mut buf)?;
buf.pop(); buf.pop();
Ok(buf) Ok(buf)
} }

23
ibfi-ts/.gitignore vendored
View file

@ -1,23 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View file

@ -1,27 +0,0 @@
# Interactive Brainfuck Interpreter in React TS
This is an interactive interpreter for the brainfuck programming language.
It provides simple brainfuck execution, along with a view of the memory, the memory pointer, the current state of the
code and more.
It is great for debugging brainfuck programs, including a memory view, program view, the location of the pointers, the
ability to directly edit memory.
You can step manually through the program, or set the execution speed to whatever speed fits best.
This interpreter also has the ability to set breakpoints using the • symbol. This means you can let your code run fast and
stopping it at any point in your program to see what went wrong.
## Features
* brainfuck execution including IO
* memory view
* code state view
* manual stepping
* breakpoints
* error messages
* seeing ASCII characters in memory
* manual code input
* fast excecution mode (no debugging info)
### Future features
* none-blocking fast excecution mode
* better speed control
* (limited) backstepping

View file

@ -1,50 +0,0 @@
{
"name": "ibfi-ts",
"version": "0.1.0",
"homepage": "https://nilstrieb.github.io/brainfuck",
"private": false,
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"node-sass": "^6.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"sass": "^1.35.1",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "yarn build && gh-pages -d build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"gh-pages": "^3.2.3"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Interactive Brainfuck Interpreter"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Brainfuck Interpreter</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View file

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View file

@ -1,128 +0,0 @@
$main-color: #282c34;
$main-color-brighter: #323942;
$light-color: ghostwhite;
$medium-color: #78787f;
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
.App-header {
background-color: $main-color;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: $light-color;
}
.App-link {
color: #61dafb;
}
.bf-input {
.code-input {
resize: none;
width: 80vw;
height: 400px;
font-size: 100px;
}
.code-options-wrapper > * {
margin: 10px;
}
}
.code-display-wrapper {
max-width: 80vw;
font-family: monospace;
span {
word-wrap: break-word;
}
}
.memory-display-table {
$border: 1px solid $light-color;
th, .cell {
border: $border;
}
th, td {
min-width: 60px;
text-align: center;
}
.array-set-value-field {
min-width: 50px;
max-width: 100px;
height: 40px;
color: $light-color;
font-size: 30px;
background-color: $main-color-brighter;
}
}
.run-button {
height: 50px;
width: 200px;
}
.bf-run {
margin: 20px;
.speed-control-wrapper > * {
margin: 10px;
}
.small-speed-button {
height: 40px;
width: 40px;
}
.program-input-area {
resize: none;
width: 80vw;
height: 50px;
font-size: 30px;
}
.info {
background-color: #579ca7;
}
}
.bf-output {
.output-area {
resize: none;
width: 80vw;
height: 200px;
font-size: 20px;
}
}
textarea {
background-color: $main-color-brighter;
color: $light-color;
}
button {
background-color: $medium-color;
font-size: 20px;
border: 1px solid $main-color;
&:hover {
cursor: pointer;
background-color: $light-color;
}
}

View file

@ -1,157 +0,0 @@
import {CodeOptions} from "../components/CodeInput";
type InHandler = (() => number);
type OutHandler = ((char: number) => void);
export default class Interpreter {
private readonly _array: Uint8Array;
private _pointer: number;
private readonly _code: string;
private _programCounter: number;
private readonly _inHandler: InHandler;
private readonly _outHandler: OutHandler;
private readonly _options: CodeOptions;
constructor(input: [string, CodeOptions], outHandler: OutHandler, inHandler: InHandler) {
const buf = new ArrayBuffer(32000);
this._array = new Uint8Array(buf);
this._pointer = 0;
this._options = input[1];
if (input[1].minify) {
this._code = this.minify(input[0])
} else {
this._code = input[0];
}
this._programCounter = 0;
this._inHandler = inHandler;
this._outHandler = outHandler;
}
public next() {
this.execute(this._code[this._programCounter++]);
}
public execute(char: string) {
switch (char) {
case '+':
this._array[this._pointer]++;
break;
case '-':
this._array[this._pointer]--;
break;
case '>':
this._pointer++;
break;
case '<':
if (this._pointer === 0) {
throw new Error("Cannot wrap left");
}
this._pointer--;
break;
case '.':
this._outHandler(this.value);
break;
case ',':
this.input();
break;
case '[':
this.loopForwards();
break;
case ']':
this.loopBackwards();
break;
case '•':
if (this._options.enableBreakpoints) {
throw new Error("Breakpoint reached");
}
break;
case undefined:
this._programCounter = this._code.length;
break;
default:
break;
}
}
private loopForwards() {
if (this.value === 0) {
let level = 0;
while (this.lastInstruction !== ']' || level > -1) {
this._programCounter++;
if (this._programCounter > this._code.length) {
throw new Error("Reached end of code while searching ']'");
}
if (this.lastInstruction === '[') level++;
else if (this.lastInstruction === ']') level--;
}
}
}
private loopBackwards() {
if (this.value !== 0) {
let level = 0;
while (this.lastInstruction !== '[' || level > -1) {
this._programCounter--;
if (this._programCounter < 0) {
throw new Error("Reached start of code while searching '['");
}
if (this.lastInstruction === '[') level--;
else if (this.lastInstruction === ']') level++;
}
}
}
private input() {
try {
this._array[this._pointer] = this._inHandler();
} catch {
this._programCounter--;
}
}
get reachedEnd(): boolean {
return this._programCounter === this._code.length;
}
get lastInstruction(): string {
return this._code[this._programCounter - 1];
}
get value(): number {
return this._array[this._pointer];
}
get array(): Uint8Array {
return this._array;
}
get pointer(): number {
return this._pointer;
}
get code(): string {
return this._code;
}
get programCounter(): number {
return this._programCounter;
}
private minify(code: string): string {
const CHARS = ['+', '-', '<', '>', '.', ',', '[', ']'];
if (this._options.enableBreakpoints) {
CHARS.push('•');
}
return code.split("")
.filter(c => CHARS.includes(c))
.join("");
}
}

View file

@ -1,41 +0,0 @@
import '../App.scss';
import CodeInput, {CodeOptions} from "./CodeInput";
import ProgramOutput from "./ProgramOutput";
import React, {useCallback, useState} from "react";
import Runner from "./Runner";
export const OptionContext = React.createContext<CodeOptions>({});
function App() {
const [out, setOut] = useState("");
const [input, setInput] = useState<[string, CodeOptions]>(["", {}]);
const [running, setRunning] = useState(false);
const outHandler = useCallback((char: number) => {
setOut(oldOut => oldOut + String.fromCharCode(char))
}, []);
const runHandler = (run: boolean) => {
setRunning(run);
if (!run) {
setOut("");
}
}
const inputHandler = (code: string, options: CodeOptions) => setInput([code, options]);
return (
<div className="App-header">
<OptionContext.Provider value={input[1]}>
{
!running && <CodeInput input={input} setInput={inputHandler}/>
}
<Runner running={running} setRunning={runHandler} code={input[0]} outHandler={outHandler}/>
{
running && <ProgramOutput text={out}/>
}
</OptionContext.Provider>
</div>
);
}
export default App;

View file

@ -1,22 +0,0 @@
import React from 'react';
interface CodeDisplayProps {
code: string,
index: number,
}
const CodeDisplay = ({code, index}: CodeDisplayProps) => {
const firstCodePart = code.substr(0, index);
const secondCodePart = code.substr(index + 1, code.length - index + 1);
return (
<div className="code-display-wrapper">
<code>{firstCodePart}</code>
<code style={{backgroundColor: "red"}}>{code[index] || " "}</code>
<code>{secondCodePart}</code>
</div>
);
};
export default CodeDisplay;

View file

@ -1,83 +0,0 @@
import React, {ChangeEvent, useState} from 'react';
import presets from "../presets.json";
export interface CodeOptions {
minify?: boolean,
directStart?: boolean,
startSuperSpeed?: boolean,
enableBreakpoints?: boolean
asciiView?: boolean
}
interface CodeInputProps {
setInput: ((code: string, options: CodeOptions) => void),
input: [string, CodeOptions]
}
const codeOptions: Array<[string, keyof CodeOptions]> = [
["Minify Code", "minify"],
["Start directly", "directStart"],
["Start in blocking mode", "startSuperSpeed"],
["Breakpoints (•)", "enableBreakpoints"],
["Show ASCII in memory", "asciiView"]
]
const CodeInput = ({input: [code, options], setInput}: CodeInputProps) => {
const [fontSize, setFontSize] = useState(40);
const setPreset = (name: keyof typeof presets) => () => {
setInput(presets[name], options);
}
const changeHandler = (name: keyof CodeOptions) => (event: ChangeEvent<HTMLInputElement>) => {
setInput(code, {...options, [name]: event.target.checked})
}
return (
<div className="bf-input">
<div className="code-options-wrapper">
<div>
<label htmlFor="bf-input-fontsize-range">Font Size</label>
<input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/>
</div>
{codeOptions.map(([display, id]) =>
<CodeOption displayName={display} name={id} options={options} onChange={changeHandler}/>
)}
</div>
<textarea value={code} onChange={e => setInput(e.target.value, options)} style={{fontSize}}
className="code-input"
placeholder="Input your code here..."/>
<div>
<div>Presets</div>
<div>
<button onClick={setPreset("helloworld")}>Hello World</button>
<button onClick={setPreset("hanoi")}>Towers of Hanoi</button>
<button onClick={setPreset("quine")}>Quine</button>
<button onClick={setPreset("gameoflife")}>Game Of Life</button>
<button onClick={setPreset("benchmark")}>Benchmark</button>
<button onClick={setPreset("fizzbuzz")}>Fizzbuzz</button>
</div>
</div>
</div>
);
};
interface CodeOptionProps {
displayName: string,
name: keyof CodeOptions,
options: CodeOptions,
onChange: (name: keyof CodeOptions) => (event: ChangeEvent<HTMLInputElement>) => void,
}
const CodeOption = ({displayName, name, options, onChange}: CodeOptionProps) => (
<span>
<input type="checkbox" checked={options[name]} id={`input-options-${name}`}
onChange={onChange(name)}/>
<label htmlFor={`input-options-${name}`}>{displayName}</label>
</span>
);
export default CodeInput;

View file

@ -1,15 +0,0 @@
import React from 'react';
interface ProgramOutputProps {
text: string
}
const ProgramOutput = ({text}: ProgramOutputProps) => {
return (
<div className="bf-output">
<textarea readOnly className="output-area" value={text}/>
</div>
);
};
export default ProgramOutput;

View file

@ -1,118 +0,0 @@
import React, {useContext, useRef, useState} from 'react';
import Interpreter from "../brainfuck/Interpreter";
import {OptionContext} from "./App";
const MAX_TABLE_COLUMNS = 20;
interface RunDisplayProps {
interpreter: Interpreter,
}
const RunDisplay = ({interpreter}: RunDisplayProps) => {
const options = useContext(OptionContext);
const index = interpreter.pointer;
let offset: number;
if (index < MAX_TABLE_COLUMNS / 2) {
offset = 0;
} else {
offset = index - MAX_TABLE_COLUMNS / 2;
}
const arrayWithIndex = Array(MAX_TABLE_COLUMNS).fill(0)
.map((_, i) => i + offset);
return (
<div>
<table className="memory-display-table">
<thead>
<tr>
{
arrayWithIndex.map((n => <th key={n}>{n}</th>))
}
</tr>
</thead>
<tbody>
<tr>
{
arrayWithIndex.map((n) => <MemoryCell key={n} index={n} interpreter={interpreter}/>)
}
</tr>
{
options.asciiView &&
<tr>
{
arrayWithIndex.map((n) => <MemoryCell key={n} index={n} interpreter={interpreter} ascii/>)
}
</tr>
}
<tr>
{
arrayWithIndex.map((n) => <td className="pointer"
key={n}>{interpreter.pointer === n && "^"}</td>)
}
</tr>
</tbody>
</table>
</div>
);
};
interface MemoryCellProps {
index: number,
interpreter: Interpreter,
ascii?: boolean,
}
const MemoryCell = ({index, interpreter, ascii}: MemoryCellProps) => {
const [isEditing, setIsEditing] = useState(false);
const [input, setInput] = useState(interpreter.array[index] + "");
const inputField = useRef<HTMLInputElement>(null);
const saveAndQuit = () => {
interpreter.array[index] = +(input);
setIsEditing(false);
}
const click = () => {
setIsEditing(true);
inputField.current?.select();
}
const keyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
console.log("key", e.key);
if (e.key === "Escape") {
setIsEditing(false);
} else if (e.key === "Enter") {
saveAndQuit();
}
}
const content = ascii ?
String.fromCharCode(interpreter.array[index])
:
interpreter.array[index];
return (
<td onClick={click} className="cell">
{
isEditing && !ascii ?
<input onKeyDown={keyDown}
className="array-set-value-field"
ref={inputField}
onChange={e => setInput(e.target.value)}
value={input}
onBlur={saveAndQuit}
autoFocus
/>
:
content
}
</td>
);
}
export default RunDisplay;

View file

@ -1,189 +0,0 @@
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import Interpreter from "../brainfuck/Interpreter";
import CodeDisplay from "./CodeDisplay";
import RunDisplay from "./RunDisplay";
import {OptionContext} from "./App";
interface RunInfoProps {
running: boolean,
setRunning: (running: boolean) => void,
code: string,
outHandler: (char: number) => void,
}
const Runner = ({setRunning, running, outHandler, code}: RunInfoProps) => {
const [speed, setSpeed] = useState(0);
const [interpreter, setInterpreter] = useState<Interpreter | null>(null);
const [info, setInfo] = useState<string | null>(null);
const [startTime, setStartTime] = useState(0);
const [, setRerenderNumber] = useState(0);
const rerender = () => setRerenderNumber(n => n + 1);
const options = useContext(OptionContext);
const inputArea = useRef<HTMLTextAreaElement>(null);
const inputHandler = () => {
if (!inputArea.current) {
throw new Error("Could not read input")
}
const value = inputArea.current.value;
if (value.length < 1) {
throw new Error("No input found");
}
const char = value.charCodeAt(0);
inputArea.current.value = value.substr(1);
return char;
}
const startHandler = useCallback(() => {
if (options.directStart) {
if (options.startSuperSpeed) {
setSpeed(-1);
} else {
setSpeed(100);
}
} else {
setSpeed(0);
}
setStartTime(Date.now);
setInterpreter(new Interpreter([code, options], outHandler, inputHandler));
setRunning(false);
setRunning(true);
}, [options, code, outHandler, setRunning]);
const stopHandler = () => {
setRunning(false);
setInfo(null);
}
const nextHandler = useCallback(() => {
setInfo(null);
try {
interpreter?.next();
} catch (e) {
setInfo(e.message);
setSpeed(0);
}
if (interpreter?.reachedEnd) {
setSpeed(0);
setInfo(`Finished Execution. Took ${(Date.now() - startTime) / 1000}s`)
}
rerender();
}, [interpreter, startTime]);
const runBlocking = useCallback(() => {
try {
while (speed === -1 && !interpreter?.reachedEnd) {
interpreter?.next();
}
setSpeed(0);
setInfo(`Finished Execution. Took ${(Date.now() - startTime) / 1000}s`)
} catch (e) {
setInfo(e.message);
setSpeed(0);
}
}, [speed, interpreter, startTime]);
useEffect(() => {
if (running) {
if (speed === 0) {
return;
}
if (speed > 0) {
const interval = setInterval(() => {
nextHandler();
}, 1000 / (speed * 10));
return () => clearInterval(interval);
}
runBlocking();
}
}, [runBlocking, running, nextHandler, speed]);
return (
<div className="bf-run">
{
running && interpreter && <>
<CodeDisplay code={interpreter.code} index={interpreter.programCounter}/>
<RunDisplay interpreter={interpreter}/>
</>
}
<div>
{running && <button className="run-button" onClick={stopHandler}>Back</button>}
<button className="run-button" onClick={startHandler}>{running ? "Restart" : "Start"}</button>
{running && <button className="run-button" onClick={nextHandler}>Next</button>}
</div>
{
running && interpreter &&
<>
<SpeedControl speed={speed} setSpeed={setSpeed}/>
<ManualControlButtons interpreter={interpreter} rerender={rerender}/>
</>
}
{info && <div className="info">{info}</div>}
{
running && <div>
<div>Input:</div>
<textarea className="program-input-area" ref={inputArea}/>
</div>
}
</div>
);
};
interface SpeedControlProps {
speed: number,
setSpeed: React.Dispatch<React.SetStateAction<number>>,
}
const SpeedControl = ({speed, setSpeed}: SpeedControlProps) => {
return (
<div className="speed-control-wrapper">
<label htmlFor="run-info-speed-range">Speed</label>
<input type="range" id="run-info-speed-range" value={speed}
onChange={e => setSpeed(+e.target.value)}/>
<span> {speed}</span>
<span>
<button onClick={() => setSpeed(s => s === 0 ? 0 : s - 1)}
className="small-speed-button">-</button>
<button onClick={() => setSpeed(0)}
className="small-speed-button">0</button>
<button onClick={() => setSpeed(s => s === 100 ? 100 : s + 1)}
className="small-speed-button">+</button>
</span>
<span>
<label>Superspeed Mode (blocking)</label>
<input id="superspeed-mode-check" type="checkbox" checked={speed === -1} onChange={() => setSpeed(-1)}/>
</span>
</div>
)
}
const ManualControlButtons = ({interpreter, rerender}: { interpreter: Interpreter, rerender: (() => void) }) => {
const run = (char: string) => {
try {
interpreter.execute(char);
} catch {
}
rerender();
}
return (
<div>
<button onClick={() => run('<')} className="small-speed-button">&lt;</button>
<button onClick={() => run('>')} className="small-speed-button">&gt;</button>
<button onClick={() => run('-')} className="small-speed-button">-</button>
<button onClick={() => run('+')} className="small-speed-button">+</button>
<button onClick={() => run('.')} className="small-speed-button">.</button>
</div>
)
}
export default Runner;

View file

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View file

@ -1,11 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View file

@ -1,26 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}

File diff suppressed because it is too large Load diff

2
js/.gitignore vendored
View file

@ -1,2 +0,0 @@
node_modules
.idea

View file

@ -1,4 +0,0 @@
{
"singleQuote": true,
"printWidth": 100
}

View file

@ -1 +0,0 @@
hello...[[].]]

View file

@ -1,11 +0,0 @@
{
"name": "brainfuck",
"version": "1.0.0",
"main": "src/index.js",
"license": "MIT",
"type": "module",
"devDependencies": {
"prettier": "^2.6.2"
},
"dependencies": {}
}

View file

@ -1,113 +0,0 @@
import fs from 'fs';
const RED = '\x1B[1;31m';
const RESET = '\x1B[1;0m';
function lex(string) {
const tokens = [];
for (let i = 0; i < string.length; i++) {
const char = string[i];
if (['+', '-', '>', '<', '.', ',', '[', ']'].includes(char)) {
tokens.push({
char,
span: i,
});
}
}
return tokens;
}
function ParseError(message, span) {
this.message = message;
this.span = span;
}
function Parser(tokens) {
this.tokens = tokens;
this.position = 0;
}
Parser.prototype.next = function () {
const token = this.tokens[this.position];
this.position++;
return token;
};
Parser.prototype.parse = function (isLoop) {
const body = [];
let nextToken;
while ((nextToken = this.next()) !== undefined) {
switch (nextToken.char) {
case '[': {
const loopBody = this.parse(true);
body.push(loopBody);
break;
}
case ']': {
if (isLoop) {
return body;
} else {
throw new ParseError('No matching `[` found', nextToken.span);
}
}
default: {
body.push(nextToken);
}
}
}
if (isLoop) {
throw new ParseError('No matching `]` found', this.tokens[this.tokens.length - 1].span);
} else {
return body;
}
};
function reportError(source, message, span) {
let lineIdx = 0;
let lastNewlineIdx = 0;
for (let i = 0; i < source.length; i++) {
const char = source[i];
if (i === span) {
break;
}
if (char === '\n') {
lineIdx++;
lastNewlineIdx = i;
}
}
const lines = source.split('\n');
const line = lines[lineIdx];
const lineNumber = String(lineIdx + 1);
const linePrefix = `${lineNumber} | `;
const lineSpan = span - lastNewlineIdx;
console.error(`${RED}error: ${message}${RESET}`);
console.error(`${linePrefix}${line}`);
console.error(`${' '.repeat(linePrefix.length + lineSpan)}${RED}^${RESET}`);
}
const file = process.argv[2];
if (!file) {
console.error('Usage: [filename]');
process.exit(1);
}
const source = fs.readFileSync(file, 'utf-8');
const tokens = lex(source);
const parser = new Parser(tokens);
try {
const ast = parser.parse(false);
console.log(ast);
} catch (parseError) {
if (!(parseError instanceof ParseError)) {
throw parseError;
}
reportError(source, parseError.message, parseError.span);
}

View file

@ -1,8 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
prettier@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==

2
rust2/.gitignore vendored
View file

@ -1,2 +0,0 @@
target
.idea

View file

@ -1,3 +0,0 @@
imports_granularity = "Crate"
newline_style = "Unix"
group_imports = "StdExternalCrate"

1238
rust2/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,29 +0,0 @@
[package]
name = "brainfuck"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bumpalo = { version = "3.9.1", features = ["allocator_api"] }
clap = { version = "3.1.9", features = ["derive"] }
dbg-pls = { version = "0.3.2", features = ["colors", "derive"] }
owo-colors = "3.3.0"
rand = "0.8.5"
tracing = "0.1.34"
tracing-subscriber = { version = "0.3.11", features = ["env-filter"] }
[dev-dependencies]
criterion = "0.3.5"
insta = "1.14.0"
[profile.release]
debug = true
[profile.dev]
opt-level = 3
[[bench]]
name = "opts"
harness = false

View file

@ -1,5 +0,0 @@
Benchmark brainf*ck program
>++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++
[>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++
++++++++[>++++++++++[>++++++++++[>++++++++++[>+
+++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++.

View file

@ -1,44 +0,0 @@
>+++++++++[<+++++++++++>-]<[>[-]>[-]<<[>+>+<<-]>>[<<+>>-]>>>
[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<
-]<<-<-]+++++++++>[<->-]>>+>[<[-]<<+>>>-]>[-]+<<[>+>-<<-]<<<
[>>+>+<<<-]>>>[<<<+>>>-]>[<+>-]<<-[>[-]<[-]]>>+<[>[-]<-]<+++
+++++[<++++++<++++++>>-]>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-
]<<<<<<.>>[-]>[-]++++[<++++++++>-]<.>++++[<++++++++>-]<++.>+
++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>
>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<+++++++
+>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<------
---->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++
++[<---------->-]<--.>+++++++++[<+++++++++>-]<--.-.>++++++++
[<---------->-]<++.>++++++++[<++++++++++>-]<++++.-----------
-.---.>+++++++[<---------->-]<+.>++++++++[<+++++++++++>-]<-.
>++[<----------->-]<.+++++++++++..>+++++++++[<---------->-]<
-----.---.>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>>+++
+[<++++++>-]<--.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.
><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++
++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<++
+++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<++
+++++++++>-]<.+++..+++++++++++++.>++++++++++[<---------->-]<
-.---.>+++++++[<++++++++++>-]<++++.+++++++++++++.++++++++++.
------.>+++++++[<---------->-]<+.>++++++++[<++++++++++>-]<-.
-.---------.>+++++++[<---------->-]<+.>+++++++[<++++++++++>-
]<--.+++++++++++.++++++++.---------.>++++++++[<---------->-]
<++.>+++++[<+++++++++++++>-]<.+++++++++++++.----------.>++++
+++[<---------->-]<++.>++++++++[<++++++++++>-]<.>+++[<----->
-]<.>+++[<++++++>-]<..>+++++++++[<--------->-]<--.>+++++++[<
++++++++++>-]<+++.+++++++++++.>++++++++[<----------->-]<++++
.>+++++[<+++++++++++++>-]<.>+++[<++++++>-]<-.---.++++++.----
---.----------.>++++++++[<----------->-]<+.---.[-]<<<->[-]>[
-]<<[>+>+<<-]>>[<<+>>-]>>>[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]
>[<+>-]>[<<++++++++++>>>+<-]<<-<-]+++++++++>[<->-]>>+>[<[-]<
<+>>>-]>[-]+<<[>+>-<<-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<>>[<+>-]<
<-[>[-]<[-]]>>+<[>[-]<-]<++++++++[<++++++<++++++>>-]>>>[>+>+
<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>[-]>[-]++++[<++++++++>
-]<.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..---
-----.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++
.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<-
-.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]
<.+++..+++++++++++++.>++++++++[<---------->-]<--.>+++++++++[
<+++++++++>-]<--.-.>++++++++[<---------->-]<++.>++++++++[<++
++++++++>-]<++++.------------.---.>+++++++[<---------->-]<+.
>++++++++[<+++++++++++>-]<-.>++[<----------->-]<.+++++++++++
..>+++++++++[<---------->-]<-----.---.+++.---.[-]<<<]

View file

@ -1,7 +0,0 @@
++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++\n++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<
++++<++++<++++>>>]++++\n+[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++\n++++>++++++>++++++++[-<+
+++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>-->\n---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+\n
+++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[\n->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[
-<+]->>>++++++++++<<[-\n>+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]>\n+>>]<<<<<]>[-]>>[>++++++
[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++\n+++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[\n
-<+]-<<]

View file

@ -1,709 +0,0 @@
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[-]>[-]+++++++++++++++++++++++++++.++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++.-------------------.-------
--------------------------------------.+++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++.-----------------------------------------.++++++
++++++++++++++++++.[-]+++++++++++++++++++++++++++.++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++.-------------------------------------
----.+++++++++.---------.+++++.+++++++++++++++++.++++++++++++.++++++++++++++
+++++++++++++.++++++++.------------------.+++++++++++++.+.------------------
-----------------------------------------------------------------.++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.------
---.----------------------------------------------------------------------.+
+++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++++.++++++++++
+++.+.------.---------------------------------------------------------------
----------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++.+++++.-------------------------------------------------------------
-----------------.++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++
+++++++++++++++++++++++++.-----------------.++++++++.+++++.--------.--------
----------------------------------------------------.+++++++++++++++++++++++
++++++++++++++++++++++++++++++++++.++++++++.[-]+++++++++++++++++++++++++++.+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.------------
----------------------------.++++++++.----------.++++.+++++++++++++++++++.++
+++++++++++++.+++++++++++++++++++++++++++.---------.+++++++++++..-----------
----.+++++++++.-------------------------------------------------------------
-----------------.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++.+++++++++++++++++++++++.-------------------------------------------
----------------------------------------------.+++++++++++++++++++++++++++++
++++++.+++++++++++++++++++++++++++++++++++++++++.---.---..+++++++++.+++.----
----------.-----------------------------------------------------------------
---.+++++++++++++++++++++++++++++++++++++++++++++++++++++++.++++++++++++++++
++++++++.---.------.--------------------------------------------------------
--------------.++++++++++++++++++++++++++++.++++++++++++++++++++++++++++++++
++++++++++++.++++++++++++..----.--------------------------------------------
----------.-----------..++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++...-----------------------------------------------------
--------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++.+
++++++++.---.---..+++++++++.+++.--------------.-----------------------------
-------------------------.++++++++++++++++++++++++++++++++++++++++++++++++++
+.+++++++++++++++++++.------------------------------------------------------
---------------.+++++++++++++++++++++++++++++++++++++++++++++++++++.++++.---
.+++++++++++++.+++++.-------------------------------------------------------
---------------.+++++++++++++++.[-]>[-]+++++++++>[-]+++>>[-]>[-]<<<<<[->>>>>
+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<[-]>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<
<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]
>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-
<<+>>]<<<[-]+>>>][-]<[->+<]>[[-<+>]<<<[-]+>>>]<<<[>[-]++++++++++++++++++++++
+++++++++++++++++++++++>[-]<<<<<[->>>>>+<<<<<]>>>>>[[-<<<<<+>>>>>]<+++++++++
++++++++++++++++++++++++++++++++++>]<<<[>>>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<<
->>>][-]++++++++++++++++>[-]++++++++++++++>>>>[-]>[-]<<<<<<<<<[->>>>>>>>>+<<
<<<<<<<]>>>>>>>>>[-<+<<<<<<<<+>>>>>>>>>][-]<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[
[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+
<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>
>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<<+++++>>>>]>[-]>[-
]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<+<<<<<<<<+>>>>>>>>>][-]+<<[-]+>>
>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<
]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<
[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<
[[-]<<<++++++++++>>>][-]>[-]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>>>>>>[-<+<<<<<<<+
>>>>>>>>][-]+++++++++++++++++++++++++<<<[-]>>[>>[-]<[->+<]>[-<+<<<+>>>>]<<-]
[-]<<[->>+<<]>>[-<<+<<+>>>>][-]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>>>>>>[-<<<<<<<
<+>>>>->>>>][-]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>>>>>>[-<<<<<<<<+>>>>->>>>]>[-]
>[-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<+<<<<<<<<+>>>>>>>>>][-]++<<[-
]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+
>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>
>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>
]<<<[[-]<<<<----->>>>][-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<<<<<<<<<
+>>>>>>->>>][-]+++++++++++++++++++++++++++.+++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++.>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>
>>]>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[
-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->
>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<
+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]>>>>>>[-]<[->+<]
>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>>>]>]<<<[-]>[-]<
<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>
+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>
>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[
-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>
]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]+
+++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-
<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->
>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<
[-]>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>>>]<<[-<<<<->>>>
]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>
>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]
<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[
[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>
[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<
<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>
>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->
[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]
+>>]<]<]<<<]<[-]>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<+>>>>>]<<[
-<<<->>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<
<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>
>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<
<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[-
>>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>[-]+<[[-<+>]<+++
+++++++++++++++++++++++++++++++++++++++++++++.<+++++++++++++++++++++++++++++
+++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>-<
]>[[-]>[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<+++++++++++++++++++++++
+++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.
>>>>>>-<]>[[-]<<<<<<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>>>]
<<]<<<<<<--------------------------------.>[-]>[-]<<<<<<[->>>>>>+<<<<<<]>>>>
>>[-<+<<<<<+>>>>>>]>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]+++++
+++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<
+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+
<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]
>>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>
>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>
>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[
-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>
>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]
>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<
+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->
>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>
->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[
-]+>>]<]<]<<<]<<[-]>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>
>>]<<[-<<<<->>>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]+++++
+++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[
[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[
->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+
>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+
<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>]
[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]
+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>
[[-<<<+>>>]<<[-]+>>]<]<]<<<]<[-]>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-
<<<+<<+>>>>>]<<[-<<<->>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>]
[-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<
<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>
[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]
<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>
[-]+<[[-<+>]<++++++++++++++++++++++++++++++++++++++++++++++++.<+++++++++++++
+++++++++++++++++++++++++++++++++++.<+++++++++++++++++++++++++++++++++++++++
+++++++++.>>>>-<]>[[-]>[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<+++++++
+++++++++++++++++++++++++++++++++++++++++.<+++++++++++++++++++++++++++++++++
+++++++++++++++.>>>>>>-<]>[[-]<<<<<<++++++++++++++++++++++++++++++++++++++++
++++++++.>>>>>>]<<]<<<<<<+++++++++++++.>[-]>[-]<<<<<<<[->>>>>>>+<<<<<<<]>>>>
>>>[-<+<<<<<<+>>>>>>>][-]+++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+
>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>
>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<
+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<[-]+<[[-]>>[-]++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++.<-<]>[[-]<<<<<<.>>>>>>]<[-]<<<<<<<<[->>>>>>>>+<<<
<<<<<]>>>>>>[-]>>[-<<<<<<<<+>>>>>>+>>][-]<<[->>+<<]>>[[-<<+>>]<<->>]<<[<<<..
>>>-]<<<.>>>>>[-]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>>>>[-]>>[-<<<<<<<<+>>>>>>+>>
][-]<<[->>+<<]>>[[-<<+>>]<<->>]<<[<<<..>>>-]>>>[-]>[-]<<<<<<<[->>>>>>>+<<<<<
<<]>>>>>>>[-<+<<<<<<+>>>>>>>][-]++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>
[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>
+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]
>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<[-]+<[[-]>>[-]+++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++.<-<]>[[-]<<<<<<.>>>>>>]<<<<<<<<]>>>[-]<<<<
<[->>>>>+<<<<<]>>>>>[[-<<<<<+>>>>>]<<<<<<<[-]<[-]<[-]>>>>>>>>>>[-]<<<<<[->>>
>>+<<<<<]>>>>>[-<<<<<+<<<+>>>>>>>>][-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>+>>>>>>>>>]<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-
[<<<<+>>>>-]<<<<]<<[-]>>>[<<<+>>>-]<<[>>>>]><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<[->>>>>+<<<<
<]>>>>>[[-<<<<<+>>>>>]<<<<<->>>>>]<]<<<<<+>>[-]+>>[-]>[-]<<<<<[->>>>>+<<<<<]
>>>>>[-<+<<<<+>>>>>][-]++++++++++<<[-]>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>
[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<
<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<
<<[-]+>>>][-]<[->+<]>[[-<+>]<<<[-]+>>>]<<<]<<<[-]>[-]+>[-]++>[-]++++++++>[-]
+>[-]+[>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++<<[-]>>>[-]>[
-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<-
>->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>
]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]+>>>][-]<[->+<]>[[-<+>]<<<[-]+>>>]<<<[>[-
]<<<<<[->>>>>+<<<<<]>>>>>[[-<<<<<+>>>>>]>[-]>[-]>[-]>>[-]>[-]<<<<<<<<<<[->>>
>>>>>>>+<<<<<<<<<<]>>>>>>>>>>[-<+<<<<<<<<<+>>>>>>>>>>][-]+<<[-]+>>>[-]>[-]<<
<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[
-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<
][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<[-]
+>[-]+>>]>[-]>[-]<<<<<<<<<<[->>>>>>>>>>+<<<<<<<<<<]>>>>>>>>>>[-<+<<<<<<<<<+>
>>>>>>>>>][-]+++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]
>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[-
>>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->
+<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<[-]+>>[-]+>][-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-
]>>[-]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>[-]>[-<
<<<<<<<<<<<<<<+>>>>>>>>>>>>>>+>]<[<+>-]>[-]<<<<<<<<<<<<<<[->>>>>>>>>>>>>>+<<
<<<<<<<<<<<<]>>>>>>>>>>>>>[-]>[-<<<<<<<<<<<<<<+>>>>>>>>>>>>>+>]<[<+++>-]>[-]
<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>>>[-]>[-<<<<<<<<<<<<<+>
>>>>>>>>>>>+>]<[<+++++++++>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<[->>+<<]>>[-<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>][-]<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>+<<<<<<<<<
<<<<<<<]>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<<<<+>>>>-]<<<<]<<[-]>>>[<<<+>>
>-]<<[>>>>]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<[->>>>>>>>>>>>+<<<<<<<<<<<<]>>>>>>>>>>>>[-<
<<<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>][-]<<<<<<<<<<<<<<<
<[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<+<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]
<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<<<<+>>>>-]<<<<]<<[-]>>>[<<<+>>>-]<<[>>>>]>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<<
<<]>>>>>>>>>>>[-<<<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>][-]<<
<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>[-<<<<<<<<
<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<
<<<+>>>>-]<<<<]<<[-]>>>[<<<+>>>-]<<[>>>>]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>+>>>>>>>>>>>>>][-]<<[->>+<<]>>[[-<<+>>]>[-]<<<<<<<<<<<<[->>>>
>>>>>>>>+<<<<<<<<<<<<]>>>>>[-]>>>>>>>[-<<<<<<<<<<<<+>>>>>+>>>>>>>][-]<<<<<<<
<<<<[->>>>>>>>>>>+<<<<<<<<<<<]<[-]>>>>>>>>>>>>[-<<<<<<<<<<<+<+>>>>>>>>>>>>][
-]<<<<<<<[->>>>>>>+<<<<<<<]<<<<[-]>>>>>>>>>>>[-<<<<<<<+<<<<+>>>>>>>>>>>]<<<<
<<<<<<->[-]>+>>>>>>>][-]<[->+<]>[[-<+>]>[-]<<<<<<<<<<<<[->>>>>>>>>>>>+<<<<<<
<<<<<<]>>>>>[-]>>>>>>>[-<<<<<<<<<<<<+>>>>>+>>>>>>>][-]<<<<<<<<<<<<<[->>>>>>>
>>>>>>+<<<<<<<<<<<<<]>[-]>>>>>>>>>>>>[-<<<<<<<<<<<<<+>+>>>>>>>>>>>>][-]<<<<<
<<[->>>>>>>+<<<<<<<]<<<<<<[-]>>>>>>>>>>>>>[-<<<<<<<+<<<<<<+>>>>>>>>>>>>>]<<<
<<<<<<<->[-]>+>>>>>>>]<<<<]>[-]>[-]<<<<<<[->>>>>>+<<<<<<]>>>>>>[-<+<<<<<+>>>
>>>][-]++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<
<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<
]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-
<+>]<<<[-]>>>]<<<[[-]>>>>[-]++>>[-]>[-]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<
<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>][-]<<[-]+>>>[-
]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[
<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]
+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-
]>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[-]>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>]<]>[-]>[-]<<<<<<<<<<<<<<<[-
>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<<<<<<<<<<<+>>>>>>>>>>
>>>>>][-]+<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-
<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<
<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[
-<+>]<<<[-]>>>]<<<[[-]>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>[-<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>+>>>>]<]>[-]>[-]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<
<<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>][-]++<<[-]+>>
>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<
]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<
[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<
[[-]>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>[-]>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>]<]>[-]
>[-]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<
<<<<<<<<<<+>>>>>>>>>>>>>>>][-]<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-
]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<
+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<
[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-]>>>
>>>>>>>>>>[-]>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<
<<<[<<<[-]<[-]<[-]+>>>>>-[<<<<+>>>>-]<<<<]<<[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+
<<<<]<<>>>>]>>[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<<<<
<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<<<<<<<<<<<+>>>>>
>>>>>>>>>>][-]+<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>
>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->
>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+
<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>[-]>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>-[<<<<+>>>>-]
<<<<]<<[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+<<<<]<<>>>>]>>[->>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>[-<+<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>][-]++<<[
-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]
+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>
>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>
>]<<<[[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-
]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>[-]<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>-[<<<<+>>>>-]<<<<]<<
[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+<<<<]<<>>>>]>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<
<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>>>>[-<+<<<<<<<<<<<<+>>>>>>>>>>>>
>][-]<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>
>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>
[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]
<<<[-]>>>]<<<[[-]<<<<<<<<<<<<<<<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>[-]<<<<<[->>>>>
+<<<<<]>>>>>[-<<<<<+<<<<<<<<<<<+>>>>>>>>>>>>>>>>][-]<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>
>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<<<<+
>>>>-]<<<<]<<[-]>>>[<<<+>>>-]<<[>>>>]><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<<
<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>>>>[-<+<<<<<<<<<<<<+>>>>>>>>>>>>>
][-]+<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>
>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>
[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]
<<<[-]>>>]<<<[[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]
<<<<<[->>>>>+<<<<<]>>>>>[-<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>][-]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<<<<+>>>>-]<<<<
]<<[-]>>>[<<<+>>>-]<<[>>>>]><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<<<<<[
->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>>>>[-<+<<<<<<<<<<<<+>>>>>>>>>>>>>][-]
++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]
<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-
<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<
[-]>>>]<<<[[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-
]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<[->>
>>>+<<<<<]>>>>>[-<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>][-]<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>>[<<<<+>>>>-]<-[<<<<+>>>>-]<<
<<]<<[-]>>>[<<<+>>>-]<<[>>>>]><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>]>[-]>[-]<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>
>>>[-<+<<<<<<<<<<<<+>>>>>>>>>>>>>][-]<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+
>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>
>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<
+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]>[-]<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>[-<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>+>>>]<]>[-]>[-]<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>
>>>>>>>>>>>[-<+<<<<<<<<<<<<+>>>>>>>>>>>>>][-]+<<[-]+>>>[-]>[-]<<<[->>>+<<<]>
>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->
>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<
<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]>[-]<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>[-]>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+>>>]<]>[-]>[-]
<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>>>>>>[-<+<<<<<<<<<<<<+>>>
>>>>>>>>>>][-]++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]
>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[-
>>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->
+<]>[[-<+>]<<<[-]>>>]<<<[[-]>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>+>>>]<]<[->>>>[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]>>[-]<<
<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>[-]>>>>
>[-<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>+>>>>>][-]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>
>[-]>>>>[-<<<<<<<<+>>>>+>>>>]<<<[-]++++++++++++++++++++++++++++++++>>-<]>[[-
]>[-]<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<]>>>>>>>>>>>[-]>>>>>
[-<<<<<<<<<<<<<<<<+>>>>>>>>>>>+>>>>>][-]<<<<<<<[->>>>>>>+<<<<<<<]>>>[-]>>>>[
-<<<<<<<+>>>+>>>>]<<<[-]++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++>>]<[-]++++++++++++++++>[-]+++++++++++++
+>>>>[-]>[-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<+<<<<<<<<+>>>>>>>>>][
-]<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]
<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-
<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<
[-]>>>]<<<[[-]<<<<+++++>>>>]>[-]>[-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>
[-<+<<<<<<<<+>>>>>>>>>][-]+<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<
<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>
>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]
>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[[-]<<<++++++++++>>>][-]>[-]<<<<<<<<[->>>
>>>>>+<<<<<<<<]>>>>>>>>[-<+<<<<<<<+>>>>>>>>][-]+++++++++++++++++++++++++<<<[
-]>>[>>[-]<[->+<]>[-<+<<<+>>>>]<<-][-]<<[->>+<<]>>[-<<+<<+>>>>][-]<<<<<<<<<<
<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>>>>>>[-<<<<<<<<<<<+>>>>>>>->>>>][-]<<<<<<<<
<<<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>>>>>>[-<<<<<<<<<<<+>>>>>>>->>>>]>[-]>[-]<
<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<+<<<<<<<<+>>>>>>>>>][-]++<<[-]+>>>
[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]
<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[
-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<<[
[-]<<<<----->>>>][-]<<<<<<[->>>>>>+<<<<<<]>>>>>>[-<<<<<<+>>>->>>][-]++++++++
+++++++++++++++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++.>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>]>>>[-]>[-]<<<<<[->>>
>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>
+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<
[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]
>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]>>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<
<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>
[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[
-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<
]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<
<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<
<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<
<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+
<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>
>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<[-]>>>>>[-]<[->+<]>[[-<
+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>>>]<<[-<<<<->>>>]>]<<<[-]>[-]<<<<<[->>>
>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>
[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+
>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>
>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<
<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++
>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>
]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]
>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<[-]>>>>[-]
<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<+>>>>>]<<[-<<<->>>]>]<<<[-]>[-]<<
<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>+
<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>
>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-
]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]
<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>[-]+<[[-<+>]<++++++++++++++++++++++++++
++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.<++
++++++++++++++++++++++++++++++++++++++++++++++.>>>>-<]>[[-]>[-]<<<<[->>>>+<<
<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<++++++++++++++++++++++++++++++++++++++++++++++
++.<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>>>-<]>[[-]<<<<<<+++
+++++++++++++++++++++++++++++++++++++++++++++.>>>>>>]<<]<<<<<<--------------
------------------.>[-]>[-]<<<<<<[->>>>>>+<<<<<<]>>>>>>[-<+<<<<<+>>>>>>]>>>[
-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->
>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]
>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>
[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]>>>>>>[-]<[->+<]>[[-<+>
]>[-]<<<[->>>+<<<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>>>]>]<<<[-]>[-]<<<<<[->
>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-
]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<
<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[-
>>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<
<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++
++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>
>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<
<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<[-]>>>>
>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>>>]<<[-<<<<->>>>]>]<<<[
-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-
]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>
>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+
>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>
>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>
>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]
>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]
<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<
]<<<]<[-]>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<+>>>>>]<<[-<<<->>
>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>
>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-
]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>
[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>
>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>[-]+<[[-<+>]<++++++++++
++++++++++++++++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++
++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>-<]>[[-]>
[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<++++++++++++++++++++++++++++++
++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>>>-
<]>[[-]<<<<<<++++++++++++++++++++++++++++++++++++++++++++++++.>>>>>>]<<]<<<<
<<+++++++++++++.>[-]>[-]<<<<<<<[->>>>>>>+<<<<<<<]>>>>>>>[-<+<<<<<<+>>>>>>>][
-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++<<[-]+>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>
>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>
>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<
]>[[-<+>]<<<[-]>>>]<<[-]+<[[-]>>[-]+++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++.<-<]>[[-]<<<<<<.>>>>>>]<[-]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>>>
>[-]>>[-<<<<<<<<<<<+>>>>>>>>>+>>][-]<<[->>+<<]>>[[-<<+>>]<<->>]<<[<<<..>>>-]
<<<.>>>>>[-]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>>>>[-]>>[-<<<<<<<<<<<
+>>>>>>>>>+>>][-]<<[->>+<<]>>[[-<<+>>]<<->>]<<[<<<..>>>-]>>>[-]>[-]<<<<<<<[-
>>>>>>>+<<<<<<<]>>>>>>>[-<+<<<<<<+>>>>>>>][-]+++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++<<[-]+>>>[-]>[-]<<<
[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-
]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]
[-]<<[->>+<<]>>[[-<<+>>]<<<[-]>>>][-]<[->+<]>[[-<+>]<<<[-]>>>]<<[-]+<[[-]>>[
-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++.<-<]>[[-]<<<<<<.>>>>>>]<<<<<<
<<<]>[-]++++++++++.[-]+>[-]+>[-]+++++++++++++++++++++++++++.++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++.>[-]>[-]<<<[->>>+<<<]>>>[-<
+<<+>>>]>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<
[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<
<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[
-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]>>>>>>[-]<[
->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>>>]>]<<<[-]
>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>[-]<
<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+
<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>
>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<+>>]
<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>
][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>
>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<
<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<
<<]<<[-]>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>>>]<<[-<<<<
->>>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[
-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>
]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]
>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+
<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>
[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<
[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<
->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]
<<[-]+>>]<]<]<<<]<[-]>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<+>>>>
>]<<[-<<<->>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++
++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<
<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>
>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-
]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>[-]+<[[-<+>
]<++++++++++++++++++++++++++++++++++++++++++++++++.<++++++++++++++++++++++++
++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++++.>
>>>-<]>[[-]>[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<++++++++++++++++++
++++++++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++
++++.>>>>>>-<]>[[-]<<<<<<++++++++++++++++++++++++++++++++++++++++++++++++.>>
>>>>]<<]<<<<<<--------------------------------.>[-]>[-]<<<<[->>>>+<<<<]>>>>[
-<+<<<+>>>>]>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++>[
-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>
[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>
>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<]<<<]<<<[-]>>>>>>[
-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<<+>>>>>>>]<<[-<<<<<->>>>>]>]<<
<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<<<<[-]>>>>[>>>
[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[-
>>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<
<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[->>+<<]>>[[-<<
+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>
>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<
<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[
-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<
]<]<<<]<<[-]>>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<<+>>>>>>]<<[-
<<<<->>>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++++++++<<
<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+
>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<[->>>>+<
<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]+>[-]<<[
->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]>[-]<<<<<[->>>>>+<<<<<]>
>>>>[-<+<<<<+>>>>>][-]++++++++++>[-]<<[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]
<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<
[<<<->>->[-]>[-]<<<<[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+
>>>]<<[-]+>>]<]<]<<<]<[-]>>>>[-]<[->+<]>[[-<+>]>[-]<<<[->>>+<<<]>>>[-<<<+<<+
>>>>>]<<[-<<<->>>]>]<<<[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<<<+>>>>>][-]++++
++++++<<<<<[-]>>>>[>>>[-]<<[->>+<<]>[-]>[-<<+>+>][-]>[-]<<<<[->>>>+<<<<]>>>>
[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<<->>->[-]>[-]<<<<
[->>>>+<<<<]>>>>[[-<<<<+>>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]
+>[-]<<[->>+<<]>>[[-<<+>>]<[-]>]<[[-]<<<<<<<+>>>>>>>]<<<][-]<[->+<]>>[-]+<[[
-<+>]<++++++++++++++++++++++++++++++++++++++++++++++++.<++++++++++++++++++++
++++++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++++++++
++.>>>>-<]>[[-]>[-]<<<<[->>>>+<<<<]>>>>>[-]+<[[-<<<<+>>>>]<<<<++++++++++++++
++++++++++++++++++++++++++++++++++.<++++++++++++++++++++++++++++++++++++++++
++++++++.>>>>>>-<]>[[-]<<<<<<+++++++++++++++++++++++++++++++++++++++++++++++
+.>>>>>>]<<]<<<<<<+++++++++++++.<<[-]+++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++[>[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[>[-]+++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++[-]<-]<-]<<<<<]<<<<+>>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<
<<+>>>>>][-]++++<<[-]>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>
>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->
>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<<[->>+<<]>>[[-<<+>>]<<<[-]+>>>][-]<[->
+<]>[[-<+>]<<<[-]+>>>]<<<]<<->>[-]<<[->>+<<]>>[[-<<+>>]<<<<<<<<-<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>>>>[-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>
>>>>>>>>[-<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>-[<<<<+>
>>>-]<<<<]<<[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+<<<<]<<>>>>]>>[->>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-]>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>[-]>>>>>[-]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<<<<<<<<<+<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>>>
-[<<<<+>>>>-]<<<<]<<[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+<<<<]<<>>>>]>>[->>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[-]<[-
]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>>>[-]<<<<<<<<<[
->>>>>>>>>+<<<<<<<<<]>>>>>>>>>[-<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[<<<[-]<[-]<[-]+>>>
>>-[<<<<+>>>>-]<<<<]<<[->>+>+<<<]>>[-<<+>>]<[>>[->>>>+<<<<]<<>>>>]>>[->>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]>[-]>>>>>>>[-]++++++++>[-]>[-]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>>
>>>>>[-<+<<<<<<<<<<+>>>>>>>>>>>]<<<[-]>>>[-]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]>
[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<<<]>>>[[-<
<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<[->+<]>[[-<+>]<<<[-]+
>>>]<<<[<<<<<<<<--------->>+>>>>>>>[-]++++++++>[-]>[-]<<<<<<<<<<<[->>>>>>>>>
>>+<<<<<<<<<<<]>>>>>>>>>>>[-<+<<<<<<<<<<+>>>>>>>>>>>]<<<[-]>>>[-]>[-]<<<[->>
>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-
]<<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<
[->+<]>[[-<+>]<<<[-]+>>>]<<<]>[-]++>[-]>[-]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<
<<<]>>>>>>>>>>>[-<+<<<<<<<<<<+>>>>>>>>>>>]<<<[-]>>>[-]>[-]<<<[->>>+<<<]>>>[[
-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<<<[->>>+<
<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<[->+<]>[[-<
+>]<<<[-]+>>>]<<<[<<<<<<<<--->+>>>>>>>>[-]++>[-]>[-]<<<<<<<<<<<[->>>>>>>>>>>
+<<<<<<<<<<<]>>>>>>>>>>>[-<+<<<<<<<<<<+>>>>>>>>>>>]<<<[-]>>>[-]>[-]<<<[->>>+
<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<[<<->->[-]>[-]<
<<[->>>+<<<]>>>[[-<<<+>>>]>[-]<<<[->>>+<<<]>>>[[-<<<+>>>]<<[-]+>>]<]<][-]<[-
>+<]>[[-<+>]<<<[-]+>>>]<<<]<<<<+>>>]<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

View file

@ -1,212 +0,0 @@
A mandelbrot set fractal viewer in brainf*** written by Erik Bosman
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++
+++++++-[[>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>>>>>>>>[
-]<<<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+<<<<<<<<>+++++<>[<>-
<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>>+<<<<<<<<>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>[<<<>>>
>>>>>>[>>>>>>>[-]<<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>[-]+<<<<<<<
>++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>+<<<<<<<>++
+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>+<<<<<<<<<<
<<<<<<[<<<<<<<<<]>>>[<<<>>>[-]<<<>>>>>>>>>[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<
<<<<<>[-<>>>>>>>+<<<<<<<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<
]>>>>>>>>>[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]<<<<<<<<>[-<>>>>>>>>+<<<<<<<<>>
>>>>+<<<<<<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>[<<<<<<<>>>>>>
>-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>+<<<<<]>>>>>>>>>+++++++++
+++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<
<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>
>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<[->>[-<<+>>]<<[->>+<<
>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<<>>-<<>>>>
>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<<<[>[-]<->
>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<>>>>>>>>>>]<[->+<]>>>>]<<<<>[
<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>>[-<<<+>>>
]<<<[->>>+<<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<<>[<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<
<<<<>]<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<<<<<>>>>>>>>>>
+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<
>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>[-
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>+<<<[<<<<<<<<<]>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>>>[-<<
<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>
>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<
<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<
<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++
+++++++++++++++++++++<<>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>[-]<<]>>[<<<<<<<
+<[-<+>>>>+<<[-]]>[-><<<[->+>>>-<<<<]>>>]>>>>>>>>>>>>>[>>[-]<<>>>[-]<<<>
>>>[-]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]<<<>>>>>>>>>[>>>>>[-<<<<<>
+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>
>>>[>>[-<<<<<<<<<+>>>>>>>>>]<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++
+++++++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<
[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>[-<<+
>>]<<[->>+<<>>>+<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>
>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<
<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<
<<[>[-]<->>>[<<<>>>-<<<+>[<->-<<<<<<<<<<>>>+<<<>>>>>>>>>>]<[->+<]>>>]<<<
>[<>-<>>>+<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>
>>>>>+<<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>
>>+<<<<<<[->>[-<<+>>]<<[->>+<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]
<>]<>>>>>>>>>>[>>>>>>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>
>]<<<<<<<<<<<>]<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>
>+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<
<>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>[
-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<>>>>>>>>>]<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<
[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]
<<<<<<<<>[-<>>>>>>>>+<<<<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>
>>>>[>>>>>>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+<<<<>>>>>[<<<<<>>
>>>-<<<<<>>>>-<<<<+>>>>>]<<<<<>>>>>>[<<<<<<>>>>>>-<<<<<<[->>>>>+<<<<<>>>
>+<<<<>>>>+<<<<]>>>>>[<<<<<>>>>>-<<<<<+>>>>>]<<<<<>>>>-<<<<>>>>>+<<<<<>>
>>>>]<<<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>>>+<<<<<<>>>>>]<<<<<[->>>>>+<<<<<]>
>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>>>>>>>[-+>>[-<<->>]+<<
[->>-<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[
>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<<<>>[-<<+>>]<<[->>+<<<<<<<<<<<[<
<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<
<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>
>>>[>+<>>>[-<<<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>>
+<<<<<<>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>[-<<<>>>>>>+<<<<<<>>>]
<<<>>]<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>]<>>[-<<>>>>>>
+<<<<<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>>]<<>>>[-<<<>>>
>>>+<<<<<<>>>]<<<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+<<<>>>>>>>>
>[>+<>>[-<<>-<>>]<<>[-<>>+<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>>+<<<<<<>
>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>[-<<>>>>>>+<<<<<<>>]<<>>>]<<<
>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>]<<>]<>>>[-<<<>>>>>>+<<<<<<>>[
-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>]<<>>>]<<<>>[-<<>>>>>>+<<<<<<>>]<
<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>>>>>
>>>>]<<<<<<<<<[>[-<>>>>>>+<<<<<<>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><
>>>[-<<<>>>>>>+<<<<<<>>>]<<<>>]<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>
>><>>>]<<<>]<>>[-<<>>>>>>+<<<<<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>
><>>>]<<<>>]<<>>>[-<<<>>>>>>+<<<<<<>>>]<<<<<<<<<<<<]]>[-]<>>>[-]<<<>>>>[
-]<<<<>>>>>>>>>[>>[-]<<>>>[-]<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[
>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<
<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[
-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>
>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<
<<<<[->>[-<<+>>]<<[->>+<<>>>+<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>
>>>>>>>[>>>>>>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<
<<<<<<>]<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>
>>>>>]<<<<<<<<<[>[-]<->>>[<<<>>>-<<<+>[<->-<<<<<<<<<<>>>+<<<>>>>>>>>>>]<
[->+<]>>>]<<<>[<>-<>>>+<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<>>>>>>>>>]<<
<<<<<<<[<<<<<<<<<]>>>>>[-]<<<<<>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]<<<
<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[-+>>>[-<<<->>>
]+<<<[->>>-<<<>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]
+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+
>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<
]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>
]<<<[->>>+<<<>>>>>>>>>[>+<>>>>[-<<<<>-<>>>>]<<<<>[-<>>>>+<<<<>]<>>>>>>>>
>]<<<<<<<<<>+<[>[-<>>+<<>>>[-<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>[-<<<<>>+<
<>>>>]<<<<>>>]<<<>>>>[-<<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>]<<<<>]<>>>[-<<
<>>+<<>>>>[-<<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>]<<<<>>>]<<<>>>>[-<<<<>>+<
<>>>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>+<>>>[-<<
<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>+<<>>>>[-<<<<>>-<<
><<<<<<<<<+>>>>>>>>><>>>[-<<<>>+<<>>>]<<<>>>>]<<<<>>>[-<<<>>-<<><<<<<<<<
<+>>>>>>>>><>>>]<<<>]<>>>>[-<<<<>>+<<>>>[-<<<>>-<<><<<<<<<<<+>>>>>>>>><>
>>]<<<>>>>]<<<<>>>[-<<<>>+<<>>>]<<<<<<<<<<<<]>>>>>+<<<<<]>>>>>>>>>[>>>[-
]<<<>>>>[-]<<<<>>>>>[-]<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]<<<>>>>[
-]<<<<>>>>>>>>>[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<<<<<<>[-<>>>>>>>+<<<<<<<>>>
+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>
-<<<<+>>>>>]<<<<<>>>>>>>[<<<<<<<>>>>>>>-<<<<<<<[->>>>>+<<<<<>>>>+<<<<>>>
>+<<<<]>>>>>[<<<<<>>>>>-<<<<<+>>>>>]<<<<<>>>>-<<<<>>>>>+<<<<<>>>>>>>]<<<
<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>>>>+<<<<<<<>>>>>]<<<<<[->>>>>+<<<<<]+>>>>[
-<<<<->>>>]+<<<<[->>>>-<<<<>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>[-<<+
>>]<<[->>+<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>
[-<<->>]+<<[->>-<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<
<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<
<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+<<<>>>>>>>>>[>+<>>[-<<>-<>>]<<>[-<>
>+<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>+<<<<<>>>[-<<<>>>>>-<<<<<><<<<<<<
<<+>>>>>>>>><>>[-<<>>>>>+<<<<<>>]<<>>>]<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>
>>>>>>><>>]<<>]<>>>[-<<<>>>>>+<<<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>>
<>>]<<>>>]<<<>>[-<<>>>>>+<<<<<>>]<<<<<<<<<<<]>>>>>[-]<<<<<>>>>>>>[<<<<<<
<>>>>>>>-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>+<<<<<]]>>>>[-<<<<
+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>+<>>>[-<<<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>
>>>]<<<<<<<<<>+<[>[-<>>>>>+<<<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>
>[-<<<>>>>>+<<<<<>>>]<<<>>]<<>>>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>
]<<<>]<>>[-<<>>>>>+<<<<<>>>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>
>]<<>>>[-<<<>>>>>+<<<<<>>>]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>>>]<<<
<[->>>>+<<<<>>>>>[-]<<<<<>>>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>>>>>>>]<<<<<<<[
->>>>>>>+<<<<<<<>>>>>+<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-<>>>>>+<<<<
<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>[-<<<>>>>>+<<<<<>>>]<<<>>]<<>>
>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>]<>>[-<<>>>>>+<<<<<>>>[-<<
<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>>]<<>>>[-<<<>>>>>+<<<<<>>>]<<<<
<<<<<<<<]]>>>>>>>>>[>>[-]<<>>>[-]<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]
<<<>>>>[-]<<<<>>>>>>>>>[>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]
<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>
[-<>>>>>>+<<<<<<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++
+++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<
<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>
>>>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<[->>[-<<+>>]<<[->>+
<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>>>>>]<<<
<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<<>>-<<>>
>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<<<[>[-]<
->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<>>>>>>>>>>]<[->+<]>>>>]<<<<
>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]
>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>>[-<<<+>
>>]<<<[->>>+<<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[
>>>>>>>>>]<<<<<<<<<<>[<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<
<<<<<<>]<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<<<<<>>>>>>>>
>>+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<
<<>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>
[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>
>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>+<<<[<<<<<<<<<]>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>>>[-
<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>
>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<
<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<
<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>-<<>>>>[-<<<<+>>>>]<<<<[->>>>+
<<<<>>[-]<<]>>]<<+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[<<<<>>>>-<<
<<<<<.>>>>>>>]<<<<>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<>>>>>>>>>[>[-]>[-]>[-]>[
-]>[-]>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]<<<<<>>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<
>]<>>>>>>>>>>]<>>>>>+<<<<<>>>>>>>>>>>>>>+<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>
>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>>>[-]<<<<<<<>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<<<<<<>[-<>>>>>>>+<<<<<<<[
<<<<<<<<<]>>>>>>>[-]+<<<<<<<>>>>>>>>>>]<<<<<<<<<<]]>>>>>>>[-<<<<<<<+>>>>
>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>>>>>[>+<>>>>>[-<<<<<>-<>>>>>]<<<<<>[-<>
>>>>+<<<<<>]<>>>>>>>>>]<<<<<<<<<>>>>>>>+<<<<<<<[>>>>>[<<<<<>>>>>-<<<<<>>
>>>>>+<<<<<<<>>>>>]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<->>
>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>+<<<<<<<>>>>>>>>>>]<
[->+<]>>>>>>>]<<<<<<<>[<>-<>>>>>>>+<<<<<<<>]<+<<<<<<<<<]>>>>>>>-<<<<<<<>
>>[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<<<<<<>>>>>>>>>[>
>>>>[<<<<<>>>>>-<<<<<>>>>>>>+<<<<<<<>>>>>]<<<<<>>>>>>>>>]<<<<<<<<<[>[-]<
->>>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>+<<<<<<<>>>>>>>>>
>]<[->+<]>>>>>>>]<<<<<<<>[<>-<>>>>>>>+<<<<<<<>]<+<<<<<<<<<]>+++++<>[<>-<
>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>+<<<<<[<<<<<<<<<]>>>>>>>>
>[-+>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>-<<<<<>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<
<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>
+<]]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<<<<<<>>>>>[-<<<<<+>>>>
>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[
-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<
<<<>+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>-<<<<<[<<
<<<<<<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<
<]>+++++++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>+<<<<
<<>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<<<+>>>>>>>>]
<<<<<<<<[->>>>>>>>+<<<<<<<<>>>>>>>>[-]<<<<<<<<>>>>>>>>>[>>>>>>>>>]<<<<<<
<<<[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]<<<<<<<<>[-<>>>>>>>>+<<<<<<<<[<<<<<<<<
<]>>>>>>>>[-]+<<<<<<<<>>>>>>>>>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<<<<+>>>>>>>>
]<<<<<<<<[->>>>>>>>+<<<<<<<<>>>>>>>>>[>+<>>>>>>[-<<<<<<>-<>>>>>>]<<<<<<>
[-<>>>>>>+<<<<<<>]<>>>>>>>>>]<<<<<<<<<>>>>>>>>+<<<<<<<<[>>>>>>[<<<<<<>>>
>>>-<<<<<<>>>>>>>>+<<<<<<<<>>>>>>]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<
<<<<<<<[>[-]<->>>>>>>>[<<<<<<<<>>>>>>>>-<<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>
>+<<<<<<<<>>>>>>>>>>]<[->+<]>>>>>>>>]<<<<<<<<>[<>-<>>>>>>>>+<<<<<<<<>]<+
<<<<<<<<<]>>>>>>>>-<<<<<<<<>>>[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<
<<<<[->>>>>>>>-<<<<<<<<>>>>>>>>>[>>>>>>[<<<<<<>>>>>>-<<<<<<>>>>>>>>+<<<<
<<<<>>>>>>]<<<<<<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>>>>>[<<<<<<<<>>>>>>>>-<<<
<<<<<+>[<->-<<<<<<<<<<>>>>>>>>+<<<<<<<<>>>>>>>>>>]<[->+<]>>>>>>>>]<<<<<<
<<>[<>-<>>>>>>>>+<<<<<<<<>]<+<<<<<<<<<]>+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<
<<<<<<<>]<>>>>>>>>>>]<>>>>>>+<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<
<<<[<<<<<<<<<]>>>>>>>>>[-+>>>>>>[-<<<<<<->>>>>>]+<<<<<<[->>>>>>-<<<<<<>>
>>>>>>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<
<<<<[->>>>>>>>-<<<<<<<<>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<
<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<
<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<<>+++++<>[<>-<>[<>-<>>>>
>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>-<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>-<<<<<<[<<<<<<<<<]]>>>]<<<

View file

@ -1,55 +0,0 @@
use std::io::{Read, Write};
use bumpalo::Bump;
use criterion::{black_box, criterion_main, Criterion};
struct MockReadWrite;
impl Read for MockReadWrite {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
buf.fill(b'A');
Ok(buf.len())
}
}
impl Write for MockReadWrite {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
fn run_bf(bf: &str) {
let bump = Bump::new();
let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap();
let hir = brainfuck::hir::optimized_hir(&bump, &ast);
let lir = brainfuck::lir::generate(&bump, &hir);
brainfuck::lir::interpreter::run(&lir, MockReadWrite, MockReadWrite, |_| {});
}
fn optimized(c: &mut Criterion) {
let fizzbuzz = include_str!("fizzbuzz.bf");
let bench = include_str!("bench.bf");
let twinkle = include_str!("twinkle.bf");
let bottles = include_str!("bottles.bf");
let mandelbrot = include_str!("mandelbrot.bf");
let hanoi = include_str!("hanoi.bf");
c.bench_function("fizzbuzz", |b| b.iter(|| run_bf(black_box(fizzbuzz))));
c.bench_function("bench", |b| b.iter(|| run_bf(black_box(bench))));
c.bench_function("twinkle", |b| b.iter(|| run_bf(black_box(twinkle))));
c.bench_function("bottles", |b| b.iter(|| run_bf(black_box(bottles))));
c.bench_function("mandelbrot", |b| b.iter(|| run_bf(black_box(mandelbrot))));
c.bench_function("hanoi", |b| b.iter(|| run_bf(black_box(hanoi))));
}
pub fn benches() {
// we need such a low sample size because the benches take ages otherwise
let mut c = Criterion::default().configure_from_args().sample_size(30);
optimized(&mut c);
}
criterion_main!(benches);

File diff suppressed because one or more lines are too long

View file

@ -1,212 +0,0 @@
A mandelbrot set fractal viewer in brainf*** written by Erik Bosman
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++
+++++++-[[>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>>>>>>>>[
-]<<<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+<<<<<<<<>+++++<>[<>-
<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>>+<<<<<<<<>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>[<<<>>>
>>>>>>[>>>>>>>[-]<<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>[-]+<<<<<<<
>++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>+<<<<<<<>++
+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>>+<<<<<<<<<<
<<<<<<[<<<<<<<<<]>>>[<<<>>>[-]<<<>>>>>>>>>[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<
<<<<<>[-<>>>>>>>+<<<<<<<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<
]>>>>>>>>>[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]<<<<<<<<>[-<>>>>>>>>+<<<<<<<<>>
>>>>+<<<<<<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>[<<<<<<<>>>>>>
>-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>+<<<<<]>>>>>>>>>+++++++++
+++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<
<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>
>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<[->>[-<<+>>]<<[->>+<<
>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<<>>-<<>>>>
>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<<<[>[-]<->
>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<>>>>>>>>>>]<[->+<]>>>>]<<<<>[
<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>>[-<<<+>>>
]<<<[->>>+<<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<<>[<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<
<<<<>]<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<<<<<>>>>>>>>>>
+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<
>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>[-
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>+<<<[<<<<<<<<<]>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>>>[-<<
<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>
>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<
<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<
<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++
+++++++++++++++++++++<<>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>[-]<<]>>[<<<<<<<
+<[-<+>>>>+<<[-]]>[-><<<[->+>>>-<<<<]>>>]>>>>>>>>>>>>>[>>[-]<<>>>[-]<<<>
>>>[-]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]<<<>>>>>>>>>[>>>>>[-<<<<<>
+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>
>>>[>>[-<<<<<<<<<+>>>>>>>>>]<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++
+++++++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<
[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>[-<<+
>>]<<[->>+<<>>>+<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>
>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<
<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<
<<[>[-]<->>>[<<<>>>-<<<+>[<->-<<<<<<<<<<>>>+<<<>>>>>>>>>>]<[->+<]>>>]<<<
>[<>-<>>>+<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>
>>>>>+<<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>
>>+<<<<<<[->>[-<<+>>]<<[->>+<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]
<>]<>>>>>>>>>>[>>>>>>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>
>]<<<<<<<<<<<>]<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>
>+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<
<>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>[
-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<>>>>>>>>>]<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<
[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]
<<<<<<<<>[-<>>>>>>>>+<<<<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>
>>>>[>>>>>>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+<<<<>>>>>[<<<<<>>
>>>-<<<<<>>>>-<<<<+>>>>>]<<<<<>>>>>>[<<<<<<>>>>>>-<<<<<<[->>>>>+<<<<<>>>
>+<<<<>>>>+<<<<]>>>>>[<<<<<>>>>>-<<<<<+>>>>>]<<<<<>>>>-<<<<>>>>>+<<<<<>>
>>>>]<<<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>>>+<<<<<<>>>>>]<<<<<[->>>>>+<<<<<]>
>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>>>>>>>[-+>>[-<<->>]+<<
[->>-<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[
>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<<<>>[-<<+>>]<<[->>+<<<<<<<<<<<[<
<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<
<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>
>>>[>+<>>>[-<<<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>>
+<<<<<<>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>[-<<<>>>>>>+<<<<<<>>>]
<<<>>]<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>]<>>[-<<>>>>>>
+<<<<<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>>]<<>>>[-<<<>>>
>>>+<<<<<<>>>]<<<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+<<<>>>>>>>>
>[>+<>>[-<<>-<>>]<<>[-<>>+<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>>+<<<<<<>
>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>[-<<>>>>>>+<<<<<<>>]<<>>>]<<<
>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>]<<>]<>>>[-<<<>>>>>>+<<<<<<>>[
-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><>>]<<>>>]<<<>>[-<<>>>>>>+<<<<<<>>]<
<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>>>>>
>>>>]<<<<<<<<<[>[-<>>>>>>+<<<<<<>>[-<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>><
>>>[-<<<>>>>>>+<<<<<<>>>]<<<>>]<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>
>><>>>]<<<>]<>>[-<<>>>>>>+<<<<<<>>>[-<<<>>>>>>-<<<<<<><<<<<<<<<+>>>>>>>>
><>>>]<<<>>]<<>>>[-<<<>>>>>>+<<<<<<>>>]<<<<<<<<<<<<]]>[-]<>>>[-]<<<>>>>[
-]<<<<>>>>>>>>>[>>[-]<<>>>[-]<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[
>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]<>>>>>>>>>]<<<<<<<<<[<<<
<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[
-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>
>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<
<<<<[->>[-<<+>>]<<[->>+<<>>>+<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>
>>>>>>>[>>>>>>>>>]<<<<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<
<<<<<<>]<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>
>>>>>]<<<<<<<<<[>[-]<->>>[<<<>>>-<<<+>[<->-<<<<<<<<<<>>>+<<<>>>>>>>>>>]<
[->+<]>>>]<<<>[<>-<>>>+<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<>>>>>>>>>]<<
<<<<<<<[<<<<<<<<<]>>>>>[-]<<<<<>>>>>>>>>++++++++++++++++-[[>>>>>>>>>]<<<
<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[-+>>>[-<<<->>>
]+<<<[->>>-<<<>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]
+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+
>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<
]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>
]<<<[->>>+<<<>>>>>>>>>[>+<>>>>[-<<<<>-<>>>>]<<<<>[-<>>>>+<<<<>]<>>>>>>>>
>]<<<<<<<<<>+<[>[-<>>+<<>>>[-<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>[-<<<<>>+<
<>>>>]<<<<>>>]<<<>>>>[-<<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>]<<<<>]<>>>[-<<
<>>+<<>>>>[-<<<<>>-<<><<<<<<<<<+>>>>>>>>><>>>>]<<<<>>>]<<<>>>>[-<<<<>>+<
<>>>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>+<>>>[-<<
<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>+<<>>>>[-<<<<>>-<<
><<<<<<<<<+>>>>>>>>><>>>[-<<<>>+<<>>>]<<<>>>>]<<<<>>>[-<<<>>-<<><<<<<<<<
<+>>>>>>>>><>>>]<<<>]<>>>>[-<<<<>>+<<>>>[-<<<>>-<<><<<<<<<<<+>>>>>>>>><>
>>]<<<>>>>]<<<<>>>[-<<<>>+<<>>>]<<<<<<<<<<<<]>>>>>+<<<<<]>>>>>>>>>[>>>[-
]<<<>>>>[-]<<<<>>>>>[-]<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]<<<>>>>[
-]<<<<>>>>>>>>>[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<<<<<<>[-<>>>>>>>+<<<<<<<>>>
+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>
-<<<<+>>>>>]<<<<<>>>>>>>[<<<<<<<>>>>>>>-<<<<<<<[->>>>>+<<<<<>>>>+<<<<>>>
>+<<<<]>>>>>[<<<<<>>>>>-<<<<<+>>>>>]<<<<<>>>>-<<<<>>>>>+<<<<<>>>>>>>]<<<
<<<<>>>>>[<<<<<>>>>>-<<<<<>>>>>>>+<<<<<<<>>>>>]<<<<<[->>>>>+<<<<<]+>>>>[
-<<<<->>>>]+<<<<[->>>>-<<<<>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>[-<<+
>>]<<[->>+<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>
[-<<->>]+<<[->>-<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<
<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<
<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+<<<>>>>>>>>>[>+<>>[-<<>-<>>]<<>[-<>
>+<<>]<>>>>>>>>>]<<<<<<<<<>+<[>[-<>>>>>+<<<<<>>>[-<<<>>>>>-<<<<<><<<<<<<
<<+>>>>>>>>><>>[-<<>>>>>+<<<<<>>]<<>>>]<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>
>>>>>>><>>]<<>]<>>>[-<<<>>>>>+<<<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>>
<>>]<<>>>]<<<>>[-<<>>>>>+<<<<<>>]<<<<<<<<<<<]>>>>>[-]<<<<<>>>>>>>[<<<<<<
<>>>>>>>-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>+<<<<<]]>>>>[-<<<<
+>>>>]<<<<[->>>>+<<<<>>>>>>>>>[>+<>>>[-<<<>-<>>>]<<<>[-<>>>+<<<>]<>>>>>>
>>>]<<<<<<<<<>+<[>[-<>>>>>+<<<<<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>
>[-<<<>>>>>+<<<<<>>>]<<<>>]<<>>>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>
]<<<>]<>>[-<<>>>>>+<<<<<>>>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>
>]<<>>>[-<<<>>>>>+<<<<<>>>]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>>>]<<<
<[->>>>+<<<<>>>>>[-]<<<<<>>>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>>>>>>>]<<<<<<<[
->>>>>>>+<<<<<<<>>>>>+<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-<>>>>>+<<<<
<>>[-<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>[-<<<>>>>>+<<<<<>>>]<<<>>]<<>>
>[-<<<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>]<>>[-<<>>>>>+<<<<<>>>[-<<
<>>>>>-<<<<<><<<<<<<<<+>>>>>>>>><>>>]<<<>>]<<>>>[-<<<>>>>>+<<<<<>>>]<<<<
<<<<<<<<]]>>>>>>>>>[>>[-]<<>>>[-]<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]
<<<>>>>[-]<<<<>>>>>>>>>[>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<>>+<<>]
<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>
[-<>>>>>>+<<<<<<>>>+<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++
+++++++++-[[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<
<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>
>>>>>>>>[>-<>>>>>[-<<<<<>+<>>>>>]<<<<<>[-<>>>>>+<<<<<[->>[-<<+>>]<<[->>+
<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[>>>>>>>>>]<<<
<<<<<<<>[<>>[<<>>-<<>>>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>]<>>[<<>>-<<>>
>>>>>>>>>+<<<<<<<<<<<>>]<<<<<<<<<<<>>>>>>>>>>+<>>>>>>>>>]<<<<<<<<<[>[-]<
->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<<<>>>>>>>>>>]<[->+<]>>>>]<<<<
>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>+<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]
>>>>>>>>>[>-<>>>>>>[-<<<<<<>+<>>>>>>]<<<<<<>[-<>>>>>>+<<<<<<[->>>[-<<<+>
>>]<<<[->>>+<<<>>>>+<<<<]+>>>>>>>>>]><<<<<<<<<[<<<<<<<<<]<>]<>>>>>>>>>>[
>>>>>>>>>]<<<<<<<<<<>[<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<
<<<<<<>]<>>>[<<<>>>-<<<>>>>>>>>>>>>+<<<<<<<<<<<<>>>]<<<<<<<<<<<<>>>>>>>>
>>+<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>[<<<<>>>>-<<<<+>[<->-<<<<<<<<<<>>>>+<<
<<>>>>>>>>>>]<[->+<]>>>>]<<<<>[<>-<>>>>+<<<<>]<+<<<<<<<<<]>>>>>>>>>[>>>>
[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>]<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++++++++++-[[>>>>>>
>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+<<<<<<<<<>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>+<<<[<<<<<<<<<]>>>>>>>>>[-+>>>[-<<<->>>]+<<<[->>>-<<<>>>>[-
<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>
>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<>>>[-<<<+>>>]<<<[->>>+<<<<<<<
<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<
<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>-<<>>>>[-<<<<+>>>>]<<<<[->>>>+
<<<<>>[-]<<]>>]<<+>>>>[-<<<<->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[<<<<>>>>-<<
<<<<<.>>>>>>>]<<<<>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<>>>>>>>>>[>[-]>[-]>[-]>[
-]>[-]>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]<<<<<>>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<
>]<>>>>>>>>>>]<>>>>>+<<<<<>>>>>>>>>>>>>>+<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>
>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>>>[-]<<<<<<<>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>>>>>>[-<<<<<<<>+<>>>>>>>]<<<<<<<>[-<>>>>>>>+<<<<<<<[
<<<<<<<<<]>>>>>>>[-]+<<<<<<<>>>>>>>>>>]<<<<<<<<<<]]>>>>>>>[-<<<<<<<+>>>>
>>>]<<<<<<<[->>>>>>>+<<<<<<<>>>>>>>>>[>+<>>>>>[-<<<<<>-<>>>>>]<<<<<>[-<>
>>>>+<<<<<>]<>>>>>>>>>]<<<<<<<<<>>>>>>>+<<<<<<<[>>>>>[<<<<<>>>>>-<<<<<>>
>>>>>+<<<<<<<>>>>>]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<->>
>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>+<<<<<<<>>>>>>>>>>]<
[->+<]>>>>>>>]<<<<<<<>[<>-<>>>>>>>+<<<<<<<>]<+<<<<<<<<<]>>>>>>>-<<<<<<<>
>>[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<<<<<<>>>>>>>>>[>
>>>>[<<<<<>>>>>-<<<<<>>>>>>>+<<<<<<<>>>>>]<<<<<>>>>>>>>>]<<<<<<<<<[>[-]<
->>>>>>>[<<<<<<<>>>>>>>-<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>+<<<<<<<>>>>>>>>>
>]<[->+<]>>>>>>>]<<<<<<<>[<>-<>>>>>>>+<<<<<<<>]<+<<<<<<<<<]>+++++<>[<>-<
>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>+<<<<<[<<<<<<<<<]>>>>>>>>
>[-+>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>-<<<<<>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<
<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>
+<]]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<<<<<<>>>>>[-<<<<<+>>>>
>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[
-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<
<<<>+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>-<<<<<[<<
<<<<<<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]<<<<<<>>>>>>>>>]<<<<<<<<<[<<<<<<<<
<]>+++++++++<>[<>-<>[<>-<>>>>>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>+<<<<
<<>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<<<+>>>>>>>>]
<<<<<<<<[->>>>>>>>+<<<<<<<<>>>>>>>>[-]<<<<<<<<>>>>>>>>>[>>>>>>>>>]<<<<<<
<<<[>>>>>>>>[-<<<<<<<<>+<>>>>>>>>]<<<<<<<<>[-<>>>>>>>>+<<<<<<<<[<<<<<<<<
<]>>>>>>>>[-]+<<<<<<<<>>>>>>>>>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<<<<+>>>>>>>>
]<<<<<<<<[->>>>>>>>+<<<<<<<<>>>>>>>>>[>+<>>>>>>[-<<<<<<>-<>>>>>>]<<<<<<>
[-<>>>>>>+<<<<<<>]<>>>>>>>>>]<<<<<<<<<>>>>>>>>+<<<<<<<<[>>>>>>[<<<<<<>>>
>>>-<<<<<<>>>>>>>>+<<<<<<<<>>>>>>]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<
<<<<<<<[>[-]<->>>>>>>>[<<<<<<<<>>>>>>>>-<<<<<<<<+>[<->-<<<<<<<<<<>>>>>>>
>+<<<<<<<<>>>>>>>>>>]<[->+<]>>>>>>>>]<<<<<<<<>[<>-<>>>>>>>>+<<<<<<<<>]<+
<<<<<<<<<]>>>>>>>>-<<<<<<<<>>>[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<
<<<<[->>>>>>>>-<<<<<<<<>>>>>>>>>[>>>>>>[<<<<<<>>>>>>-<<<<<<>>>>>>>>+<<<<
<<<<>>>>>>]<<<<<<>>>>>>>>>]<<<<<<<<<[>[-]<->>>>>>>>[<<<<<<<<>>>>>>>>-<<<
<<<<<+>[<->-<<<<<<<<<<>>>>>>>>+<<<<<<<<>>>>>>>>>>]<[->+<]>>>>>>>>]<<<<<<
<<>[<>-<>>>>>>>>+<<<<<<<<>]<+<<<<<<<<<]>+++++<>[<>-<>[<>-<>>>>>>>>>>+<<<
<<<<<<<>]<>>>>>>>>>>]<>>>>>>+<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<
<<<[<<<<<<<<<]>>>>>>>>>[-+>>>>>>[-<<<<<<->>>>>>]+<<<<<<[->>>>>>-<<<<<<>>
>>>>>>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+<<<<>>>>>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<
<<<<[->>>>>>>>-<<<<<<<<>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<
<<<[<<<<<<<<<]>>>[-]+<<<>>>>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<
<<<<<>]<>>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<<>+++++<>[<>-<>[<>-<>>>>
>>>>>>+<<<<<<<<<<>]<>>>>>>>>>>]<>>>>>>-<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>-<<<<<<[<<<<<<<<<]]>>>]<<<

View file

@ -1,2 +0,0 @@
[toolchain]
channel = "nightly-2022-04-17"

View file

@ -1,102 +0,0 @@
use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use dbg_pls::DebugPls;
use crate::{
parse::{Ast, Instr, Span},
BumpVec,
};
pub mod opts;
#[derive(Clone)]
pub struct Hir<'hir> {
pub stmts: BumpVec<'hir, Stmt<'hir>>,
}
impl Debug for Hir<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.stmts, f)
}
}
impl DebugPls for Hir<'_> {
fn fmt(&self, f: dbg_pls::Formatter<'_>) {
DebugPls::fmt(&self.stmts.iter().collect::<Vec<_>>(), f)
}
}
#[derive(Clone)]
pub struct Stmt<'hir> {
pub kind: StmtKind<'hir>,
pub span: Span,
}
impl<'hir> Stmt<'hir> {
fn new(kind: StmtKind<'hir>, span: Span) -> Stmt<'hir> {
Self { kind, span }
}
pub fn kind(&self) -> &StmtKind<'hir> {
&self.kind
}
}
impl Debug for Stmt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.kind, f)
}
}
impl DebugPls for Stmt<'_> {
fn fmt(&self, f: dbg_pls::Formatter<'_>) {
DebugPls::fmt(&self.kind, f)
}
}
#[derive(Debug, Clone, DebugPls)]
pub enum StmtKind<'hir> {
Add(i32, u8),
Sub(i32, u8),
/// Sets the current cell to 0 and adds that value of the cell to another cell at `offset`
MoveAddTo {
offset: i32,
},
Right(usize),
Left(usize),
Loop(Hir<'hir>),
Out,
In,
SetN(u8),
}
fn ast_to_ir<'hir>(alloc: &'hir Bump, ast: &Ast<'_>) -> Hir<'hir> {
let mut stmts = Vec::new_in(alloc);
let stmts_iter = ast.iter().map(|(instr, span)| {
let kind = match instr {
Instr::Add => StmtKind::Add(0, 1),
Instr::Sub => StmtKind::Sub(0, 1),
Instr::Right => StmtKind::Right(1),
Instr::Left => StmtKind::Left(1),
Instr::Out => StmtKind::Out,
Instr::In => StmtKind::In,
Instr::Loop(body) => {
let ir_body = ast_to_ir(alloc, body);
StmtKind::Loop(ir_body)
}
};
Stmt::new(kind, *span)
});
stmts.extend(stmts_iter);
Hir { stmts }
}
pub fn optimized_hir<'hir>(alloc: &'hir Bump, ast: &Ast<'_>) -> Hir<'hir> {
let mut hir = ast_to_ir(alloc, ast);
opts::optimize(alloc, &mut hir);
hir
}

View file

@ -1,321 +0,0 @@
use std::cmp::Ordering;
use bumpalo::Bump;
use tracing::trace;
use crate::{
hir::{Hir, Stmt, StmtKind},
BumpVec,
};
pub fn optimize<'hir>(alloc: &'hir Bump, hir: &mut Hir<'hir>) {
pass_group(alloc, hir);
pass_find_set_null(hir);
pass_set_n(hir);
pass_cancel_left_right_add_sub(hir);
pass_add_sub_offset(hir);
pass_move_add_to(hir);
// pass_unroll_loops(hir);
// pass_cancel_left_right_add_sub(hir);
}
/// pass that replaces things like `Sub(1) Sub(1)` with `Sub(2)`
// TODO: This pass is really slow, speed it up please
#[tracing::instrument(skip(alloc, ir_param))]
fn pass_group<'hir>(alloc: &'hir Bump, ir_param: &mut Hir<'hir>) {
let empty_ir = Hir {
stmts: Vec::new_in(alloc),
};
let ir = std::mem::replace(ir_param, empty_ir);
let new_stmts = Vec::new_in(alloc);
let stmts =
ir.stmts
.into_iter()
.fold(new_stmts, |mut stmts: BumpVec<'hir, Stmt<'hir>>, next| {
let Some(old) = stmts.last_mut() else {
if let StmtKind::Loop(mut body) = next.kind {
pass_group(alloc, &mut body);
stmts.push(Stmt::new(
StmtKind::Loop(body),
next.span,
));
} else {
stmts.push(next);
}
return stmts;
};
match (&mut old.kind, next.kind) {
(StmtKind::Add(offset_a, a), StmtKind::Add(offset_b, b))
if *a < 255 && *offset_a == offset_b =>
{
old.span = old.span.merge(next.span);
*a += b;
}
(StmtKind::Sub(offset_a, a), StmtKind::Sub(offset_b, b))
if *a < 255 && *offset_a == offset_b =>
{
old.span = old.span.merge(next.span);
*a += b;
}
(StmtKind::Right(a), StmtKind::Right(b)) if *a < 255 => {
old.span = old.span.merge(next.span);
*a += b;
}
(StmtKind::Left(a), StmtKind::Left(b)) if *a < 255 => {
old.span = old.span.merge(next.span);
*a += b;
}
(_, StmtKind::Loop(mut body)) => {
pass_group(alloc, &mut body);
stmts.push(Stmt {
span: next.span,
kind: StmtKind::Loop(body),
});
}
(_, kind) => {
stmts.push(Stmt::new(kind, next.span));
}
}
stmts
});
*ir_param = Hir { stmts };
}
/// pass that replaces `Loop([Sub(_)])` to `SetNull`
#[tracing::instrument(skip(ir))]
fn pass_find_set_null(ir: &mut Hir<'_>) {
pass_find_set_null_inner(ir)
}
fn pass_find_set_null_inner(ir: &mut Hir<'_>) {
for stmt in &mut ir.stmts {
if let Stmt {
kind: StmtKind::Loop(body),
span,
} = stmt
{
if let [Stmt {
kind: StmtKind::Sub(0, _),
..
}] = body.stmts.as_slice()
{
trace!(?span, "Replacing Statement with SetNull");
*stmt = Stmt::new(StmtKind::SetN(0), *span);
} else {
pass_find_set_null_inner(body);
}
}
}
}
/// pass that replaces `SetN(n) Add(m)` with `SetN(n + m)`
#[tracing::instrument(skip(ir))]
fn pass_set_n(ir: &mut Hir<'_>) {
pass_set_n_inner(ir)
}
fn pass_set_n_inner(ir: &mut Hir<'_>) {
window_pass(ir, pass_set_n_inner, |[a, b]| {
if let StmtKind::SetN(before) = a.kind() {
let new = match b.kind() {
StmtKind::Add(0, n) => StmtKind::SetN(before.wrapping_add(*n)),
StmtKind::Sub(0, n) => StmtKind::SetN(before.wrapping_sub(*n)),
_ => {
return WindowPassAction::None;
}
};
return WindowPassAction::Merge(new);
}
WindowPassAction::None
});
}
/// pass that replaces `Left(5) Right(3)` with `Left(2)`
#[tracing::instrument(skip(ir))]
fn pass_cancel_left_right_add_sub(ir: &mut Hir<'_>) {
pass_cancel_left_right_add_sub_inner(ir)
}
fn pass_cancel_left_right_add_sub_inner(ir: &mut Hir<'_>) {
window_pass(ir, pass_cancel_left_right_add_sub_inner, |[a, b]| {
match (a.kind(), b.kind()) {
(StmtKind::Right(r), StmtKind::Left(l)) | (StmtKind::Left(l), StmtKind::Right(r)) => {
let new = match r.cmp(l) {
Ordering::Equal => {
return WindowPassAction::RemoveAll;
}
Ordering::Less => StmtKind::Left(l - r),
Ordering::Greater => StmtKind::Right(r - l),
};
WindowPassAction::Merge(new)
}
(StmtKind::Add(offset_a, r), StmtKind::Sub(offset_b, l))
| (StmtKind::Sub(offset_a, l), StmtKind::Add(offset_b, r))
if offset_a == offset_b =>
{
let new = match r.cmp(l) {
Ordering::Equal => return WindowPassAction::RemoveAll,
Ordering::Less => StmtKind::Sub(*offset_a, l - r),
Ordering::Greater => StmtKind::Add(*offset_a, r - l),
};
WindowPassAction::Merge(new)
}
_ => WindowPassAction::None,
}
})
}
/// pass that replaces `Right(9) Add(5) Left(9)` with `AddOffset(9, 5)`
#[tracing::instrument(skip(ir))]
fn pass_add_sub_offset(ir: &mut Hir<'_>) {
pass_add_sub_offset_inner(ir)
}
fn pass_add_sub_offset_inner(ir: &mut Hir<'_>) {
window_pass(ir, pass_add_sub_offset_inner, |[a, b, c]| {
match (a.kind(), b.kind(), c.kind()) {
(StmtKind::Right(r), StmtKind::Add(0, n), StmtKind::Left(l)) if r == l => {
WindowPassAction::Merge(StmtKind::Add(i32::try_from(*r).unwrap(), *n))
}
(StmtKind::Left(l), StmtKind::Add(0, n), StmtKind::Right(r)) if r == l => {
WindowPassAction::Merge(StmtKind::Add(-i32::try_from(*r).unwrap(), *n))
}
(StmtKind::Right(r), StmtKind::Sub(0, n), StmtKind::Left(l)) if r == l => {
WindowPassAction::Merge(StmtKind::Sub(i32::try_from(*r).unwrap(), *n))
}
(StmtKind::Left(l), StmtKind::Sub(0, n), StmtKind::Right(r)) if r == l => {
WindowPassAction::Merge(StmtKind::Sub(-i32::try_from(*r).unwrap(), *n))
}
_ => WindowPassAction::None,
}
})
}
/// pass that replaces `Loop([Sub(1) AddOffset(o, 1)])` with `MoveAddTo(o)`
#[tracing::instrument(skip(ir))]
fn pass_move_add_to(ir: &mut Hir<'_>) {
pass_move_add_to_inner(ir)
}
fn pass_move_add_to_inner(ir: &mut Hir<'_>) {
for stmt in &mut ir.stmts {
if let Stmt {
kind: StmtKind::Loop(body),
span,
} = stmt
{
if let [Stmt {
kind: StmtKind::Sub(0, 1),
..
}, Stmt {
kind: StmtKind::Add(offset, 1),
..
}]
| [Stmt {
kind: StmtKind::Add(offset, 1),
..
}, Stmt {
kind: StmtKind::Sub(0, 1),
..
}] = body.stmts.as_slice()
{
trace!(?span, ?offset, "Replacing Statement with MoveAddTo");
*stmt = Stmt::new(StmtKind::MoveAddTo { offset: *offset }, *span);
} else {
pass_move_add_to_inner(body);
}
}
}
}
#[tracing::instrument(skip(ir))]
fn pass_unroll_loops(ir: &mut Hir<'_>) {
let alloc = Bump::new();
pass_unroll_loops_inner(&alloc, ir);
}
fn pass_unroll_loops_inner(alloc: &Bump, ir: &mut Hir<'_>) {
window_pass(ir, pass_unroll_loops, |[a, b]| {
if let (StmtKind::SetN(n), StmtKind::Loop(body)) = (a.kind(), b.kind()) {
let mut stmts_vec = BumpVec::new_in(alloc);
let stmts = std::iter::repeat(body.stmts.iter())
.take(usize::from(*n))
.flatten()
.cloned();
stmts_vec.extend(stmts);
WindowPassAction::MergeMany(stmts_vec)
} else {
WindowPassAction::None
}
})
}
enum WindowPassAction<'hir, 'pass> {
None,
Merge(StmtKind<'hir>),
MergeMany(BumpVec<'pass, Stmt<'hir>>),
RemoveAll,
}
fn window_pass<'hir, 'pass, P, F, const N: usize>(ir: &mut Hir<'hir>, pass_recur: P, action: F)
where
P: Fn(&mut Hir<'hir>),
F: Fn([&Stmt<'hir>; N]) -> WindowPassAction<'hir, 'pass>,
{
assert!(N > 0);
let stmts = &mut ir.stmts;
let mut i = 0;
while i < stmts.len() {
let a = &mut stmts[i];
if let StmtKind::Loop(body) = &mut a.kind {
pass_recur(body);
}
if i + N > stmts.len() {
break; // there aren't N elements left
}
let mut elements = stmts[i..][..N].iter();
let elements = [(); N].map(|()| elements.next().unwrap());
let merged_span = elements[0].span.merge(elements.last().unwrap().span);
let result = action(elements);
match result {
WindowPassAction::None => {
// only increment i if we haven't removed anything
i += 1;
}
WindowPassAction::RemoveAll => {
trace!(?elements, "Removing all statements");
for _ in 0..N {
stmts.remove(i);
}
}
WindowPassAction::Merge(new) => {
trace!(?elements, ?new, "Merging statements");
for _ in 1..N {
stmts.remove(i);
}
stmts[i] = Stmt::new(new, merged_span);
}
WindowPassAction::MergeMany(new) => {
trace!(?elements, ?new, "Merging many");
for _ in 0..N {
stmts.remove(i);
}
for stmt in new.into_iter().rev() {
stmts.insert(i, stmt);
}
}
}
}
}

View file

@ -1,185 +0,0 @@
#![feature(allocator_api, let_else)]
#![feature(nonzero_ops)]
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(rust_2018_idioms)]
use std::{
fmt::Display,
io::{Read, Write},
path::PathBuf,
str::FromStr,
};
use bumpalo::Bump;
use owo_colors::OwoColorize;
use crate::parse::ParseError;
pub mod hir;
pub mod lir;
mod mir;
pub mod parse;
#[derive(clap::Parser, Default)]
#[clap(author, about)]
pub struct Args {
/// Print colored source code depending on how often it was run.
/// Makes the interpreter ~30% slower.
#[clap(short, long)]
pub profile: bool,
/// Dump the IR info (ast, hir, mir, lir)
#[clap(long)]
pub dump: Option<DumpKind>,
/// Use experimental mid-level IR
#[clap(long)]
pub mir: bool,
/// The file to run
pub file: PathBuf,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DumpKind {
Ast,
Hir,
Mir,
Lir,
}
impl FromStr for DumpKind {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ast" => Ok(Self::Ast),
"hir" => Ok(Self::Hir),
"mir" => Ok(Self::Mir),
"lir" => Ok(Self::Lir),
other => Err(format!("Invalid IR level: '{other}'")),
}
}
}
type BumpVec<'a, T> = Vec<T, &'a Bump>;
pub enum UseProfile {
Yes,
No,
}
pub fn run<R, W>(src: &str, stdout: W, stdin: R, config: &Args) -> Result<(), ParseError>
where
W: Write,
R: Read,
{
let ast_alloc = Bump::new();
let parsed = parse::parse(&ast_alloc, src.bytes().enumerate())?;
if let Some(DumpKind::Ast) = config.dump {
println!("{parsed:#?}");
return Ok(());
}
let hir_alloc = Bump::new();
let optimized_hir = hir::optimized_hir(&hir_alloc, &parsed);
if let Some(DumpKind::Hir) = config.dump {
println!("{}", dbg_pls::color(&optimized_hir));
return Ok(());
}
drop(parsed);
drop(ast_alloc);
if config.dump == Some(DumpKind::Mir) || config.mir {
let mir_alloc = Bump::new();
let mir = mir::optimized_mir(&mir_alloc, &optimized_hir);
if config.dump == Some(DumpKind::Mir) {
println!("{mir:#?}");
}
}
let cg_alloc = Bump::new();
let lir = lir::generate(&cg_alloc, &optimized_hir);
if let Some(DumpKind::Lir) = config.dump {
println!("{lir:#?}");
return Ok(());
}
drop(optimized_hir);
drop(hir_alloc);
match config.profile {
true => {
let mut code_profile_count = vec![0; lir.debug().len()];
lir::interpreter::run(&lir, stdout, stdin, |ip| unsafe {
*code_profile_count.get_unchecked_mut(ip) += 1;
});
let mut src_profile_count = vec![0u64; src.len()];
for (stmt_span, stmt_count) in lir.debug().iter().zip(&code_profile_count) {
for i in &mut src_profile_count[stmt_span.start()..stmt_span.end()] {
*i += stmt_count;
}
}
let max = src_profile_count.iter().max().copied().unwrap_or(0);
println!("\n\n---------------- Profile ----------------");
for (char, value) in src.bytes().zip(src_profile_count) {
print!("{}", color_by_profile(char as char, value, max));
}
}
false => {
lir::interpreter::run(&lir, stdout, stdin, |_| {});
}
}
Ok(())
}
fn color_by_profile(char: char, value: u64, max: u64) -> impl Display {
let max = max as f64;
let value = value as f64;
let ratio = value / max;
let logged = -ratio.log10();
let logged = (logged * 100.) as u64;
match logged {
0..=15 => char.bright_red().to_string(),
16..=70 => char.yellow().to_string(),
71..=300 => char.green().to_string(),
_ => char.default_color().to_string(),
}
}
#[cfg(test)]
mod tests {
use crate::Args;
#[test]
fn fizzbuzz() {
let str = include_str!("../benches/fizzbuzz.bf");
let mut stdout = Vec::new();
let stdin = [];
super::run(str, &mut stdout, stdin.as_slice(), &Args::default()).unwrap();
insta::assert_debug_snapshot!(String::from_utf8(stdout));
}
#[test]
fn mandelbrot() {
let str = include_str!("../benches/mandelbrot.bf");
let mut stdout = Vec::new();
let stdin = [];
super::run(str, &mut stdout, stdin.as_slice(), &Args::default()).unwrap();
insta::assert_debug_snapshot!(String::from_utf8(stdout));
}
}

View file

@ -1,139 +0,0 @@
use std::{
io::{Read, Write},
num::Wrapping,
};
use crate::lir::{Lir, Stmt};
const MEM_SIZE: usize = 32_000;
type Memory = [Wrapping<u8>; MEM_SIZE];
// `repr(C)` to make sure rustc never reorders the fields weirdly
// maybe useless, but seems to give tiny wins
#[repr(C)]
struct Interpreter<'lir, W, R, P> {
code: &'lir Lir<'lir>,
profile_collector: P,
ip: usize,
ptr: usize,
mem: Memory,
stdout: W,
stdin: R,
}
pub fn run<W, R, P>(code: &Lir<'_>, stdout: W, stdin: R, profile_collector: P)
where
W: Write,
R: Read,
P: FnMut(usize),
{
let mut interpreter = Interpreter {
code,
ip: 0,
ptr: 0,
stdout,
stdin,
mem: [Wrapping(0u8); MEM_SIZE],
profile_collector,
};
// SAFETY: `Lir` can only be produced by the `crate::lir` module, which is trusted to not
// produce out of bounds jumps and put the `End` at the end
unsafe {
interpreter.execute();
}
}
impl<'c, W: Write, R: Read, P> Interpreter<'c, W, R, P>
where
P: FnMut(usize),
{
unsafe fn execute(&mut self) {
let stmts = self.code.stmts();
loop {
// SAFETY: If the code ends with an `End` and there are no out of bounds jumps,
// `self.ip` will never be out of bounds
// Removing this bounds check speeds up execution by about 40%
debug_assert!(self.ip < stmts.len());
let instr = unsafe { *stmts.get_unchecked(self.ip) };
self.ip += 1;
match instr {
Stmt::Add(n) => {
*self.elem_mut() += n;
}
Stmt::Sub(n) => {
*self.elem_mut() -= n;
}
Stmt::AddOffset { offset, n } => *self.elem_mut_offset(offset) += n,
Stmt::SubOffset { offset, n } => *self.elem_mut_offset(offset) -= n,
Stmt::MoveAddTo { offset } => {
let value = self.elem();
*self.elem_mut() = Wrapping(0);
*self.elem_mut_offset(offset) += value;
}
Stmt::Right(n) => {
self.ptr += n as usize;
if self.ptr >= MEM_SIZE {
self.ptr = 0;
}
}
Stmt::Left(n) => {
if self.ptr < n as usize {
let diff = n as usize - self.ptr;
self.ptr = MEM_SIZE - 1 - diff;
} else {
self.ptr -= n as usize;
}
}
Stmt::Out => {
let char = self.elem() as char;
write!(self.stdout, "{char}").unwrap();
self.stdout.flush().unwrap();
}
Stmt::In => {
let mut buf = [0; 1];
self.stdin.read_exact(&mut buf).unwrap();
*self.elem_mut() = Wrapping(buf[0]);
}
Stmt::SetN(n) => {
*self.elem_mut() = Wrapping(n);
}
Stmt::JmpIfZero(pos) => {
if self.elem() == 0 {
self.ip = pos as usize;
}
}
Stmt::JmpIfNonZero(pos) => {
if self.elem() != 0 {
self.ip = pos as usize;
}
}
Stmt::End => break,
}
// this should be a no-op if `profile_collector` is does nothing
(self.profile_collector)(self.ip);
}
}
fn elem_mut_offset(&mut self, offset: i32) -> &mut Wrapping<u8> {
let ptr = self.ptr as isize;
let offset = offset as isize;
// SAFETY: `self.ptr` is never out of bounds
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked_mut((ptr + offset) as usize) }
}
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
// SAFETY: `self.ptr` is never out of bounds
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked_mut(self.ptr) }
}
fn elem(&self) -> u8 {
// SAFETY: `self.ptr` is never out of bounds
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked(self.ptr).0 }
}
}

View file

@ -1,137 +0,0 @@
//! codegen to flat code
//!
//! ```bf
//! ++[-].
//! ```
//! compiles down to
//! ```text
//! Add | Add | JmpIfZero | Sub | JumpIfNotZero | Out | End
//! | ^ | ^
//! +-------|-----------|---------|
//! +-----------+
//! ```
//!
//! technically, the `JumpIfNotZero` would be an unconditional Jmp to the `JmpIfZero`, but that's
//! a needless indirection.
//!
//! this module must not produce out of bounds jumps and always put the `End` instruction at the
//! end
pub mod interpreter;
use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use crate::{
hir::{Hir, Stmt as HirStmt, StmtKind as HirStmtKind},
parse::Span,
BumpVec,
};
#[derive(Debug, Clone, Copy)]
pub enum Stmt {
Add(u8),
Sub(u8),
AddOffset { offset: i32, n: u8 },
SubOffset { offset: i32, n: u8 },
MoveAddTo { offset: i32 },
Right(u32),
Left(u32),
Out,
In,
SetN(u8),
JmpIfZero(u32),
JmpIfNonZero(u32),
End,
}
const _: [(); 8] = [(); std::mem::size_of::<Stmt>()];
#[derive(Clone)]
pub struct Lir<'lir> {
stmts: BumpVec<'lir, Stmt>,
debug: BumpVec<'lir, Span>,
}
impl Debug for Lir<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.stmts.fmt(f)
}
}
impl Lir<'_> {
pub fn stmts(&self) -> &[Stmt] {
&self.stmts
}
pub fn debug(&self) -> &[Span] {
&self.debug
}
}
pub fn generate<'lir>(alloc: &'lir Bump, ir: &Hir<'_>) -> Lir<'lir> {
let stmts = Vec::new_in(alloc);
let debug = Vec::new_in(alloc);
let mut lir = Lir { stmts, debug };
hir_to_lir(&mut lir, &ir.stmts);
lir.stmts.push(Stmt::End);
lir.debug.push(Span::default());
assert_eq!(lir.stmts.len(), lir.debug.len());
lir
}
fn hir_to_lir<'lir>(lir: &mut Lir<'lir>, ir: &[HirStmt<'_>]) {
for ir_stmt in ir {
hir_stmt_to_lir_stmt(lir, ir_stmt);
}
debug_assert_eq!(lir.stmts.len(), lir.debug.len());
}
fn hir_stmt_to_lir_stmt<'lir>(lir: &mut Lir<'lir>, ir_stmt: &HirStmt<'_>) {
let stmt = match &ir_stmt.kind {
HirStmtKind::Add(0, n) => Stmt::Add(*n),
HirStmtKind::Sub(0, n) => Stmt::Sub(*n),
HirStmtKind::Add(offset, n) => Stmt::AddOffset {
offset: *offset,
n: *n,
},
HirStmtKind::Sub(offset, n) => Stmt::SubOffset {
offset: *offset,
n: *n,
},
HirStmtKind::MoveAddTo { offset } => Stmt::MoveAddTo { offset: *offset },
HirStmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()),
HirStmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()),
HirStmtKind::Out => Stmt::Out,
HirStmtKind::In => Stmt::In,
HirStmtKind::SetN(n) => Stmt::SetN(*n),
HirStmtKind::Loop(instr) => {
let skip_jmp_idx = lir.stmts.len();
lir.stmts.push(Stmt::JmpIfZero(0)); // placeholder
lir.debug.push(ir_stmt.span);
// compile the loop body now
hir_to_lir(lir, &instr.stmts);
// if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected
let first_loop_body_idx = skip_jmp_idx + 1;
lir.stmts
.push(Stmt::JmpIfNonZero(first_loop_body_idx.try_into().unwrap()));
lir.debug.push(ir_stmt.span);
// there will always at least be an `End` instruction after the loop
let after_loop_idx = lir.stmts.len();
// fix the placeholder with the actual index
lir.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx.try_into().unwrap());
return;
}
};
lir.stmts.push(stmt);
lir.debug.push(ir_stmt.span);
}

View file

@ -1,31 +0,0 @@
#![feature(allocator_api, let_else)]
#![warn(rust_2018_idioms)]
use std::{fs, io, process};
use brainfuck::Args;
use clap::Parser;
fn main() {
let stdout = io::stdout();
let stdout = stdout.lock();
let stdin = io::stdin();
let stdin = stdin.lock();
let args = Args::parse();
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
.without_time()
.init();
let src = fs::read_to_string(&args.file).unwrap_or_else(|err| {
eprintln!("error: Failed to read file: {err}");
process::exit(1);
});
brainfuck::run(&src, stdout, stdin, &args).unwrap_or_else(|_| {
eprintln!("error: Failed to parse brainfuck code");
process::exit(1);
});
}

View file

@ -1,120 +0,0 @@
//! an experimental MIR (mid-level-ir)
//!
//! The MIR consists of two parts. First, there are instructions (`Stmt`). These instructions
//! can be seen as an extended version of the default brainfuck instruction set `+-<>,.[]`.
//! These instructions modify the classic tape. What MIR does is that it attaches an abstract
//! `MemoryState` to *each* statement. This state contains all facts known about the state of the
//! tape at the point of execution of the statement.
//!
//! For example, for the code `++.`, the `MemoryState` for the `.` instruction contains a single
//! fact: "The current cell was written to, by the instruction before and with the value 2". MIR
//! tracks as much of the reads/writes to determine their dependencies and eliminate as many
//! of them as possible.
//!
//! Note that MIR is always pessimized, so if it can't determine for sure that something is true,
//! it will not act on it.
#![allow(dead_code)]
mod opts;
mod state;
use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use crate::{
hir::{Hir, StmtKind as HirStmtKind},
mir::state::{MemoryState, Store},
parse::Span,
BumpVec,
};
#[derive(Debug, Clone)]
pub struct Mir<'mir> {
stmts: BumpVec<'mir, Stmt<'mir>>,
}
#[derive(Clone)]
struct Stmt<'mir> {
kind: StmtKind<'mir>,
state: MemoryState<'mir>,
span: Span,
}
impl Debug for Stmt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Stmt")
.field("kind", &self.kind)
.field("state", &self.state)
.finish()
}
}
type Offset = i32;
#[derive(Debug, Clone)]
enum StmtKind<'mir> {
/// Add or sub, the value has the valid range -255..=255
AddSub {
offset: Offset,
n: i16,
store: Store,
},
/// Sets the current cell to 0 and adds that value of the cell to another cell at `offset`
MoveAddTo {
offset: Offset,
store_set_null: Store,
store_move: Store,
},
/// Left or Right pointer move (`<>`)
PointerMove(Offset),
Loop(Mir<'mir>),
Out,
In(Store),
SetN(u8, Store),
}
#[tracing::instrument(skip(alloc, hir))]
pub fn optimized_mir<'mir>(alloc: &'mir Bump, hir: &Hir<'_>) -> Mir<'mir> {
let mut mir = hir_to_mir(alloc, hir);
opts::passes(alloc, &mut mir);
mir
}
/// compiles hir down to a minimal mir
fn hir_to_mir<'mir>(alloc: &'mir Bump, hir: &Hir<'_>) -> Mir<'mir> {
let mut stmts = Vec::new_in(alloc);
let iter = hir.stmts.iter().map(|hir_stmt| {
let kind = match *hir_stmt.kind() {
HirStmtKind::Add(offset, n) => StmtKind::AddSub {
offset,
n: i16::from(n),
store: Store::dead(),
},
HirStmtKind::Sub(offset, n) => StmtKind::AddSub {
offset,
n: -i16::from(n),
store: Store::dead(),
},
HirStmtKind::MoveAddTo { offset } => StmtKind::MoveAddTo {
offset,
store_set_null: Store::dead(),
store_move: Store::dead(),
},
HirStmtKind::Right(n) => StmtKind::PointerMove(i32::try_from(n).unwrap()),
HirStmtKind::Left(n) => StmtKind::PointerMove(-i32::try_from(n).unwrap()),
HirStmtKind::Loop(ref body) => StmtKind::Loop(hir_to_mir(alloc, body)),
HirStmtKind::Out => StmtKind::Out,
HirStmtKind::In => StmtKind::In(Store::dead()),
HirStmtKind::SetN(n) => StmtKind::SetN(n, Store::dead()),
};
Stmt {
kind,
span: hir_stmt.span,
state: MemoryState::empty(alloc),
}
});
stmts.extend(iter);
Mir { stmts }
}

View file

@ -1,215 +0,0 @@
use std::collections::{hash_map::Entry, HashMap};
use bumpalo::Bump;
use tracing::info;
use crate::mir::{
state::{CellState, MemoryState, MemoryStateChange, Store},
Mir, Offset, StmtKind,
};
/// this pass fills out as much state info for all statements as possible
#[tracing::instrument(skip(alloc, mir))]
pub fn passes<'mir>(alloc: &'mir Bump, mir: &mut Mir<'mir>) {
pass_fill_state_info(alloc, mir);
pass_const_propagation(mir);
pass_dead_store_elimination(mir);
}
/// this pass fills out as much state info for all statements as possible
#[tracing::instrument(skip(alloc, mir))]
pub fn pass_fill_state_info<'mir>(alloc: &'mir Bump, mir: &mut Mir<'mir>) {
let empty_state = MemoryState::empty(alloc);
pass_fill_state_info_inner(alloc, mir, empty_state);
}
// note: this whole thing is unsound because it doesn't consider that stores inside a loop
// could be loaded from after the loop
fn pass_fill_state_info_inner<'mir>(
alloc: &'mir Bump,
mir: &mut Mir<'mir>,
mut outer: MemoryState<'mir>,
) {
for stmt in &mut mir.stmts {
let state = match &mut stmt.kind {
StmtKind::AddSub { offset, n, store } => {
let prev_state = outer.state_for_offset(*offset);
let new_state = match prev_state {
CellState::WrittenToKnown(_, prev_n) => {
let n = i16::from(prev_n).wrapping_add(*n);
let n = u8::try_from(n).unwrap();
CellState::WrittenToKnown(store.clone(), n)
}
_ => CellState::WrittenToUnknown(store.clone()),
};
MemoryState::single(
alloc,
outer,
MemoryStateChange::Change {
offset: *offset,
new_state,
},
)
}
StmtKind::MoveAddTo {
offset,
store_set_null,
store_move,
} => MemoryState::double(
alloc,
outer,
MemoryStateChange::Change {
offset: 0,
new_state: CellState::WrittenToKnown(store_set_null.clone(), 0),
},
MemoryStateChange::Change {
offset: *offset,
new_state: CellState::WrittenToUnknown(store_move.clone()),
},
),
StmtKind::PointerMove(n) => {
MemoryState::single(alloc, outer, MemoryStateChange::Move(*n))
}
StmtKind::Loop(body) => {
// TODO: we can get a lot smarter here and get huge benefits; we don't yet
pass_fill_state_info_inner(alloc, body, MemoryState::empty(alloc));
MemoryState::double(
alloc,
outer,
// forget all knowledge, the opaque loop might have touched it all
MemoryStateChange::Forget,
// we certainly know that the current cell is zero, since the loop exited
MemoryStateChange::Change {
offset: 0,
new_state: CellState::LoopNull,
},
)
}
StmtKind::Out => outer,
StmtKind::In(store) => MemoryState::single(
alloc,
outer,
MemoryStateChange::Change {
offset: 0,
new_state: CellState::WrittenToUnknown(store.clone()),
},
),
StmtKind::SetN(value, store) => MemoryState::single(
alloc,
outer,
MemoryStateChange::Change {
offset: 0,
new_state: CellState::WrittenToKnown(store.clone(), *value),
},
),
};
stmt.state = state.clone();
outer = state;
}
}
/// This pass eliminates dead stores. It should probably be run multiple times between other passes
/// for cleanup
#[tracing::instrument(skip(mir))]
fn pass_dead_store_elimination(mir: &mut Mir<'_>) {
pass_dead_store_elimination_mark_dead_stores(mir)
}
#[tracing::instrument(skip(mir))]
fn pass_dead_store_elimination_mark_dead_stores(mir: &Mir<'_>) {
fn mark_store(
potential_dead_stores: &mut HashMap<Offset, Store>,
offset: Offset,
store: &Store,
) {
match potential_dead_stores.entry(offset) {
Entry::Occupied(mut entry) => {
let old = entry.insert(store.clone());
if old.is_maybe_dead() {
// it's certainly dead
info!("We have a dead one!!!");
old.mark_dead();
} else {
// it's alive and well, drop it and keep it marked alive
drop(old);
}
}
Entry::Vacant(entry) => {
entry.insert(store.clone());
}
}
}
let mut potential_dead_stores = HashMap::new();
let mut current_offset = 0;
for stmt in &mir.stmts {
match &stmt.kind {
StmtKind::AddSub { store, offset, .. } => {
mark_store(&mut potential_dead_stores, current_offset + offset, store);
}
StmtKind::MoveAddTo {
offset,
store_move,
store_set_null,
} => {
mark_store(&mut potential_dead_stores, current_offset, store_set_null);
mark_store(
&mut potential_dead_stores,
current_offset + offset,
store_move,
);
}
StmtKind::PointerMove(offset) => {
current_offset += offset; // ???
}
StmtKind::Loop(body) => {
let store = potential_dead_stores.get(&current_offset);
if let Some(store) = store {
store.add_load();
}
pass_dead_store_elimination_mark_dead_stores(body);
}
StmtKind::Out => {
let store = potential_dead_stores.get(&current_offset);
if let Some(store) = store {
store.add_load();
}
}
StmtKind::In(store) | StmtKind::SetN(_, store) => {
mark_store(&mut potential_dead_stores, current_offset, store);
}
}
if stmt.state.has_forget_delta() {
// they might all have loads now
potential_dead_stores.values().for_each(Store::clobber);
}
info!(?potential_dead_stores, ?current_offset, "stores");
}
}
// test pass
#[tracing::instrument(skip(mir))]
fn pass_const_propagation(mir: &mut Mir<'_>) {
pass_const_propagation_inner(mir)
}
fn pass_const_propagation_inner(mir: &mut Mir<'_>) {
for stmt in &mut mir.stmts {
match &mut stmt.kind {
StmtKind::Out => {
let _state = stmt.state.state_for_offset(0);
// we could now insert a `SetN` before the `Out`, to mark the previous store
// as dead.
}
StmtKind::Loop(body) => {
let _state = stmt.state.state_for_offset(0);
// we could now insert a `SetN` before the `Loop`, to mark the previous store
// as dead.
pass_const_propagation_inner(body);
}
_ => {}
}
}
}

View file

@ -1,220 +0,0 @@
// todo: we're gonna leak `Rc`s here aren't we?
use std::{
cell::{Cell, RefCell},
fmt::{Debug, Formatter},
num::NonZeroU32,
rc::Rc,
};
use bumpalo::Bump;
use crate::{mir::Offset, BumpVec};
/// The known state of a cell in the MIR
#[derive(Debug, Clone)]
pub enum CellState {
/// The state of this cell is completely unknown and could be anything, for example after `,`
Unknown,
/// This cell is guaranteed to be `0` because a loop just terminated on it
LoopNull,
/// Some value was written to this cell classified by the `Store`, but we do not know the value
WrittenToUnknown(Store),
/// A known value was written to this cell
WrittenToKnown(Store, u8),
}
/// A change in the known state of the memory caused by a single instruction
#[derive(Debug, Clone)]
pub enum MemoryStateChange {
/// A cell value was changed to a new state.
Change {
offset: Offset,
new_state: CellState,
},
/// The pointer was moved. This affects the `offset` calculations from previous states.
Move(Offset),
/// Forget everything about the memory state. This currently happens after each loop, since
/// the loop is opaque and might clobber everything.
Forget,
/// Load a value from memory. This is not a direct change of the memory itself, but it does
/// change the state in that it marks the corresponding store, if any, as alive. Loads should
/// be eliminated whenever possible, to remove as many dead stores as possible.
Load { offset: Offset },
}
/// The known state of memory at a specific instance in the instruction sequence
#[derive(Clone)]
pub struct MemoryState<'mir>(Rc<RefCell<MemoryStateInner<'mir>>>);
impl<'mir> MemoryState<'mir> {
pub fn empty(alloc: &'mir Bump) -> Self {
Self::new(None, Vec::new_in(alloc))
}
pub fn single(
alloc: &'mir Bump,
prev: MemoryState<'mir>,
delta: MemoryStateChange,
) -> MemoryState<'mir> {
let mut deltas = Vec::new_in(alloc);
deltas.push(delta);
Self::new(Some(prev), deltas)
}
pub fn double(
alloc: &'mir Bump,
prev: MemoryState<'mir>,
delta1: MemoryStateChange,
delta2: MemoryStateChange,
) -> MemoryState<'mir> {
let mut deltas = Vec::new_in(alloc);
deltas.push(delta1);
deltas.push(delta2);
Self::new(Some(prev), deltas)
}
pub fn new(
prev: Option<MemoryState<'mir>>,
deltas: BumpVec<'mir, MemoryStateChange>,
) -> MemoryState<'mir> {
Self(Rc::new(RefCell::new(MemoryStateInner { prev, deltas })))
}
pub fn state_for_offset(&self, offset: Offset) -> CellState {
self.0.borrow().state_for_offset(offset)
}
pub fn has_forget_delta(&self) -> bool {
self.0
.borrow()
.deltas
.iter()
.any(|d| matches!(d, MemoryStateChange::Forget))
}
}
impl Debug for MemoryState<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0
.try_borrow()
.map(|s| MemoryStateInner::fmt(&*s, f))
.unwrap_or_else(|_| f.debug_struct("MemoryState").finish_non_exhaustive())
}
}
/// The known state of memory relative to the pointer
#[derive(Debug, Clone)]
struct MemoryStateInner<'mir> {
prev: Option<MemoryState<'mir>>,
deltas: BumpVec<'mir, MemoryStateChange>,
}
impl<'mir> MemoryStateInner<'mir> {
fn state_for_offset(&self, offset: Offset) -> CellState {
let mut offset = offset;
for delta in &self.deltas {
match delta {
MemoryStateChange::Change {
offset: write_offset,
new_state,
} if *write_offset == offset => return new_state.clone(),
MemoryStateChange::Move(change) => offset -= change,
// we may not access the forbidden knowledge
MemoryStateChange::Forget => return CellState::Unknown,
_ => {}
}
}
self.prev
.as_ref()
.map(|state| state.state_for_offset(offset))
.unwrap_or(CellState::Unknown)
}
}
/// The abstract representation of a store in memory. Corresponding loads can also hold
/// a reference to this to mark the store as alive
#[derive(Clone)]
pub struct Store(Rc<Cell<StoreInner>>);
impl Store {
pub fn dead() -> Self {
StoreKind::Dead.into()
}
pub fn id(&self) -> u64 {
self.inner().id
}
pub fn add_load(&self) {
let old = self.inner();
let kind = match old.kind {
StoreKind::Unknown => StoreKind::UsedAtLeast(NonZeroU32::new(1).unwrap()),
StoreKind::UsedExact(n) => StoreKind::UsedExact(n.checked_add(1).unwrap()),
StoreKind::UsedAtLeast(n) => StoreKind::UsedAtLeast(n.checked_add(1).unwrap()),
StoreKind::Dead => StoreKind::UsedExact(NonZeroU32::new(1).unwrap()),
};
self.0.set(StoreInner { id: old.id, kind })
}
pub fn is_maybe_dead(&self) -> bool {
matches!(self.inner().kind, StoreKind::Dead | StoreKind::Unknown)
}
pub fn mark_dead(&self) {
let old = self.inner();
self.0.set(StoreInner {
id: old.id,
kind: StoreKind::Dead,
})
}
pub fn clobber(&self) {
let old = self.inner();
let kind = match old.kind {
StoreKind::Unknown => StoreKind::Unknown,
StoreKind::UsedExact(n) => StoreKind::UsedAtLeast(n),
StoreKind::UsedAtLeast(n) => StoreKind::UsedAtLeast(n),
StoreKind::Dead => StoreKind::Unknown,
};
self.0.set(StoreInner { id: old.id, kind })
}
fn inner(&self) -> StoreInner {
self.0.get()
}
}
impl Debug for Store {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.inner().kind.fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
struct StoreInner {
id: u64,
kind: StoreKind,
}
#[derive(Debug, Clone, Copy)]
enum StoreKind {
/// No information is known about uses of the store, it has probably been clobbered
Unknown,
/// The exact amount of subsequent loads is known about the store, and it's this
UsedExact(NonZeroU32),
/// The exact amount of subsequent loads not known about this store, but it's at least this
UsedAtLeast(NonZeroU32),
/// The store is known to be dead
Dead,
}
impl From<StoreKind> for Store {
fn from(kind: StoreKind) -> Self {
Self(Rc::new(Cell::new(StoreInner {
id: rand::random(),
kind,
})))
}
}

View file

@ -1,176 +0,0 @@
use std::{
cmp,
fmt::{Debug, Formatter},
};
use bumpalo::Bump;
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub struct Span {
start: u32,
len: u32,
}
impl Span {
fn single(idx: usize) -> Self {
Self {
start: idx.try_into().unwrap(),
len: 1,
}
}
/// start..end
fn start_end(start: usize, end: usize) -> Span {
Self {
start: start.try_into().unwrap(),
len: (end - start).try_into().unwrap(),
}
}
// start..=end
fn start_end_incl(start: usize, end: usize) -> Span {
Self {
start: start.try_into().unwrap(),
len: (end - start + 1).try_into().unwrap(),
}
}
#[must_use]
pub fn until(&self, other: Self) -> Self {
Self {
start: self.start,
len: (other.start + other.len) - self.len,
}
}
#[must_use]
pub fn merge(&self, other: Self) -> Self {
Self::start_end(
cmp::min(self.start(), other.start()),
cmp::max(self.end(), other.end()),
)
}
pub fn start(&self) -> usize {
self.start.try_into().unwrap()
}
pub fn len(&self) -> usize {
self.len.try_into().unwrap()
}
/// ..end
pub fn end(&self) -> usize {
self.start() + self.len()
}
}
impl Debug for Span {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&(self.start..(self.start + self.len)), f)
}
}
pub type Ast<'ast> = Vec<(Instr<'ast>, Span), &'ast Bump>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instr<'ast> {
Add,
Sub,
Right,
Left,
Out,
In,
Loop(Ast<'ast>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError;
pub fn parse<I>(alloc: &Bump, mut src: I) -> Result<Ast<'_>, ParseError>
where
I: Iterator<Item = (usize, u8)>,
{
let mut instrs = Vec::new_in(alloc);
loop {
match src.next() {
Some((idx, b'+')) => instrs.push((Instr::Add, Span::single(idx))),
Some((idx, b'-')) => instrs.push((Instr::Sub, Span::single(idx))),
Some((idx, b'>')) => instrs.push((Instr::Right, Span::single(idx))),
Some((idx, b'<')) => instrs.push((Instr::Left, Span::single(idx))),
Some((idx, b'.')) => instrs.push((Instr::Out, Span::single(idx))),
Some((idx, b',')) => instrs.push((Instr::In, Span::single(idx))),
Some((idx, b'[')) => {
let (loop_instrs, span) = parse_loop(alloc, &mut src, 0, idx)?;
instrs.push((Instr::Loop(loop_instrs), span));
}
Some((_, b']')) => return Err(ParseError),
Some(_) => {} // comment
None => break,
}
}
Ok(instrs)
}
fn parse_loop<'ast, I>(
alloc: &'ast Bump,
src: &mut I,
depth: u16,
start_idx: usize,
) -> Result<(Ast<'ast>, Span), ParseError>
where
I: Iterator<Item = (usize, u8)>,
{
const MAX_DEPTH: u16 = 1000;
if depth > MAX_DEPTH {
return Err(ParseError);
}
let mut instrs = Vec::new_in(alloc);
let end_idx = loop {
match src.next() {
Some((idx, b'+')) => instrs.push((Instr::Add, Span::single(idx))),
Some((idx, b'-')) => instrs.push((Instr::Sub, Span::single(idx))),
Some((idx, b'>')) => instrs.push((Instr::Right, Span::single(idx))),
Some((idx, b'<')) => instrs.push((Instr::Left, Span::single(idx))),
Some((idx, b'.')) => instrs.push((Instr::Out, Span::single(idx))),
Some((idx, b',')) => instrs.push((Instr::In, Span::single(idx))),
Some((idx, b'[')) => {
let (loop_instrs, span) = parse_loop(alloc, src, depth + 1, idx)?;
instrs.push((Instr::Loop(loop_instrs), span));
}
Some((idx, b']')) => break idx,
Some(_) => {} // comment
None => return Err(ParseError),
}
};
Ok((instrs, Span::start_end_incl(start_idx, end_idx)))
}
#[cfg(test)]
mod tests {
use bumpalo::Bump;
#[test]
fn simple() {
let alloc = Bump::new();
let bf = ">+<++[-].";
let instrs = super::parse(&alloc, bf.bytes().enumerate());
insta::assert_debug_snapshot!(instrs);
}
#[test]
fn nested_loop() {
let alloc = Bump::new();
let bf = "+[-[-[-]]+>>>]";
let instrs = super::parse(&alloc, bf.bytes().enumerate());
insta::assert_debug_snapshot!(instrs);
}
}

View file

@ -1,61 +0,0 @@
---
source: src/parse.rs
expression: instrs
---
Ok(
[
(
Add,
0..1,
),
(
Loop(
[
(
Sub,
2..3,
),
(
Loop(
[
(
Sub,
4..5,
),
(
Loop(
[
(
Sub,
6..7,
),
],
),
5..8,
),
],
),
3..9,
),
(
Add,
9..10,
),
(
Right,
10..11,
),
(
Right,
11..12,
),
(
Right,
12..13,
),
],
),
1..14,
),
],
)

View file

@ -1,43 +0,0 @@
---
source: src/parse.rs
expression: instrs
---
Ok(
[
(
Right,
0..1,
),
(
Add,
1..2,
),
(
Left,
2..3,
),
(
Add,
3..4,
),
(
Add,
4..5,
),
(
Loop(
[
(
Sub,
6..7,
),
],
),
5..8,
),
(
Out,
8..9,
),
],
)

View file

@ -1,8 +0,0 @@
---
source: src/lib.rs
assertion_line: 43
expression: "String::from_utf8(stdout)"
---
Ok(
"1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz\n",
)

View file

@ -1,7 +0,0 @@
---
source: src/lib.rs
expression: "String::from_utf8(stdout)"
---
Ok(
"AAAAAAAABBBBBBBBCCCCCCCCCCCCCCCCCCDDDDEFEEDDDCCCCCBBBBBBBBBBBBBBB\nAAAAAAABBBBBBCCCCCCCCCCCCCCCCCDDDDDDEEFIKGGGDDDDDCCCCBBBBBBBBBBBB\nAAAAAABBBBCCCCCCCCCCCCCCCCCDDDDDDDEEEFGHKPIGFEDDDDDCCCCCBBBBBBBBB\nAAAAABBBCCCCCCCCCCCCCCCCCDDDDDDDEEEFGPVT Q[HEEEEDDDCCCCCCBBBBBBB\nAAAABBCCCCCCCCCCCCCCCCDDDDDDDEEFFFGGHK HGFFEEEDDDCCCCCBBBBBB\nAAABBCCCCCCCCCCCCCCCDDDDDEEEFGK MJJ NR YS L HHGIJFDDCCCCCCBBBB\nAAABCCCCCCCCCCCCCDDDEEEEEEFFFHI MGEDDCCCCCCBBB\nAABCCCCCCCCCCCDDEEEEEEEEFFFGY Q MHGEEDCCCCCCCBB\nAACCCCCCDDDDDEEFLHGGHMHGGGHIR QLHEDDCCCCCCCB\nABCCDDDDDDEEEEFGIKU RLJJL IFEDDCCCCCCCB\nACDDDDDDEEEEEGGHOS QR JFEDDDCCCCCCC\nADDDDDEFFFGGHKOPS GEEDDDCCCCCCC\nA PJGFEEDDDCCCCCCC\nADDDDDEFFFGGHKOPS GEEDDDCCCCCCC\nACDDDDDDEEEEEGGHOS QR JFEDDDCCCCCCC\nABCCDDDDDDEEEEFGIKU RLJJL IFEDDCCCCCCCB\nAACCCCCCDDDDDEEFLHGGHMHGGGHIR QLHEDDCCCCCCCB\nAABCCCCCCCCCCCDDEEEEEEEEFFFGY Q MHGEEDCCCCCCCBB\nAAABCCCCCCCCCCCCCDDDEEEEEEFFFHI MGEDDCCCCCCBBB\nAAABBCCCCCCCCCCCCCCCDDDDDEEEFGK MJJ NR YS L HHGIJFDDCCCCCCBBBB\nAAAABBCCCCCCCCCCCCCCCCDDDDDDDEEFFFGGHK HGFFEEEDDDCCCCCBBBBBB\nAAAAABBBCCCCCCCCCCCCCCCCCDDDDDDDEEEFGPVT Q[HEEEEDDDCCCCCCBBBBBBB\nAAAAAABBBBCCCCCCCCCCCCCCCCCDDDDDDDEEEFGHKPIGFEDDDDDCCCCCBBBBBBBBB\nAAAAAAABBBBBBCCCCCCCCCCCCCCCCCDDDDDDEEFIKGGGDDDDDCCCCBBBBBBBBBBBB\n",
)

View file

@ -1 +0,0 @@
+++++>[-]+++[<.>]