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.
106 lines
2.8 KiB
106 lines
2.8 KiB
use crate::instr::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;
|
|
|
|
pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Sexp>) -> Result<Op, Error> {
|
|
Ok(match keyword {
|
|
"jmp" | "j" => {
|
|
let dest = parse_label(arg_tokens.next())?;
|
|
if far {
|
|
Op::FarJump(dest)
|
|
} else {
|
|
Op::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))?);
|
|
}
|
|
Op::Call(dest, args)
|
|
}
|
|
|
|
"ret" => {
|
|
let mut args = vec![];
|
|
for t in arg_tokens {
|
|
args.push(parse_rd(Some(t))?);
|
|
}
|
|
Op::Ret(args)
|
|
}
|
|
|
|
"rtn" | "fn" => {
|
|
let dest = RoutineName(expect_string_atom(arg_tokens.next())?);
|
|
Op::Routine(dest)
|
|
}
|
|
|
|
"skip" => {
|
|
Op::Skip(parse_rd(arg_tokens.next())?)
|
|
}
|
|
|
|
"jmp.if" | "j.if" => {
|
|
let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
|
|
let dest = parse_label(arg_tokens.next())?;
|
|
Op::JumpIf(cond, dest)
|
|
}
|
|
|
|
"barrier" => {
|
|
Op::Barrier(match arg_tokens.next() {
|
|
None => None,
|
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
})
|
|
}
|
|
|
|
"fault" => {
|
|
Op::Fault(match arg_tokens.next() {
|
|
None => None,
|
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
})
|
|
}
|
|
|
|
"mov" | "ld" | "mv" => {
|
|
Op::Mov(
|
|
parse_wr(arg_tokens.next())?,
|
|
parse_rd(arg_tokens.next())?
|
|
)
|
|
}
|
|
|
|
"cmp" => {
|
|
Op::Cmp(
|
|
parse_rd(arg_tokens.next())?,
|
|
parse_rd(arg_tokens.next())?
|
|
)
|
|
}
|
|
|
|
"inc" => {
|
|
Op::Inc(
|
|
parse_wr(arg_tokens.next())?
|
|
)
|
|
}
|
|
|
|
"dec" => {
|
|
Op::Dec(
|
|
parse_wr(arg_tokens.next())?
|
|
)
|
|
}
|
|
|
|
other => {
|
|
if let Some(label) = other.strip_prefix(':') {
|
|
let label = Label::Named(label.to_string());
|
|
if far {
|
|
Op::FarLabel(label)
|
|
} else {
|
|
Op::Label(label)
|
|
}
|
|
} else {
|
|
return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|