use crate::Instruct;
use alloc::{string::String, vec::Vec};
pub trait Target {
fn assemble(&self, initial_stack_ptr: usize, stack_size: usize, code: Vec<Instruct>) -> String;
}
pub struct C;
impl Target for C {
fn assemble(&self, initial_stack_ptr: usize, stack_size: usize, code: Vec<Instruct>) -> String {
let total_mem_size = initial_stack_ptr + stack_size;
let mut result = format!(
"#include <stdio.h>
#include <stdbool.h>
const int INIT_STACK_PTR = {reg_size};
const int MEMORY_SIZE = {mem_size};",
reg_size = initial_stack_ptr,
mem_size = total_mem_size
);
result += r#"
const int ACC = 0;
const int SPR = 1;
void init(double tape[], bool alloc_tape[]) {
tape[SPR] = INIT_STACK_PTR;
for (int i=0; i<INIT_STACK_PTR; i++) {
alloc_tape[i] = true;
}
}
void push_cell(double tape[], double value) {
tape[(int)tape[SPR]++] = value;
}
void pop_cell(double tape[], int addr) {
tape[addr] = tape[(int)--tape[SPR]];
tape[(int)tape[SPR]] = 0;
}
void deref_load(double tape[]) {
pop_cell(tape, ACC);
int addr = tape[ACC];
push_cell(tape, (int)tape[addr]);
}
void deref_store(double tape[]) {
pop_cell(tape, ACC);
int addr = tape[ACC];
pop_cell(tape, addr);
}
void store(double tape[], int addr, int size) {
for (int i=0; i<size; i++) {
pop_cell(tape, addr + size - i - 1);
}
}
void load(double tape[], int addr, int size) {
for (int i=0; i<size; i++) {
push_cell(tape, tape[(int)(addr + i)]);
}
}
void add(double tape[]) {
pop_cell(tape, ACC);
double a = tape[ACC];
pop_cell(tape, ACC);
double b = tape[ACC];
push_cell(tape, a + b);
}
void sub(double tape[]) {
pop_cell(tape, ACC);
double a = tape[ACC];
pop_cell(tape, ACC);
double b = tape[ACC];
push_cell(tape, a - b);
}
void div(double tape[]) {
pop_cell(tape, ACC);
double a = tape[ACC];
pop_cell(tape, ACC);
double b = tape[ACC];
push_cell(tape, a / b);
}
void mul(double tape[]) {
pop_cell(tape, ACC);
double a = tape[ACC];
pop_cell(tape, ACC);
double b = tape[ACC];
push_cell(tape, a * b);
}
void dup(double tape[]) {
pop_cell(tape, ACC);
push_cell(tape, tape[ACC]);
push_cell(tape, tape[ACC]);
}
void cmp(double tape[]) {
pop_cell(tape, ACC);
double a = tape[ACC];
pop_cell(tape, ACC);
double b = tape[ACC];
if (a < b) {
push_cell(tape, -1);
} else if (a == b) {
push_cell(tape, 0);
} else if (a > b) {
push_cell(tape, 1);
}
}
void outc(double tape[]) {
pop_cell(tape, ACC);
printf("%c", (int)(tape[ACC]) % 256);
}
void outn(double tape[]) {
pop_cell(tape, ACC);
printf("%lG", tape[ACC]);
}
void inc(double tape[]) {
char ch;
if (scanf("%c", &ch) == 1) {
push_cell(tape, ch);
} else {
push_cell(tape, 0);
}
}
void inn(double tape[]) {
double d;
if (scanf("%lG", &d) == 1) {
push_cell(tape, d);
} else {
push_cell(tape, 0);
}
}
bool pop_bool(double tape[]) {
pop_cell(tape, ACC);
int a = tape[ACC];
return a;
}
void lasm_alloc(double tape[], bool alloc_tape[], int ptr_addr) {
pop_cell(tape, ACC);
int size = tape[ACC];
int cons_zeroes = 0;
int i;
for (i=MEMORY_SIZE-1; i>0; i--) {
if (!alloc_tape[i]) {
cons_zeroes++;
} else {
cons_zeroes = 0;
}
if (cons_zeroes == size) {
push_cell(tape, i);
pop_cell(tape, ptr_addr);
break;
}
}
for (int n=0; n<size; n++) {
alloc_tape[i+n] = true;
}
}
void lasm_free(double tape[], bool alloc_tape[], int ptr_addr) {
pop_cell(tape, ACC);
int size = tape[ACC];
int addr = tape[ptr_addr];
for (int n=0; n<size; n++) {
tape[addr+n] = 0;
alloc_tape[addr+n] = false;
}
}
int main() {
double tape[MEMORY_SIZE];
bool alloc_tape[MEMORY_SIZE];
for (int i=0; i<MEMORY_SIZE; i++) tape[i] = 0;
for (int i=0; i<MEMORY_SIZE; i++) alloc_tape[i] = false;
init(tape, alloc_tape);
"#;
for line in &code {
result += &(String::from(" ")
+ &match line {
Instruct::Refer(r) => format!("push_cell(tape, {});", r.get_addr()),
Instruct::DerefLoad => String::from("deref_load(tape);"),
Instruct::DerefStore => String::from("deref_store(tape);"),
Instruct::Alloc(r) => {
format!("lasm_alloc(tape, alloc_tape, {});", r.get_addr())
}
Instruct::Free(r) => format!("lasm_free(tape, alloc_tape, {});", r.get_addr()),
Instruct::Load(r) => format!("load(tape, {}, {});", r.get_addr(), r.get_size()),
Instruct::Store(r) => {
format!("store(tape, {}, {});", r.get_addr(), r.get_size())
}
Instruct::Push(l) => format!("push_cell(tape, {});", l.get()),
Instruct::Pop => String::from("pop_cell(tape, ACC);"),
Instruct::Duplicate => String::from("dup(tape);"),
Instruct::Add => String::from("add(tape);"),
Instruct::Subtract => String::from("sub(tape);"),
Instruct::Multiply => String::from("mul(tape);"),
Instruct::Divide => String::from("div(tape);"),
Instruct::InputChar => String::from("inc(tape);"),
Instruct::InputNumber => String::from("inn(tape);"),
Instruct::OutputChar => String::from("outc(tape);"),
Instruct::OutputNumber => String::from("outn(tape);"),
Instruct::Compare => String::from("cmp(tape);"),
Instruct::WhileNotZero => String::from("while (pop_bool(tape)) {"),
Instruct::EndWhile => String::from("}"),
}
+ "\n");
}
result += r#"
// printf("...\n\n");
// for (int i=0; i<MEMORY_SIZE; i++) {
// if (i == INIT_STACK_PTR) {
// printf("STK_BGN ");
// }
// if (i == (int)tape[SPR]) {
// printf("STK_END ");
// }
// printf("%G ", tape[i]);
// }
// printf("\n...\n");
// for (int i=0; i<MEMORY_SIZE; i++) {
// if (i == INIT_STACK_PTR) {
// printf("STK_BGN ");
// }
// if (i == (int)tape[SPR]) {
// printf("STK_END ");
// }
// printf("%d ", alloc_tape[i]);
// }
return 0;
}"#;
result
}
}