NeuroWhAI의 잡블로그

[Rust] Brainfuck(브레인퍽) 구현 본문

개발 및 공부

[Rust] Brainfuck(브레인퍽) 구현

NeuroWhAI 2019. 1. 15. 21:15


use std::io::{self, Read};


mod bf {
    use std::io::{self, Read};

    #[derive(Default)]
    pub struct Machine {
        code: Vec<char>,
        ram: Vec<u8>,
        head: usize,
        ptr: usize,
    }
    
    impl Machine {
        pub fn new() -> Self {
            Machine::default()
        }
    }
    
    impl Machine {
        pub fn initialize(&mut self, ram_size: usize) {
            self.ram.resize(ram_size, 0);
        }
    
        pub fn mount(&mut self, code: &str) {
            self.code = code.chars().collect();
        }
        
        pub fn step(&mut self) -> Result<bool, String> {
            if self.head >= self.code.len() {
                return Ok(true);
            }
        
        
            match self.code[self.head] {
                '>' => {
                    // Increase ptr.
                    if self.ptr + 1 >= self.ram.len() {
                        return Err("the pointer is out of bound".into());
                    }
                    self.ptr += 1;
                    self.head += 1;
                },
                '<' => {
                    // Decrease ptr.
                    if self.ptr < 1 {
                        return Err("the pointer is out of bound".into());
                    }
                    self.ptr -= 1;
                    self.head += 1;
                },
                '+' => {
                    // Increase value that ptr points.
                    self.ram[self.ptr] = self.ram[self.ptr].wrapping_add(1);
                    self.head += 1;
                },
                '-' => {
                    // Decrease value that ptr points.
                    self.ram[self.ptr] = self.ram[self.ptr].wrapping_sub(1);
                    self.head += 1;
                },
                '.' => {
                    // Print value that ptr points.
                    print!("{}", char::from(self.ram[self.ptr]));
                    self.head += 1;
                },
                ',' => {
                    // Read a byte from stream.
                    let mut buff = [0_u8];
                    let io_result = io::stdin().read_exact(&mut buff);
                    if let Err(err) = io_result {
                        return Err(err.to_string());
                    }
                    
                    self.ram[self.ptr] = buff[0];
                    self.head += 1;
                },
                '[' => {
                    // Jump to matching ']' if value at ptr is zero
                    if self.ram[self.ptr] == 0 {
                        let mut depth = 0;
                        
                        while self.head < self.code.len() {
                            let token = self.code[self.head];
                            
                            if token == '[' {
                                depth += 1;
                            }
                            else if token == ']' {
                                depth -= 1;
                                if depth == 0 {
                                    break;
                                }
                            }
                            
                            self.head += 1;
                        }
                        
                        if depth != 0 {
                            return Err("parentheses not found".into());
                        }
                    }
                    else {
                        self.head += 1;
                    }
                },
                ']' => {
                    // Jump to matching '[' if value at ptr is not zero
                    if self.ram[self.ptr] != 0 {
                        let mut depth = 0;
                        
                        while self.head > 0 {
                            let token = self.code[self.head];
                            
                            if token == ']' {
                                depth += 1;
                            }
                            else if token == '[' {
                                depth -= 1;
                                if depth == 0 {
                                    break;
                                }
                            }
                            
                            self.head -= 1;
                        }
                        
                        if depth != 0 {
                            return Err("parentheses not found".into());
                        }
                    }
                    else {
                        self.head += 1;
                    }
                },
                _ => { }
            }
            
            
            // is end?
            Ok(self.head >= self.code.len())
        }
    }
}


fn main() -> io::Result<()> {
    use crate::bf::Machine;


    let mut code = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
        .to_string();
    //io::stdin().read_to_string(&mut code)?;
        
        
    let mut machine = Machine::new();
    machine.initialize(256);
    machine.mount(&code);
    
    loop {
        let result = machine.step();
        
        match result {
            Ok(true) => break,
            Ok(false) => continue,
            Err(msg) => {
                eprintln!("error: {}", msg);
                break;
            },
        }
    }
    
    Ok(())
}

실행 및 결과 확인 : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b983021490480d828ff330be0a382691


Brainfuck(브레인퍽)은 유명한(?) 난해한 프로그래밍 언어 중 하나입니다.

비교적 구현이 쉽습니다.


뜬금없이 이걸 구현한 이유는 저도 모릅니다.

ㅌㅌ



Comments