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
use crate::parser::BrainfuckInstruction;

/// Compiles a sequence of BrainfuckInstructions to C source code.
pub fn compile(ir: Vec<BrainfuckInstruction>) -> String {
    let mut result = String::new();

    fn indent(s: &mut String, n: u32) {
        for _ in 0..n {
            s.push_str("    ");
        }
    }

    let mut level = 1;
    let mut index = 0;
    while index < ir.len() {
        match &ir[index] {
            BrainfuckInstruction::Add(count) => {
                indent(&mut result, level);
                result.push_str(&format!("ADJUST(0, {})", count));
            }
            BrainfuckInstruction::Sub(count) => {
                indent(&mut result, level);
                result.push_str(&format!("ADJUST(0, -{})", count));
            }
            BrainfuckInstruction::Right(count) => {
                indent(&mut result, level);
                result.push_str(&format!("SELECT({})", count));
            }
            BrainfuckInstruction::Left(count) => {
                indent(&mut result, level);
                result.push_str(&format!("SELECT(-{})", count));
            }
            BrainfuckInstruction::Read => {
                indent(&mut result, level);
                result.push_str(&format!("READ(0)"));
            }
            BrainfuckInstruction::Write => {
                indent(&mut result, level);
                result.push_str(&format!("WRITE(0)"));
            }
            BrainfuckInstruction::Open => {
                indent(&mut result, level);
                result.push_str("OPEN()");
                level += 1;
            }
            BrainfuckInstruction::Close => {
                level -= 1;
                indent(&mut result, level);
                result.push_str("CLOSE()");
            }
            BrainfuckInstruction::Set(value) => {
                indent(&mut result, level);
                result.push_str(&format!("SET(0, {})", value))
            }
            BrainfuckInstruction::ScanLeft => {
                indent(&mut result, level);
                result.push_str("SCAN_LEFT()")
            }
            BrainfuckInstruction::ScanRight => {
                indent(&mut result, level);
                result.push_str("SCAN_RIGHT()")
            }
        }
        result.push('\n');
        index += 1;
    }

    let template = include_str!("template.c");
    template
        .replace("__TAPE_SIZE__", "30000")
        .replace("__CODE__", &result.trim())
}