Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::BitBitError;
use std::io::Write;
use std::io::{self, Write};

pub const BASE: usize = 256;
#[cfg(target_pointer_width = "16")]
Expand Down Expand Up @@ -33,7 +33,7 @@ pub fn shift_left(pointer: &mut usize, amount: usize) -> Result<(), BitBitError>
/// Output character at pointer
#[inline]
pub fn output(memory: &Vec<u8>, pointer: &usize, amount: usize) -> Result<(), BitBitError> {
// print ascii
// print ASCII character at the pointer position
for _ in 0..amount {
putch(memory[*pointer] as core::ffi::c_char);
}
Expand All @@ -49,7 +49,7 @@ pub fn output(memory: &Vec<u8>, pointer: &usize, amount: usize) -> Result<(), Bi
#[inline]
pub fn input(memory: &mut Vec<u8>, pointer: &usize, amount: usize) {
for _ in 0..amount {
// get 1 character input
// get 1 character input and store it in the memory at the pointer position
(*memory)[*pointer] = getch() as u8;
}
}
Expand Down Expand Up @@ -84,22 +84,46 @@ pub fn decrement(cell: &mut u8, amount: usize) {
}
}

// I/O for brainfuck
// Cross-platform I/O for brainfuck
#[cfg(target_os = "windows")]
extern "C" {
fn _getch() -> core::ffi::c_char;
fn _putch(c_char: core::ffi::c_char) -> core::ffi::c_void;
}

// Read 1 byte input
#[cfg(target_os = "windows")]
#[inline]
fn getch() -> core::ffi::c_char {
// SAFETY: trust C
// SAFETY: call Windows-specific `_getch`
unsafe { _getch() }
}

// Write 1 byte output
#[cfg(target_os = "windows")]
#[inline]
fn putch(c_char: core::ffi::c_char) -> core::ffi::c_void {
// SAFETY: trust C
// SAFETY: call Windows-specific `_putch`
unsafe { _putch(c_char) }
}

// Alternative implementation for non-Windows platforms
#[cfg(not(target_os = "windows"))]
#[inline]
fn getch() -> core::ffi::c_char {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this getch function uses the stand rust library, which is nice to not depend on external C functions, it has a different functionality from the original implementation. The intended implementation for getch should terminate once a single byte has been read, but your implementation allows for multiple characters to be typed in the terminal and requires a \n character or enter key to be pressed before the first byte is read.

Ex: This code should terminate and only show a single character in the terminal after 1 key press.

,.

use std::io::Read;
// Read a single byte from stdin
io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.unwrap_or(0) as core::ffi::c_char
}

// Alternative implementation for non-Windows platforms
#[cfg(not(target_os = "windows"))]
#[inline]
fn putch(c_char: core::ffi::c_char) {
print!("{}", c_char as u8 as char);
io::stdout().flush().unwrap();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flushing is already handled in memory::output(). This is to reduce the amount of times flush() is called when printing multiple times at once.

}