use std::cmp; use std::io; use std::process; use std::convert::TryInto; //const CORE_SIZE: usize = 65408 const CORE_SIZE: usize = 192; #[derive(Debug, Eq, PartialEq)] enum State { Compiling, Interpreting } #[derive(Debug)] struct Core { ram: [u8; CORE_SIZE], ip: u16, dp: u16, // newest link field, or 0 here: u16, // first unused byte state: State, dstack: [u16; 16], tds: usize, // post-incremented; exceeds top by one rstack: [u16; 16], trs: usize, // post-incremented; exceeds top by one } type Primitive = fn(&mut Core); struct ShortName { bytes: [u8; 3], length: u8 } fn truncate_name(name: &str) -> ShortName { let name_bytes = name.as_bytes(); let mut out = ShortName { bytes: *b" ", length: name_bytes.len() as u8 }; let n = std::cmp::min(3, out.length) as usize; out.bytes[0..n].copy_from_slice(&name_bytes[0..n]); return out; } struct TableEntry { f: Primitive, name: Option, immediate: bool } const PRIMITIVES: [TableEntry; 13] = [ TableEntry {f: ret , name: None, immediate: false}, TableEntry {f: lit , name: None, immediate: false}, TableEntry {f: call , name: Some(ShortName {bytes: *b"cal", length: 4}), immediate: false}, TableEntry {f: dot , name: Some(ShortName {bytes: *b". ", length: 1}), immediate: false}, TableEntry {f: comma_ , name: Some(ShortName {bytes: *b", ", length: 1}), immediate: false}, TableEntry {f: store , name: Some(ShortName {bytes: *b"! ", length: 1}), immediate: false}, TableEntry {f: load , name: Some(ShortName {bytes: *b"@ ", length: 1}), immediate: false}, TableEntry {f: add , name: Some(ShortName {bytes: *b"+ ", length: 1}), immediate: false}, TableEntry {f: sub , name: Some(ShortName {bytes: *b"- ", length: 1}), immediate: false}, TableEntry {f: mul , name: Some(ShortName {bytes: *b"* ", length: 1}), immediate: false}, TableEntry {f: div , name: Some(ShortName {bytes: *b"/ ", length: 1}), immediate: false}, TableEntry {f: lbracket, name: Some(ShortName {bytes: *b"[ ", length: 1}), immediate: true}, TableEntry {f: rbracket, name: Some(ShortName {bytes: *b"] ", length: 1}), immediate: false} ]; fn new_core() -> Core { let mut c = Core { ram: [0; CORE_SIZE], ip: 0, dp: 0, here: 2, state: State::Interpreting, dstack: [0; 16], tds: 0, rstack: [0; 16], trs: 0 }; init_dictionary(&mut c); return c; } // --- Dictionary management --- fn create(c: &mut Core, name: ShortName) { let addr: usize = c.here as usize; c.ram[addr+0..=addr+1].copy_from_slice(&c.dp.to_le_bytes()); c.dp = addr as u16; c.ram[addr+2] = name.length & 0x7f; c.ram[addr+3..=addr+5].copy_from_slice(&name.bytes); c.here = (addr+6) as u16; } fn find(c: &mut Core, name: ShortName) -> Option { let mut addr = c.dp as usize; while addr != 0 { if (c.ram[addr+2] & 0x7f) == name.length { if c.ram[addr+3..=addr+5] == name.bytes { return Some((addr+6) as u16); } } addr = u16::from_le_bytes(c.ram[addr..=addr+1].try_into().unwrap()) as usize; } return None; } fn init_dictionary(c: &mut Core) { let mut opcode = 65535; for p in PRIMITIVES { match p.name { Some(name) => { create(c, name); if p.immediate { immediate(c); } comma(c, opcode); comma(c, 65535); // ret } None => {} } opcode -= 1; } } fn smudge(c: &mut Core) { c.ram[(c.dp as usize) + 2] ^= 0x40; } fn immediate(c: &mut Core) { c.ram[(c.dp as usize) + 2] ^= 0x80; } fn is_immediate(c: &mut Core, addr: u16) -> bool { return (c.ram[(addr as usize) - 4] & 0x80) != 0; } fn comma(c: &mut Core, val: u16) { let addr = c.here as usize; c.ram[addr..=addr+1].copy_from_slice(&val.to_le_bytes()); c.here += 2; } fn comma_(c: &mut Core) { let val = pop(c); comma(c, val); } // --- Memory management --- fn store(c: &mut Core) { let addr = pop(c) as usize; let val = pop(c); c.ram[addr..=addr+1].copy_from_slice(&val.to_le_bytes()); } fn load(c: &mut Core) { let addr = pop(c) as usize; push(c, u16::from_le_bytes(c.ram[addr..=addr+1].try_into().unwrap())); } // --- Stack management --- fn push(c: &mut Core, val: u16) { c.dstack[c.tds] = val; c.tds += 1; } fn pop(c: &mut Core) -> u16 { c.tds -= 1; return c.dstack[c.tds]; } fn to_r(c: &mut Core, val: u16) { c.rstack[c.trs] = val; c.trs += 1; } fn from_r(c: &mut Core) -> u16 { c.trs -= 1; return c.rstack[c.trs]; } fn call(c: &mut Core) { to_r(c, c.ip); c.ip = pop(c); } // note: this is an inline primitive, not a dict entry fn ret(c: &mut Core) { if c.trs == 0 { } c.ip = from_r(c); } // --- Inner interpreter --- fn fetch(c: &mut Core) -> u16 { let ip = c.ip as usize; let opcode = u16::from_le_bytes(c.ram[ip..=ip+1].try_into().unwrap()); c.ip += 2; return opcode; } fn execute(c: &mut Core, opcode: u16) { let primitive_index = (65535 - opcode) as usize; if primitive_index < PRIMITIVES.len() { (PRIMITIVES[primitive_index].f)(c); } else { // call to_r(c, c.ip); c.ip = opcode; } } fn step(c: &mut Core) { let opcode = fetch(c); execute(c, opcode); } fn inner(c: &mut Core) { loop { step(c); println!("ip={} trs={}", c.ip, c.trs); if c.trs == 0 { break; } } } // --- Math --- fn dot(c: &mut Core) { print!("{} ", pop(c)); } // note: this is an inline primitive, not a dict entry fn lit(c: &mut Core) { let ip = c.ip as usize; push(c, u16::from_le_bytes(c.ram[ip..=ip+1].try_into().unwrap())); c.ip += 2; } fn add(c: &mut Core) { let v1 = pop(c); let v2 = pop(c); push(c, v1 + v2); } fn sub(c: &mut Core) { let v1 = pop(c); let v2 = pop(c); push(c, v2 - v1); } fn mul(c: &mut Core) { let v1 = pop(c); let v2 = pop(c); push(c, v1 * v2); } fn div(c: &mut Core) { let v1 = pop(c); let v2 = pop(c); push(c, v2 / v1); } // --- Outer interpreter --- fn lbracket(c: &mut Core) { c.state = State::Interpreting; } fn rbracket(c: &mut Core) { c.state = State::Compiling; } fn outer(c: &mut Core, s: &str) { let ss = s.trim(); let tokens = ss.split(" "); for t in tokens { match t { "dmp" => { println!("{:?}", c); }, _ => { match find(c, truncate_name(t)) { Some(addr) => { if c.state == State::Interpreting || is_immediate(c, addr) { c.ip = addr; inner(c); } else { comma(c, addr); } } None => { let val = t.parse::(); match val { Ok(n) => { match c.state { State::Interpreting => { push(c, n) } State::Compiling => { comma(c, 65534); // lit comma(c, n); } } } Err(_) => { if t != "" { println!("{}?", t) }} } } } } } } } fn main() { let mut c = new_core(); loop { let mut buf = String::new(); match io::stdin().read_line(&mut buf) { Ok(_) => { outer(&mut c, &buf); println!(" ok");} Err(_) => { break; } } } }