|
|
|
@ -3,7 +3,7 @@ use std::convert::TryFrom; |
|
|
|
|
|
|
|
|
|
use sexp::{Atom, Sexp, SourcePosition}; |
|
|
|
|
|
|
|
|
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData, RdWr}; |
|
|
|
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData, RdWr, Register}; |
|
|
|
|
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value}; |
|
|
|
|
use crate::asm::error::CrsnError; |
|
|
|
|
use crate::asm::parse::{ParserContext, parse_instructions}; |
|
|
|
@ -75,6 +75,7 @@ pub fn parse_label_str(name: &str, pos: &SourcePosition) -> Result<Label, CrsnEr |
|
|
|
|
pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
// trace!("parse data: {:?}", tok);
|
|
|
|
|
match tok { |
|
|
|
|
// immediates are okay in const eval - no tests needed
|
|
|
|
|
Sexp::Atom(Atom::I(val), _pos) => { |
|
|
|
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(val) })) |
|
|
|
|
} |
|
|
|
@ -92,10 +93,12 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE |
|
|
|
|
} |
|
|
|
|
Sexp::List(list, pos) => { |
|
|
|
|
if let Some(Sexp::Atom(Atom::S(s), s_pos)) = list.first() { |
|
|
|
|
// Const eval
|
|
|
|
|
|
|
|
|
|
let parsing_expr = pcx.state.borrow().parsing_expr; |
|
|
|
|
|
|
|
|
|
if !s.starts_with('=') && !parsing_expr { |
|
|
|
|
return Err(CrsnError::Parse(format!("Invalid syntax, did you mean \"={}\"?", s).into(), s_pos.clone())); |
|
|
|
|
return Err(CrsnError::Parse(format!("Invalid syntax, did you mean \"={}\" (a compile-time expression)?", s).into(), s_pos.clone())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// start expr parsing mode
|
|
|
|
@ -116,6 +119,10 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE |
|
|
|
|
|
|
|
|
|
let op = expr_ops.remove(0); |
|
|
|
|
|
|
|
|
|
if !op.is_compile_time_evaluable() { |
|
|
|
|
return Err(CrsnError::Parse(format!("Instruction {} cannot be used in an expression!", op.to_sexp()).into(), pos.clone())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut state_mut = pcx.state.borrow_mut(); |
|
|
|
|
state_mut.const_eval.clear_all(); |
|
|
|
|
|
|
|
|
@ -144,12 +151,16 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// 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> { |
|
|
|
|
fn parse_data_disp_from_str(s: &str, pos: &SourcePosition, pcx: &ParserContext) -> Result<DataDisp, CrsnError> { |
|
|
|
|
if s == "_" { |
|
|
|
|
return Ok(DataDisp::Discard); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(reference) = s.strip_prefix('@') { |
|
|
|
|
if pcx.state.borrow().parsing_expr { |
|
|
|
|
return Err(CrsnError::Parse("Object handles cannot be used in expressions!".into(), pos.clone())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* extension constants (pre-defined handles) */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(reference) { |
|
|
|
@ -188,7 +199,7 @@ pub fn parse_data_disp_from_str(s: &str, pos: &SourcePosition, pcx: &ParserConte |
|
|
|
|
return Ok(DataDisp::Immediate(*val)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register aliases */ |
|
|
|
|
/* register aliases - no need to check for const_eval, the aliases could never be defined */ |
|
|
|
|
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) { |
|
|
|
@ -215,6 +226,14 @@ pub fn parse_data_disp_from_str(s: &str, pos: &SourcePosition, pcx: &ParserConte |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if pcx.state.borrow().parsing_expr { |
|
|
|
|
if s == "=result" { |
|
|
|
|
return Ok(DataDisp::Register(Register::Gen(0))); |
|
|
|
|
} else { |
|
|
|
|
return Err(CrsnError::Parse("Registers cannot be used in expressions!".into(), pos.clone())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* register */ |
|
|
|
|
let reg = reg::parse_reg(&s, &pos)?; |
|
|
|
|
|
|
|
|
@ -231,39 +250,13 @@ pub fn parse_data_disp_from_str(s: &str, pos: &SourcePosition, pcx: &ParserConte |
|
|
|
|
|
|
|
|
|
/// Parse immediate value
|
|
|
|
|
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<(Value, SourcePosition), CrsnError> { |
|
|
|
|
match tok { |
|
|
|
|
Sexp::Atom(Atom::I(val), pos) => { |
|
|
|
|
Ok((unsafe { std::mem::transmute(val) }, pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::U(val), pos) => { |
|
|
|
|
Ok((val, pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::C(val), pos) => { |
|
|
|
|
Ok((val as u64, pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::QS(_), pos) => { |
|
|
|
|
Err(CrsnError::Parse("quoted string not expected here".into(), pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::F(val), pos) => { |
|
|
|
|
Ok((unsafe { std::mem::transmute(val) }, pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::Atom(Atom::S(s), pos) => { |
|
|
|
|
let pstate = pcx.state.borrow(); |
|
|
|
|
if let Some(val) = pstate.constants.get(&s) { |
|
|
|
|
return Ok((*val, pos)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* extension constants */ |
|
|
|
|
for p in pcx.parsers { |
|
|
|
|
if let Some(val) = p.get_constant_value(&s) { |
|
|
|
|
return Ok((val, pos)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
let pos = tok.pos().clone(); |
|
|
|
|
let parsed = parse_rd(tok, pcx)?; |
|
|
|
|
|
|
|
|
|
Err(CrsnError::Parse(format!("unknown constant: {}", s).into(), pos)) |
|
|
|
|
} |
|
|
|
|
Sexp::List(_, pos) => { |
|
|
|
|
Err(CrsnError::Parse("expected a value".into(), pos)) |
|
|
|
|
match parsed { |
|
|
|
|
Rd(RdData::Immediate(value)) => Ok((value, pos)), |
|
|
|
|
_ => { |
|
|
|
|
Err(CrsnError::Parse("expected an immediate value".into(), pos)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|