|
|
|
@ -3,7 +3,7 @@ use std::convert::TryFrom; |
|
|
|
|
|
|
|
|
|
use sexp::{Atom, Sexp, SourcePosition}; |
|
|
|
|
|
|
|
|
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData}; |
|
|
|
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData, RdWr}; |
|
|
|
|
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value}; |
|
|
|
|
use crate::asm::error::CrsnError; |
|
|
|
|
use crate::asm::parse::ParserContext; |
|
|
|
@ -71,9 +71,6 @@ pub fn parse_label_str(name: &str, pos: &SourcePosition) -> Result<Label, CrsnEr |
|
|
|
|
/// Parse data disposition (address/value, without the read/write restriction)
|
|
|
|
|
pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
// trace!("parse data: {:?}", tok);
|
|
|
|
|
|
|
|
|
|
// TODO implement masks
|
|
|
|
|
|
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::I(val), _pos) => { |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(val) })) |
|
|
|
@ -94,69 +91,94 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE |
|
|
|
|
Err(CrsnError::Parse("List not expected here".into(), pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
if s == "_" { |
|
|
|
|
return Ok(DataDisp::Discard); |
|
|
|
|
} |
|
|
|
|
parse_data_disp_from_str(&s, &pos, pcx) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(reference) = s.strip_prefix('@') { |
|
|
|
|
/* extension constants (pre-defined handles) */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(reference) { |
|
|
|
|
return Ok(DataDisp::ImmObject(val)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/// Parse data disp from a string token (a &str is used so the string can be preprocessed)
|
|
|
|
|
pub fn parse_data_disp_from_str(s: &str, pos: &SourcePosition, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
if s == "_" { |
|
|
|
|
return Ok(DataDisp::Discard); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register aliases */ |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(reg) = pstate.reg_aliases.get(reference) { |
|
|
|
|
return Ok(DataDisp::RegObject(*reg)) |
|
|
|
|
} else if let Some(reg) = pstate.global_reg_aliases.get(reference) { |
|
|
|
|
return Ok(DataDisp::RegObject(*reg)) |
|
|
|
|
} |
|
|
|
|
if let Some(reference) = s.strip_prefix('@') { |
|
|
|
|
/* extension constants (pre-defined handles) */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(reference) { |
|
|
|
|
return Ok(DataDisp::ImmObject(val)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let reg = reg::parse_reg(reference, &pos)?; |
|
|
|
|
/* register aliases */ |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(reg) = pstate.reg_aliases.get(reference) { |
|
|
|
|
return Ok(DataDisp::RegObject(*reg)) |
|
|
|
|
} else if let Some(reg) = pstate.global_reg_aliases.get(reference) { |
|
|
|
|
return Ok(DataDisp::RegObject(*reg)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::RegObject(reg)) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* extension constants */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(&s) { |
|
|
|
|
return Ok(DataDisp::Immediate(val)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
let reg = reg::parse_reg(reference, pos)?; |
|
|
|
|
|
|
|
|
|
/* program constants */ |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(val) = pstate.constants.get(&s) { |
|
|
|
|
return Ok(DataDisp::Immediate(*val)); |
|
|
|
|
} |
|
|
|
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos.clone())) |
|
|
|
|
} else if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos.clone())) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::RegObject(reg)) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* extension constants */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(&s) { |
|
|
|
|
return Ok(DataDisp::Immediate(val)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register aliases */ |
|
|
|
|
if let Some(val) = pstate.reg_aliases.get(&s) { |
|
|
|
|
return Ok(DataDisp::Register(*val)); |
|
|
|
|
} else if let Some(val) = pstate.global_reg_aliases.get(&s) { |
|
|
|
|
return Ok(DataDisp::Register(*val)); |
|
|
|
|
} |
|
|
|
|
/* program constants */ |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(val) = pstate.constants.get(s) { |
|
|
|
|
return Ok(DataDisp::Immediate(*val)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register */ |
|
|
|
|
let reg = reg::parse_reg(&s, &pos)?; |
|
|
|
|
/* register aliases */ |
|
|
|
|
if let Some(val) = pstate.reg_aliases.get(s) { |
|
|
|
|
return Ok(DataDisp::Register(*val)); |
|
|
|
|
} else if let Some(val) = pstate.global_reg_aliases.get(s) { |
|
|
|
|
return Ok(DataDisp::Register(*val)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::Register(reg)) |
|
|
|
|
/* It can also be a plain old number */ |
|
|
|
|
|
|
|
|
|
if s.starts_with('#') |
|
|
|
|
|| s.starts_with('-') |
|
|
|
|
|| s.starts_with('.') |
|
|
|
|
|| s.starts_with("0x") |
|
|
|
|
|| s.starts_with("0b") |
|
|
|
|
|| s.starts_with(|c : char| c.is_ascii_digit()) |
|
|
|
|
{ |
|
|
|
|
match sexp::atom_of_string(s.to_string()) { |
|
|
|
|
Atom::C(v) => return Ok(DataDisp::Immediate(v as Value)), |
|
|
|
|
Atom::I(v) => return Ok(DataDisp::Immediate(unsafe { std::mem::transmute::<_, u64>(v) } as Value)), |
|
|
|
|
Atom::U(v) => return Ok(DataDisp::Immediate(v as Value)), |
|
|
|
|
Atom::F(v) => return Ok(DataDisp::Immediate(unsafe { std::mem::transmute::<_, u64>(v) } as Value)), |
|
|
|
|
Atom::S(_) | Atom::QS(_) => { |
|
|
|
|
// this will probably fail validation down the line, but it is definitely not a number
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register */ |
|
|
|
|
let reg = reg::parse_reg(&s, &pos)?; |
|
|
|
|
|
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos.clone())) |
|
|
|
|
} else if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() { |
|
|
|
|
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos.clone())) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::Register(reg)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -225,3 +247,59 @@ pub fn parse_wr(tok: Sexp, pcx: &ParserContext) -> Result<Wr, CrsnError> { |
|
|
|
|
let pos = tok.pos().clone(); |
|
|
|
|
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?).err_pos(&pos)?)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_rdwr(tok: Sexp, pcx: &ParserContext) -> Result<RdWr, CrsnError> { |
|
|
|
|
let pos = tok.pos().clone(); |
|
|
|
|
let wr = parse_wr(tok, pcx)?; |
|
|
|
|
if !wr.is_readable() { |
|
|
|
|
return Err(CrsnError::Parse("Argument is not readable!".into(), pos)); |
|
|
|
|
} |
|
|
|
|
Ok(RdWr::new(wr.0)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_wr_offset(tok: Sexp, pcx: &ParserContext) -> Result<(Wr, u32), CrsnError> { |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
let (s, offset) = parse_disp_offs(&s, &pos)?; |
|
|
|
|
Ok((Wr::new(WrData::try_from(parse_data_disp_from_str(s, &pos, pcx)?).err_pos(&pos)?), offset)) |
|
|
|
|
} |
|
|
|
|
_ => Ok((parse_wr(tok, pcx)?, 0)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_rd_offset(tok: Sexp, pcx: &ParserContext) -> Result<(Rd, u32), CrsnError> { |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
let (s, offset) = parse_disp_offs(&s, &pos)?; |
|
|
|
|
Ok((Rd::new(RdData::try_from(parse_data_disp_from_str(s, &pos, pcx)?).err_pos(&pos)?), offset)) |
|
|
|
|
} |
|
|
|
|
_ => Ok((parse_rd(tok, pcx)?, 0)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_rdwr_offset(tok: Sexp, pcx: &ParserContext) -> Result<(RdWr, u32), CrsnError> { |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
let (s, offset) = parse_disp_offs(&s, &pos)?; |
|
|
|
|
let wr = WrData::try_from(parse_data_disp_from_str(s, &pos, pcx)?).err_pos(&pos)?; |
|
|
|
|
|
|
|
|
|
if !wr.is_readable() { |
|
|
|
|
return Err(CrsnError::Parse("Argument is not readable!".into(), pos)); |
|
|
|
|
} |
|
|
|
|
Ok((RdWr::new(wr), offset)) |
|
|
|
|
} |
|
|
|
|
_ => Ok((parse_rdwr(tok, pcx)?, 0)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn parse_disp_offs<'a>(s : &'a str, pos: &SourcePosition) -> Result<(&'a str, u32), CrsnError> { |
|
|
|
|
if s.contains(':') { |
|
|
|
|
let mut split = s.split(':'); |
|
|
|
|
|
|
|
|
|
let disp = split.next().unwrap(); |
|
|
|
|
let num : u32 = split.next().unwrap().parse().err_pos(pos)?; |
|
|
|
|
Ok((disp, num)) |
|
|
|
|
} else { |
|
|
|
|
Ok((&s, 0)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|