use crate::instr::{HLOp, Op}; use sexp::Sexp; use crate::error::Error; use crate::data::literal::{RoutineName, Label}; use crate::parse::sexp_expect::expect_string_atom; use crate::parse::parse_data::{parse_rd, parse_wr, parse_label}; use crate::parse::parse_cond::parse_cond; use crate::data::{Rd, Wr}; pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator + Clone) -> Result { Ok(match keyword { "j" => { let dest = parse_label(arg_tokens.next())?; if far { HLOp::L(Op::FarJump(dest)) } else { HLOp::Jump(dest) } } "call" => { let dest = RoutineName(expect_string_atom(arg_tokens.next())?); let mut args = vec![]; for t in arg_tokens { args.push(parse_rd(Some(t))?); } HLOp::L(Op::Call(dest, args)) } "ret" => { let mut args = vec![]; for t in arg_tokens { args.push(parse_rd(Some(t))?); } HLOp::L(Op::Ret(args)) } "routine" => { let dest = RoutineName(expect_string_atom(arg_tokens.next())?); HLOp::L(Op::Routine(dest)) } "s" => { HLOp::L(Op::Skip(parse_rd(arg_tokens.next())?)) } "sif" => { let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; let offs = parse_rd(arg_tokens.next())?; HLOp::L(Op::SkipIf(cond, offs)) } "jif" => { let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; let dest = parse_label(arg_tokens.next())?; HLOp::JumpIf(cond, dest) } "barrier" => { HLOp::L(Op::Barrier(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), })) } "fault" => { HLOp::L(Op::Fault(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), })) } "ld" => { HLOp::L(Op::Move { dst: parse_wr(arg_tokens.next())?, src: parse_rd(arg_tokens.next())?, }) } "cmp" => { HLOp::L(Op::Compare { a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, }) } "tst" => { let arg = parse_rd(arg_tokens.next())?; HLOp::L(Op::Test { a: arg }) } "inc" => { let dst = parse_wr(arg_tokens.next())?; HLOp::L(Op::Add { dst, a: dst.as_rd(), b: Rd::immediate(1), }) } "dec" => { let dst = parse_wr(arg_tokens.next())?; HLOp::L(Op::Sub { dst, a: dst.as_rd(), b: Rd::immediate(1), }) } "add" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Add { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Add { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("Add requires 2 or 3 arguments".into())); } }) } "sub" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Sub { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Sub { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); } }) } "mul" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Mul { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Mul { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); } }) } "divr" => { HLOp::L(match arg_tokens.len() { 3 => { let dst = parse_wr(arg_tokens.next())?; let rem = parse_wr(arg_tokens.next())?; let div = parse_rd(arg_tokens.next())?; Op::Div { dst, rem, a: dst.as_rd(), div, } } 4 => { Op::Div { dst: parse_wr(arg_tokens.next())?, rem : parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, div: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); } }) } "div" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Div { dst: parse_wr(arg_tokens.next())?, rem: Wr::discard(), a: parse_rd(arg_tokens.next())?, div: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; let div = parse_rd(arg_tokens.next())?; Op::Div { dst, rem: Wr::discard(), a: dst.as_rd(), div, } } _ => { return Err(Error::Parse("Div requires 2 or 3 arguments".into())); } }) } "mod" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Mod { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, div: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; let div = parse_rd(arg_tokens.next())?; Op::Mod { dst, a: dst.as_rd(), div, } } _ => { return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); } }) } "and" => { HLOp::L(match arg_tokens.len() { 3 => { Op::And { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::And { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("And requires 2 or 3 arguments".into())); } }) } "or" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Or { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Or { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("Or requires 2 or 3 arguments".into())); } }) } "xor" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Xor { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, b: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Xor { dst, a: dst.as_rd(), b: parse_rd(arg_tokens.next())?, } } _ => { return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); } }) } "cpl" => { HLOp::L(match arg_tokens.len() { 2 => { Op::Cpl { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Cpl { dst, a: dst.as_rd(), } } _ => { return Err(Error::Parse("Cpl requires 1 or 2 arguments".into())); } }) } "rol" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Rol { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, n: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Rol { dst, a: dst.as_rd(), n: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Rol { dst, a: dst.as_rd(), n: Rd::immediate(1), } } _ => { return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into())); } }) } "ror" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Ror { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, n: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Ror { dst, a: dst.as_rd(), n: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Ror { dst, a: dst.as_rd(), n: Rd::immediate(1), } } _ => { return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into())); } }) } "lsl" | "asl" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Lsl { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, n: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Lsl { dst, a: dst.as_rd(), n: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Lsl { dst, a: dst.as_rd(), n: Rd::immediate(1), } } _ => { return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into())); } }) } "lsr" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Lsr { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, n: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Lsr { dst, a: dst.as_rd(), n: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Lsr { dst, a: dst.as_rd(), n: Rd::immediate(1), } } _ => { return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); } }) } "asr" => { HLOp::L(match arg_tokens.len() { 3 => { Op::Asr { dst: parse_wr(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?, n: parse_rd(arg_tokens.next())?, } } 2 => { let dst = parse_wr(arg_tokens.next())?; Op::Asr { dst, a: dst.as_rd(), n: parse_rd(arg_tokens.next())?, } } 1 => { let dst = parse_wr(arg_tokens.next())?; Op::Asr { dst, a: dst.as_rd(), n: Rd::immediate(1), } } _ => { return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into())); } }) } other => { if let Some(label) = other.strip_prefix(':') { let label = Label::Named(label.to_string()); if far { HLOp::L(Op::FarLabel(label)) } else { HLOp::Label(label) } } else { return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); } } }) }