brainfuck interpreter
brainfuck cli rust
5

Configure Feed

Select the types of activity you want to include in your feed.

change tokenizer to return Token structs with line/column info

- updated tokenizer to produce Token values instead of raw bytes,
storing byte value along with source position
- adjusted parse_brackets and VM::run to destructure the new Token type
for comparison and display
- paves the way for nicer error messages in the future

digi.rip (Jun 7, 2026, 12:48 PM EDT) bc5de81b 6258fcb8

+44 -11
+4 -3
src/evaluator.rs
··· 1 + use crate::lexer::Token; 1 2 use clap::ValueEnum; 2 3 use std::fmt; 3 4 use std::io::Write; ··· 276 277 277 278 pub fn run<R: std::io::BufRead, W: std::io::Write>( 278 279 &mut self, 279 - tokens: &[u8], 280 + tokens: &[Token], 280 281 jump_map: &[usize], 281 282 mut reader: R, 282 283 mut writer: W, ··· 294 295 "\nTape: {}[{}] ", 295 296 self.data_pointer, self.tape[self.data_pointer] 296 297 ); 297 - print!("\nInst: '{}' @ {}", current as char, self.inst_pointer); 298 + print!("\nInst: '{}' @ {}", current.byte as char, self.inst_pointer); 298 299 } 299 300 300 - match current { 301 + match current.byte { 301 302 b'>' => { 302 303 self.move_right()?; 303 304 }
+35 -5
src/lexer.rs
··· 1 - pub fn tokenizer(input: &str) -> Vec<u8> { 2 - input 3 - .bytes() 4 - .filter(|&b| matches!(b, b'>' | b'<' | b'+' | b'-' | b'.' | b',' | b'[' | b']')) 5 - .collect() 1 + #[derive(Copy, Clone, Debug)] 2 + pub struct Token { 3 + pub byte: u8, 4 + pub line: usize, 5 + pub col: usize, 6 + } 7 + 8 + pub fn tokenizer(input: &str) -> Vec<Token> { 9 + let mut tokens = Vec::new(); 10 + let mut token = Token { 11 + byte: b'0', 12 + line: 0, 13 + col: 0, 14 + }; 15 + let mut current_line: usize = 1; 16 + let mut current_col: usize = 1; 17 + 18 + for b in input.bytes() { 19 + if b == b'\n' { 20 + current_line += 1; 21 + current_col = 1; 22 + continue; 23 + } 24 + 25 + if matches!(b, b'>' | b'<' | b'+' | b'-' | b'.' | b',' | b'[' | b']') { 26 + token.byte = b; 27 + token.line = current_line; 28 + token.col = current_col; 29 + tokens.push(token); 30 + } 31 + 32 + current_col += 1; 33 + } 34 + 35 + tokens 6 36 }
+5 -3
src/parser.rs
··· 1 + use crate::lexer::Token; 2 + // use crate::lexer::tokenizer; 1 3 use std::fmt; 2 4 3 5 #[derive(Debug)] ··· 21 23 22 24 impl std::error::Error for SyntaxError {} 23 25 24 - pub fn parse_brackets(tokens: &[u8]) -> Result<Vec<usize>, SyntaxError> { 26 + pub fn parse_brackets(tokens: &[Token]) -> Result<Vec<usize>, SyntaxError> { 25 27 let mut jump_map = vec![0; tokens.len()]; 26 28 let mut balance = Vec::new(); 27 29 28 30 for (pos, &e) in tokens.iter().enumerate() { 29 - if e == b'[' { 31 + if e.byte == b'[' { 30 32 balance.push(pos); 31 - } else if e == b']' { 33 + } else if e.byte == b']' { 32 34 match balance.pop() { 33 35 Some(pop) => { 34 36 jump_map[pos] = pop;