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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use parser;
use parser::{OpCode,Loop,Program};
struct Context {
isn: uint,
}
impl Context {
fn new() -> Context {
Context {
isn: 0
}
}
}
fn effective_len(program: &Program) -> uint {
let mut len = 0;
for op in program.iter() {
match *op {
Loop(ref l) => len += effective_len(l) + 1,
_ => len += 1,
}
}
len
}
pub fn compile<W: Writer>(program: &[OpCode], outfile: &mut W) {
let mut ctx = Context::new();
outfile.write(PRELUDE.as_bytes());
let _ = inner(program, outfile, &mut ctx);
outfile.write(format!(" isn{}:\n", ctx.isn).as_bytes());
outfile.write(EPILOGUE.as_bytes());
}
#[allow(unused_must_use)]
fn inner<W: Writer>(program: &[OpCode], outfile: &mut W, ctx: &mut Context) {
macro_rules! write(
($op:expr) => (
outfile.write($op.as_bytes());
)
)
macro_rules! write_s(
($op:expr) => (
{
write!($op.to_string());
()
}
)
)
let len = program.len();
let mut pc = 0;
while pc < len {
write!(format!(" isn{}:\n", ctx.isn));
ctx.isn += 1;
match program[pc] {
parser::Rshift => write_s!(" add esi, dword 1\n"),
parser::Lshift => write_s!(" sub esi, dword 1\n"),
parser::Inc => write_s!(" add [esi], dword 1\n"),
parser::Dec => write_s!(" sub [esi], dword 1\n"),
parser::Putc => write_s!(" call dot\n"),
parser::Getc => panic!("Getc not implemented"),
parser::Loop(ref l) => {
let jmp = format!(" jmp isn{}\n", ctx.isn - 1);
write_s!(" cmp [esi], byte 0\n");
write!(format!(" je isn{}\n", ctx.isn + effective_len(l)));
inner(l.as_slice(), outfile, ctx);
write!(jmp);
}
}
pc += 1;
}
}
static PRELUDE: &'static str = "
global start
section .bss
tape: resb 30000
section .text
dot:
push dword 1
push esi
push dword 1
mov eax, 4
sub esp, 4
int 0x80
add esp, 16
ret
start:
; Begin, setup rcx as our index
mov esi, tape
";
static EPILOGUE: &'static str = "
; End, exit zero because everything probably went super well
push dword 0
mov eax, 1
push dword 0
int 0x80
";