You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.3 KiB
109 lines
3.3 KiB
use sexp::Sexp;
|
|
|
|
use crate::asm::data::literal::{Label, RoutineName};
|
|
use crate::asm::error::{AsmError, Error};
|
|
use crate::asm::instr::{HLOp, Op};
|
|
use crate::asm::instr::cond::parse_cond;
|
|
use crate::asm::instr::op::OpParser;
|
|
use crate::asm::parse::parse_data::{parse_label, parse_rd, parse_wr};
|
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
|
|
|
pub fn parse_op(keyword: &str, far: bool, arg_tokens_slice: Vec<Sexp>, parsers: &[Box<dyn OpParser>]) -> Result<HLOp, Error> {
|
|
let mut arg_tokens = arg_tokens_slice.clone().into_iter();
|
|
|
|
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())?,
|
|
})
|
|
}
|
|
|
|
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 {
|
|
for p in parsers {
|
|
match p.parse_op(keyword, far, arg_tokens_slice.clone()) {
|
|
Ok(op) => return Ok(HLOp::L(Op::Extension(op))),
|
|
Err(Error::Asm(AsmError::UnknownInstruction)) => {
|
|
/* ok, try another */
|
|
}
|
|
Err(other) => {
|
|
return Err(other);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|