From 7a8cfed53e42180e3476fb8bcc122b56d0c82807 Mon Sep 17 00:00:00 2001 From: Kyllingene Date: Sun, 17 Sep 2023 17:42:09 -0700 Subject: [PATCH] Added duplication --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 ++- src/lib.rs | 11 +++++ src/token.rs | 123 ++++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 118 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b33fe2..bf8b28f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "brim" -version = "3.0.2" +version = "3.0.3" dependencies = [ "sarge", ] diff --git a/Cargo.toml b/Cargo.toml index 3cea2c7..1ec1f0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "brim" -version = "3.0.2" +version = "3.0.3" edition = "2021" description = "An optimizing brain* interpreter." diff --git a/README.md b/README.md index c0f1aae..eae3048 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ a single "instruction". Currently, it recognizes: - Also recognizes multiplication (`[->+++<]`) - Subtracting one cell from another (`[->-<]`) - Scanning for a zero cell (`[>>>]`) +- Duplicating a cell (`[->+>+<<]`) + - Also recognizes multiplication (as with moving) The token-based structure makes these trivial to recognize, since repeating instructions have already been collapsed into one. @@ -64,8 +66,8 @@ functions, as well as the `Token` enum. Brim isn't finished yet! My hopes for the future include: - More macro-optimizations -- Heavy micro-optimization of brim itself -- More variations (non-wrapping, signed, varying tape size) +- Tape customizations via features +- Cell behavior variants via features ## Contributions diff --git a/src/lib.rs b/src/lib.rs index 98b97b8..a3b7ce0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,17 @@ pub fn interpret(code: &[Token], stdin: &mut impl Iterator, stdout: & *cell = cell.wrapping_sub(v); tape[sp] = 0; } + Token::Dup(i1, mul1, i2, mul2) => { + let v = tape[sp]; + + let cell = &mut tape[wrap_goto(sp, i1)]; + *cell = cell.wrapping_add(v * mul1); + + let cell = &mut tape[wrap_goto(sp, i1 + i2)]; + *cell = cell.wrapping_add(v * mul2); + + tape[sp] = 0; + } Token::Scan(i) => { while tape[sp] != 0 { sp = wrap_goto(sp, i); diff --git a/src/token.rs b/src/token.rs index 6d9efa6..d03284e 100644 --- a/src/token.rs +++ b/src/token.rs @@ -36,6 +36,8 @@ pub enum Token { Add(isize, u8), /// Macro-optimization. Equivalent to `[->-<]`. Sub(isize), + /// Macro-optimization. Equivalent to `[->+>+<<]`. + Dup(isize, u8, isize, u8), /// Macro-optimization. Equivalent to `[>>>]`. Scan(isize), @@ -127,12 +129,17 @@ pub fn optimize(toks: &[Token]) -> Vec { if matches!(tok, Token::LBrack(_)) { let next = toks.get(si + 1); - // Zero / Set / Add / Sub + // [ + // Zero / Set / Add / Sub / Dup if matches!(next, Some(Token::Dec(1))) { let next = toks.get(si + 2); + + // [- // Zero / Set if matches!(next, Some(Token::RBrack(_))) { + // [-] if let Some(Token::Inc(i)) = toks.get(si + 3) { + // [-]+++ out.push(Token::Set(*i)); si += 4; @@ -144,19 +151,45 @@ pub fn optimize(toks: &[Token]) -> Vec { continue; - // Add / Sub + // [- + // Add / Sub / Dup } else if let Some(Token::Goto(there)) = next { let next = toks.get(si + 3); - // Add + // [-> + // Add / Dup if let Some(Token::Inc(mul)) = next { if let Some(Token::Goto(back)) = toks.get(si + 4) { - if *there == -back && matches!(toks.get(si + 5), Some(Token::RBrack(_))) - { - out.push(Token::Add(*there, *mul)); - - si += 6; - continue; + let next = toks.get(si + 5); + + // [->+ >< + // Add + if *there == -back { + // [->+< + if matches!(next, Some(Token::RBrack(_))) { + // [->+<] + out.push(Token::Add(*there, *mul)); + + si += 6; + continue; + } + + // [->+ >< + // Dup + } else if let Some(Token::Inc(mul2)) = next { + // [->+ >< + + if let Some(Token::Goto(bi)) = toks.get(si + 6) { + // [->+ >< + >< + if bi + there + back == 0 + // [->+>+<<] + && matches!(toks.get(si + 7), Some(Token::RBrack(_))) + { + out.push(Token::Dup(*there, *mul, *back, *mul2)); + + si += 8; + continue; + } + } } } @@ -174,21 +207,51 @@ pub fn optimize(toks: &[Token]) -> Vec { } } - // Add + // [ + // Add / Sub / Dup / Scan } else if let Some(Token::Goto(there)) = next { let next = toks.get(si + 2); + + // [> + // Add / Dup if let Some(Token::Inc(mul)) = next { if let Some(Token::Goto(back)) = toks.get(si + 3) { + let next = toks.get(si + 4); + + // [>+ >< + // Add if *there == -back - && matches!(toks.get(si + 4), Some(Token::Dec(1))) + && matches!(next, Some(Token::Dec(1))) && matches!(toks.get(si + 5), Some(Token::RBrack(_))) { + // [>+<-] out.push(Token::Add(*there, *mul)); si += 6; continue; + + // [>+ >< + // Dup + } else if let Some(Token::Inc(mul2)) = next { + // [>+ >< + + if let Some(Token::Goto(bi)) = toks.get(si + 5) { + if *bi == -(there + back) + // [>+>+<< + && matches!(toks.get(si + 6), Some(Token::Dec(1))) + // [>+>+<<- + && matches!(toks.get(si + 7), Some(Token::RBrack(_))) + // [>+>+<<-] + { + out.push(Token::Dup(*there, *mul, *back, *mul2)); + + si += 8; + continue; + } + } } } + + // Sub } else if matches!(next, Some(Token::Dec(1))) { if let Some(Token::Goto(back)) = toks.get(si + 3) { if *there == -back @@ -201,6 +264,8 @@ pub fn optimize(toks: &[Token]) -> Vec { continue; } } + + // Scan } else if matches!(next, Some(Token::RBrack(_))) { out.push(Token::Scan(*there)); @@ -210,17 +275,22 @@ pub fn optimize(toks: &[Token]) -> Vec { } } - if matches!(tok, Token::LBrack(_)) { - lbracks.push(out.len()); - } else if matches!(tok, Token::RBrack(_)) { - let lb = lbracks - .pop() - .unwrap_or_else(|| err("invalid input", "unmatched closing bracket")); - out[lb] = Token::LBrack(out.len()); - tok = Token::RBrack(lb); - } else if matches!(tok, Token::Goto(0)) { - si += 1; - continue; + match tok { + Token::LBrack(_) => lbracks.push(out.len()), + Token::RBrack(_) => { + let lb = lbracks + .pop() + .unwrap_or_else(|| err("invalid input", "unmatched closing bracket")); + out[lb] = Token::LBrack(out.len()); + tok = Token::RBrack(lb); + } + + Token::Goto(0) | Token::Inc(0) | Token::Dec(0) => { + si += 1; + continue; + } + + _ => {} } out.push(tok); @@ -255,6 +325,15 @@ impl Display for Token { "+".repeat(*mul as usize) ), Token::Sub(i) => write!(f, "[{}-{}-]", left_right(*i), left_right(-i)), + Token::Dup(i1, mul1, i2, mul2) => write!( + f, + "[-{}{}{}{}{}]", + left_right(*i1), + "+".repeat(*mul1 as usize), + left_right(*i2), + "+".repeat(*mul2 as usize), + left_right(-(i1 + i2)), + ), Token::Scan(i) => write!(f, "[{}]", left_right(*i)), #[cfg(any(debug_assertions, feature = "debug"))]