-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.rs
96 lines (96 loc) · 2.67 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::{env, error, fs, io::{self, Read, Write}};
enum Ops {
Left(usize), Right(usize), Add(u8), Sub(u8), LBrack(usize), RBrack(usize), Zero, Output, Input
}
fn main() -> Result<(), Box<dyn error::Error>> {
let prog = compile()?;
evaluate(prog)?;
Ok(())
}
// Compiler
fn optimise(prog: &mut Vec<Ops>) {
let mut i = 0;
while i < prog.len() {
if i + 2 < prog.len() && matches!(prog[i..i+3], [Ops::LBrack(_), Ops::Sub(1), Ops::RBrack(_)]) {
prog.splice(i..i+3, [Ops::Zero]);
i += 3;
} else { i += 1; }
}
}
fn compile() -> Result<Vec<Ops>, Box<dyn error::Error>> {
let mut prog = vec![];
let bytes = fs::read(env::args().nth(1).unwrap())?;
let mut i = 0;
while i < bytes.len() {
match bytes[i] as char {
'<' => {
let j = bytes[i..].iter()
.take_while(|b| **b as char == '<').count();
prog.push(Ops::Left(j));
i += j - 1;
}
'>' => {
let j = bytes[i..].iter()
.take_while(|b| **b as char == '>').count();
prog.push(Ops::Right(j));
i += j - 1;
}
'+' => {
let j = bytes[i..].iter()
.take_while(|b| **b as char == '+').count();
prog.push(Ops::Add(u8::try_from(j).unwrap()));
i += j - 1;
}
'-' => {
let j = bytes[i..].iter()
.take_while(|b| **b as char == '-').count();
prog.push(Ops::Sub(u8::try_from(j).unwrap()));
i += j - 1;
}
'[' => prog.push(Ops::LBrack(usize::max_value())),
']' => prog.push(Ops::RBrack(usize::max_value())),
'.' => prog.push(Ops::Output),
',' => prog.push(Ops::Input),
_ => (),
}
i += 1;
}
optimise(&mut prog);
let mut bstack = vec![];
let mut i = 0;
while i < prog.len() {
match prog[i] {
Ops::LBrack(_) => bstack.push(i),
Ops::RBrack(_) => {
let s = bstack.pop().unwrap();
prog[s] = Ops::LBrack(i);
prog[i] = Ops::RBrack(s);
}
_ => ()
}
i += 1;
}
Ok(prog)
}
// Evaluator / "Interpreter"
fn evaluate(prog: Vec<Ops>) -> Result<(), Box<dyn error::Error>> {
let mut cells = vec![0u8; 10000];
let mut cc = 0usize;
let mut pc = 0;
while pc < prog.len() {
match prog[pc] {
Ops::Left(i) => cc -= i,
Ops::Right(i) => cc += i,
Ops::Add(i) => cells[cc] = cells[cc].wrapping_add(i),
Ops::Sub(i) => cells[cc] = cells[cc].wrapping_sub(i),
Ops::LBrack(i) if cells[cc] == 0 => pc = i,
Ops::RBrack(i) if cells[cc] != 0 => pc = i,
Ops::Zero => cells[cc] = 0,
Ops::Output => io::stdout().write_all(&cells[cc..cc+1])?,
Ops::Input => io::stdin().read_exact(&mut cells[cc..cc + 1])?,
_ => ()
}
pc += 1;
}
Ok(())
}