1use fck::{
2 lexer::lex,
3 parser::{parse, AstNode},
4};
5use hecate_assembler::Assembler;
6use hecate_common::BytecodeFile;
7use stringlit::s;
8
9const SC: &str = "R1";
10const SC_ADDR: &str = "R2";
11const SC_LEN: &str = "R3";
12const Z: &str = "R0"; const DP: &str = "R10"; const T1: &str = "R11"; const T2: &str = "R12"; pub fn ast_to_assembly(
18 ast: &AstNode,
19 asm: &mut Vec<String>,
20 dp_offset: &mut isize,
21 max_dp_offset_left: &mut isize,
22 max_dp_offset_right: &mut isize,
23) {
24 match ast {
25 AstNode::Sequence(nodes) => {
26 for node in nodes {
27 ast_to_assembly(
28 node,
29 asm,
30 dp_offset,
31 max_dp_offset_left,
32 max_dp_offset_right,
33 );
34 }
35 }
36 AstNode::Loop(nodes) => {
37 let loop_start_label = format!("loop_start_{}", asm.len());
38 let loop_end_label = format!("loop_end_{}", asm.len());
39
40 asm.push(format!("{}:", loop_start_label));
41 asm.push(format!("loadreg {T1}, {DP}"));
42 asm.push(format!("cmp {T1}, {Z}"));
43 asm.push(format!("je @{}", loop_end_label));
44 for node in nodes {
45 ast_to_assembly(
46 node,
47 asm,
48 dp_offset,
49 max_dp_offset_left,
50 max_dp_offset_right,
51 );
52 }
53 asm.push(format!("jmp @{}", loop_start_label));
54 asm.push(format!("{}:", loop_end_label));
55 }
56 AstNode::Clear => {
57 asm.push(format!("load {DP}, 500"));
58 }
59 AstNode::Right(steps) => {
60 asm.push(format!("add {DP}, {}", steps));
61 *dp_offset += *steps as isize;
62 if *dp_offset > *max_dp_offset_right {
63 *max_dp_offset_right = *dp_offset;
64 }
65 }
66 AstNode::Left(steps) => {
67 asm.push(format!("sub {DP}, {}", steps));
68 *dp_offset -= *steps as isize;
69 if *dp_offset < *max_dp_offset_left {
70 *max_dp_offset_left = *dp_offset;
71 }
72 }
73 AstNode::Increment(value) => {
74 asm.push(format!("loadreg {T2}, {DP}"));
75 asm.push(format!("add {T2}, {}", value));
76 asm.push(format!("storereg {DP}, {T2}"));
77 }
78 AstNode::Decrement(value) => {
79 asm.push(format!("loadreg {T2}, {DP}"));
80 asm.push(format!("sub {T2}, {}", value));
81 asm.push(format!("storereg {DP}, {T2}"));
82 }
83 AstNode::Output => {
84 asm.push(format!("load {SC}, {Z}"));
85 asm.push(format!("load {SC_ADDR}, {DP}"));
86 asm.push(format!("load {SC_LEN}, 1"));
87 asm.push(s!("syscall"));
88 }
89 AstNode::Input => {
90 panic!("Input not implemented");
91 }
92 }
93}
94
95pub fn compile_program(program: &str) -> anyhow::Result<BytecodeFile> {
96 let tokens = lex(program)?;
97 let ast = parse(&tokens)?;
98 let mut asm = Vec::new();
99 let mut dp_offset = 0;
100 let mut dp_offset_max_left = 0;
101 let mut dp_offset_max_right = 0;
102 asm.push(format!("load {DP}, 500"));
103 ast_to_assembly(
104 &ast,
105 &mut asm,
106 &mut dp_offset,
107 &mut dp_offset_max_left,
108 &mut dp_offset_max_right,
109 );
110
111 asm.push(s!("halt"));
112
113 let file = Assembler::new().assemble_program(&asm.join("\n"))?;
114
115 Ok(file)
116}