Skip to content

Commit be5e455

Browse files
committed
Improved interpreter
1 parent c6085e3 commit be5e455

File tree

5 files changed

+54
-41
lines changed

5 files changed

+54
-41
lines changed

src/cli.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ use clap::Parser;
55
#[command(version, about, long_about = None)]
66
pub struct CommandLineArgs {
77
/// The path of the configuration file.
8-
#[arg(short, long, default_value_t = crate::config::CONFIG_FILE_PATH.to_string())]
8+
#[arg(short('c'), long("config"), default_value_t = crate::config::CONFIG_FILE_PATH.to_string())]
99
pub config: String,
1010

1111
/// The path of the source file to interpret.
1212
pub input: String,
13+
14+
#[arg(short('p'), long("print-program"))]
15+
pub print_program: Option<bool>,
1316
}

src/interpreter/ast.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,21 @@ pub enum Token {
2828
impl fmt::Display for Token {
2929
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3030
match self {
31-
Self::Inc => write!(f, "Inc"),
32-
Self::Dec => write!(f, "Dec"),
33-
Self::MoveRight => write!(f, "MoveRght"),
34-
Self::MoveLeft => write!(f, "MoveLeft"),
31+
Self::Inc => write!(f, "+"),
32+
Self::Dec => write!(f, "-"),
33+
Self::MoveRight => write!(f, ">"),
34+
Self::MoveLeft => write!(f, "<"),
3535
Self::Loop(vec) => {
36-
write!(f, "Loop[")?;
36+
write!(f, "[")?;
3737

3838
for ele in vec {
39-
write!(f, "{},", ele)?;
39+
write!(f, "{}", ele)?;
4040
}
4141

4242
return write!(f, "]");
4343
}
44-
Self::Print => write!(f, "Print"),
45-
Self::Read => write!(f, "Read"),
44+
Self::Print => write!(f, "."),
45+
Self::Read => write!(f, ","),
4646
}
4747
}
4848
}

src/interpreter/mod.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@ pub enum ProgramError {
1515
IOError,
1616

1717
/// Error when performing illegal operation
18-
IllegalOperation
18+
IllegalOperation { instruction: Token, pointer: usize },
1919
}
2020

2121
impl fmt::Display for ProgramError {
2222
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2323
match self {
2424
ProgramError::OutOfBounds => write!(f, "Attempted to move pointer past end of buffer"),
2525
ProgramError::IOError => write!(f, "Error when attempting to perform IO operation"),
26-
ProgramError::IllegalOperation => write!(f, "Operation is illegal")
26+
ProgramError::IllegalOperation {
27+
instruction,
28+
pointer,
29+
} => write!(
30+
f,
31+
"Operation is illegal: {instruction} at pointer address {pointer}"
32+
),
2733
}
2834
}
2935
}
@@ -34,18 +40,18 @@ const BUFFER_SIZE: usize = 30000;
3440
/// Buffer used internally by the interpreter.
3541
///
3642
/// This struct exists for the sole purpose of exploiting **interior mutability**, allowing [Interpreter] objects to expose an immutable API.
37-
struct ArrayBuffer {
43+
struct Tape {
3844
/// The data held in the buffer.
3945
data: [u8; BUFFER_SIZE],
4046

4147
/// A pointer to the *current location* in the buffer.
4248
pointer: usize,
4349
}
4450

45-
impl ArrayBuffer {
51+
impl Tape {
4652
/// Creates a new empty [ArrayBuffer] with all elements set to 0 which points to the byte at position 0.
4753
fn new() -> Self {
48-
ArrayBuffer {
54+
Tape {
4955
data: [0; BUFFER_SIZE],
5056
pointer: 0,
5157
}
@@ -68,12 +74,14 @@ impl ArrayBuffer {
6874

6975
/// Increments by 1 the value currently pointed at in the buffer
7076
fn inc(&mut self) {
71-
self.data[self.pointer] += 1;
77+
self.data[self.pointer] = self.data[self.pointer].wrapping_add(1);
78+
// self.data[self.pointer] += 1;
7279
}
7380

7481
/// Decrements by 1 the value currently pointed at in the buffer
7582
fn dec(&mut self) {
76-
self.data[self.pointer] -= 1;
83+
self.data[self.pointer] = self.data[self.pointer].wrapping_sub(1);
84+
// self.data[self.pointer] -= 1;
7785
}
7886

7987
/// Moves the pointer one position to the left.
@@ -92,7 +100,7 @@ pub struct Interpreter {
92100
/// The data used by the interpreter.
93101
///
94102
/// This is stored behind a [RefCell] so we can expose an immutable API.
95-
data: RefCell<ArrayBuffer>,
103+
tape: RefCell<Tape>,
96104

97105
/// Object that abstracts I/O operations away from interpreter objects.
98106
io: IO,
@@ -102,7 +110,7 @@ impl Interpreter {
102110
/// Creates a new [Interpreter] object with a empty [buffer](ArrayBuffer).
103111
pub fn new() -> Self {
104112
Interpreter {
105-
data: RefCell::new(ArrayBuffer::new()),
113+
tape: RefCell::new(Tape::new()),
106114
io: IO::new(),
107115
}
108116
}
@@ -111,39 +119,35 @@ impl Interpreter {
111119
fn process_token(&self, token: Token) -> Result<(), ProgramError> {
112120
match token {
113121
Token::Inc => {
114-
self.data.borrow_mut().inc();
122+
self.tape.borrow_mut().inc();
115123
}
116124
Token::Dec => {
117-
if self.data.borrow().get() == 0 {
118-
return Err(ProgramError::IllegalOperation);
119-
}
120-
121-
self.data.borrow_mut().dec();
125+
self.tape.borrow_mut().dec();
122126
}
123127
Token::MoveLeft => {
124-
if self.data.borrow().pointer() == 0 {
128+
if self.tape.borrow().pointer() == 0 {
125129
return Err(ProgramError::OutOfBounds);
126130
}
127131

128-
self.data.borrow_mut().pointer_left();
132+
self.tape.borrow_mut().pointer_left();
129133
}
130134
Token::MoveRight => {
131-
if self.data.borrow().pointer() == BUFFER_SIZE - 1 {
135+
if self.tape.borrow().pointer() == BUFFER_SIZE - 1 {
132136
return Err(ProgramError::OutOfBounds);
133137
}
134138

135-
self.data.borrow_mut().pointer_right();
139+
self.tape.borrow_mut().pointer_right();
136140
}
137141
Token::Print => {
138-
let current_byte = self.data.borrow().get();
142+
let current_byte = self.tape.borrow().get();
139143

140144
let character = current_byte as char;
141145

142146
self.io.print(character);
143147
}
144148
Token::Read => match self.io.read() {
145149
None => return Err(ProgramError::IOError),
146-
Some(character) => self.data.borrow_mut().set(character as u8),
150+
Some(character) => self.tape.borrow_mut().set(character as u8),
147151
},
148152
Token::Loop(loop_tokens) => self.run_loop(loop_tokens)?,
149153
};
@@ -163,7 +167,8 @@ impl Interpreter {
163167
/// Specialized function used to run loops.
164168
fn run_loop(&self, loop_tokens: Vec<Token>) -> Result<(), ProgramError> {
165169
loop {
166-
if self.data.borrow().get() == 0 {
170+
// if 0 at the beginning of loop, skip it
171+
if self.tape.borrow().get() == 0 {
167172
break;
168173
}
169174

src/log.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,4 @@ impl<'a> Logger<'a> {
3737
_log!(high, VerbosityLevel::High);
3838

3939
_log!(medium, VerbosityLevel::High | VerbosityLevel::Medium);
40-
41-
_log!(
42-
low,
43-
VerbosityLevel::High | VerbosityLevel::Medium | VerbosityLevel::Low
44-
);
4540
}

src/main.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,23 @@ fn main() {
3434
}
3535
};
3636

37-
logger.medium("Running Brainfuck program");
37+
let print_program = args.print_program.unwrap_or(false);
3838

39-
let interpreter = interpreter::Interpreter::new();
39+
if print_program {
40+
let mut string = String::new();
41+
for i in tokens {
42+
string = format!("{}{}", string, i);
43+
}
44+
print!("{}", string)
45+
} else {
46+
logger.medium("Running Brainfuck program");
47+
48+
let interpreter = interpreter::Interpreter::new();
4049

41-
if let Err(err) = interpreter.run(tokens) {
42-
logger.high(format!("Error while running Brainfuck code: {}", err));
50+
if let Err(err) = interpreter.run(tokens) {
51+
logger.high(format!("Error while running Brainfuck code: {}", err));
4352

44-
exit(3);
53+
exit(3);
54+
}
4555
}
4656
}

0 commit comments

Comments
 (0)