|
|
|
@ -1,13 +1,15 @@ |
|
|
|
|
use std::borrow::Cow; |
|
|
|
|
use std::convert::TryFrom; |
|
|
|
|
|
|
|
|
|
use sexp::{Atom, Sexp}; |
|
|
|
|
use sexp::{Atom, Sexp, SourcePosition}; |
|
|
|
|
|
|
|
|
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData}; |
|
|
|
|
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value}; |
|
|
|
|
use crate::asm::error::CrsnError; |
|
|
|
|
use crate::asm::parse::ParserContext; |
|
|
|
|
use crate::asm::parse::sexp_expect::expect_string_atom; |
|
|
|
|
use std::num::TryFromIntError; |
|
|
|
|
use crate::asm::patches::ErrWithPos; |
|
|
|
|
|
|
|
|
|
fn is_valid_identifier(name: &str) -> bool { |
|
|
|
|
name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_') |
|
|
|
@ -15,65 +17,60 @@ fn is_valid_identifier(name: &str) -> bool { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Parse register alias
|
|
|
|
|
pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> { |
|
|
|
|
pub fn parse_reg_alias(name: Sexp) -> Result<(RegisterAlias, SourcePosition), CrsnError> { |
|
|
|
|
// trace!("parse reg alias: {:?}", name);
|
|
|
|
|
|
|
|
|
|
let name = expect_string_atom(name)?; |
|
|
|
|
let (name, namepos) = expect_string_atom(name)?; |
|
|
|
|
|
|
|
|
|
if !is_valid_identifier(&name) { |
|
|
|
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into())); |
|
|
|
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into(), namepos)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(name) |
|
|
|
|
Ok((name, namepos)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Parse constant name
|
|
|
|
|
pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError> { |
|
|
|
|
pub fn parse_constant_name(name: Sexp) -> Result<(ConstantName, SourcePosition), CrsnError> { |
|
|
|
|
// trace!("parse const name: {:?}", name);
|
|
|
|
|
|
|
|
|
|
let name = expect_string_atom(name)?; |
|
|
|
|
let (name, namepos) = expect_string_atom(name)?; |
|
|
|
|
|
|
|
|
|
if !is_valid_identifier(&name) { |
|
|
|
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into())); |
|
|
|
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into(), namepos)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(name) |
|
|
|
|
Ok((name, namepos)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Parse a label
|
|
|
|
|
pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> { |
|
|
|
|
pub fn parse_label(name: Sexp) -> Result<Label, CrsnError> { |
|
|
|
|
// trace!("parse label: {:?}", name);
|
|
|
|
|
let name = expect_string_atom(name)?; |
|
|
|
|
Ok(parse_label_str(&name)?) |
|
|
|
|
let (name, namepos) = expect_string_atom(name)?; |
|
|
|
|
Ok(parse_label_str(&name, namepos)?) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_label_str(name: &str) -> Result<Label, CrsnError> { |
|
|
|
|
pub fn parse_label_str(name: &str, pos: SourcePosition) -> Result<Label, CrsnError> { |
|
|
|
|
let label = name.trim_start_matches(':'); |
|
|
|
|
|
|
|
|
|
Ok(if label.starts_with('#') { |
|
|
|
|
Label::Numbered(u32::try_from(parse_u64(&label[1..])?).expect("numbered label fit in u32")) |
|
|
|
|
let val = parse_u64(&label[1..], pos.clone())?; |
|
|
|
|
Label::Numbered(u32::try_from(val).err_pos(pos)?) |
|
|
|
|
} else { |
|
|
|
|
Label::Named(label.to_string()) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Parse data disposition (address/value, without the read/write restriction)
|
|
|
|
|
pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
// trace!("parse data: {:?}", tok);
|
|
|
|
|
|
|
|
|
|
let tok = if let Some(tok) = tok { |
|
|
|
|
tok |
|
|
|
|
} else { |
|
|
|
|
return Err(CrsnError::Parse("Expected data disposition token".into())); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// TODO implement masks
|
|
|
|
|
|
|
|
|
|
match &tok { |
|
|
|
|
Sexp::Atom(Atom::I(val)) => { |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(*val) })) |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::I(val), pos) => { |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(val) })) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::S(s)) => { |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
if s == "_" { |
|
|
|
|
return Ok(DataDisp::Discard); |
|
|
|
|
} |
|
|
|
@ -81,11 +78,11 @@ pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDis |
|
|
|
|
// check if we have an alias defined
|
|
|
|
|
{ |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(val) = pstate.constants.get(s) { |
|
|
|
|
if let Some(val) = pstate.constants.get(&s) { |
|
|
|
|
return Ok(DataDisp::Immediate(*val)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(val) = pstate.reg_aliases.get(s) { |
|
|
|
|
if let Some(val) = pstate.reg_aliases.get(&s) { |
|
|
|
|
return Ok(DataDisp::Register(*val)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -95,63 +92,55 @@ pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDis |
|
|
|
|
if let Some(val) = pstate.reg_aliases.get(reference) { |
|
|
|
|
Ok(DataDisp::ObjectPtr(*val)) |
|
|
|
|
} else { |
|
|
|
|
let reg = reg::parse_reg(reference)?; |
|
|
|
|
let reg = reg::parse_reg(reference, pos.clone())?; |
|
|
|
|
|
|
|
|
|
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())) |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::ObjectPtr(reg)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if s.starts_with(|c: char| c.is_ascii_digit()) { |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(s)?) })) |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(&s, pos)?) })) |
|
|
|
|
} else { |
|
|
|
|
let reg = reg::parse_reg(s)?; |
|
|
|
|
let reg = reg::parse_reg(&s, pos.clone())?; |
|
|
|
|
|
|
|
|
|
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())) |
|
|
|
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) |
|
|
|
|
} else { |
|
|
|
|
Ok(DataDisp::Register(reg)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
Err(CrsnError::Parse(format!("bad data disp: {:?}", tok).into())) |
|
|
|
|
other => { |
|
|
|
|
Err(CrsnError::Parse(format!("bad data disp: {:?}", other).into(), other.pos().clone())) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Parse immediate value
|
|
|
|
|
pub fn parse_value(tok: Option<Sexp>, pcx: &ParserContext) -> Result<Value, CrsnError> { |
|
|
|
|
let tok = if let Some(tok) = tok { |
|
|
|
|
tok |
|
|
|
|
} else { |
|
|
|
|
return Err(CrsnError::Parse("Expected value token".into())); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// trace!("parse value: {:?}", tok);
|
|
|
|
|
|
|
|
|
|
match &tok { |
|
|
|
|
Sexp::Atom(Atom::I(val)) => { |
|
|
|
|
Ok(unsafe { std::mem::transmute(*val) }) |
|
|
|
|
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<Value, CrsnError> { |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::I(val), pos) => { |
|
|
|
|
Ok(unsafe { std::mem::transmute(val) }) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::S(s)) => { |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(val) = pstate.constants.get(s) { |
|
|
|
|
if let Some(val) = pstate.constants.get(&s) { |
|
|
|
|
return Ok(*val); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(unsafe { std::mem::transmute(parse_i64(s)?) }) |
|
|
|
|
Ok(unsafe { std::mem::transmute(parse_i64(&s, pos)?) }) |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
Err(CrsnError::Parse(format!("bad value format: {:?}", tok).into())) |
|
|
|
|
other => { |
|
|
|
|
Err(CrsnError::Parse(format!("bad value format: {:?}", other).into(), other.pos().clone())) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn parse_u64(literal: &str) -> anyhow::Result<u64> { |
|
|
|
|
pub fn parse_u64(literal: &str, pos: SourcePosition) -> Result<u64, CrsnError> { |
|
|
|
|
// trace!("parse u64 from {}", literal);
|
|
|
|
|
let mut without_underscores = Cow::Borrowed(literal); |
|
|
|
|
if without_underscores.contains('_') { |
|
|
|
@ -159,27 +148,29 @@ pub fn parse_u64(literal: &str) -> anyhow::Result<u64> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(hex) = without_underscores.strip_prefix("0x") { |
|
|
|
|
Ok(u64::from_str_radix(hex, 16)?) |
|
|
|
|
Ok(u64::from_str_radix(hex, 16).err_pos(pos)?) |
|
|
|
|
} else if let Some(hex) = without_underscores.strip_prefix("0b") { |
|
|
|
|
Ok(u64::from_str_radix(hex, 2)?) |
|
|
|
|
Ok(u64::from_str_radix(hex, 2).err_pos(pos)?) |
|
|
|
|
} else { |
|
|
|
|
Ok(u64::from_str_radix(&without_underscores, 10)?) |
|
|
|
|
Ok(u64::from_str_radix(&without_underscores, 10).err_pos(pos)?) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_i64(literal: &str) -> anyhow::Result<i64> { |
|
|
|
|
pub fn parse_i64(literal: &str, pos: SourcePosition) -> Result<i64, CrsnError> { |
|
|
|
|
// trace!("parse i64 from {}", literal);
|
|
|
|
|
if let Some(_value) = literal.strip_prefix("-") { |
|
|
|
|
Ok(-1 * i64::try_from(parse_u64(literal)?)?) |
|
|
|
|
Ok(-1 * i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?) |
|
|
|
|
} else { |
|
|
|
|
Ok(i64::try_from(parse_u64(literal)?)?) |
|
|
|
|
Ok(i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_rd(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Rd> { |
|
|
|
|
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?)?)) |
|
|
|
|
pub fn parse_rd(tok: Sexp, pcx: &ParserContext) -> Result<Rd, CrsnError> { |
|
|
|
|
let pos = tok.pos().clone(); |
|
|
|
|
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?).err_pos(pos)?)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn parse_wr(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Wr> { |
|
|
|
|
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?)?)) |
|
|
|
|
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)?)) |
|
|
|
|
} |
|
|
|
|