Updated parse::line to support label functions.

Fixed single-argument "nop" not being parsed.
This commit is contained in:
Filipe Rodrigues 2021-04-28 15:25:56 +01:00
parent 926e2669f7
commit cd6f64cb34
16 changed files with 243 additions and 192 deletions

View File

@ -121,9 +121,7 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
#[rustfmt::skip]
let to_kind = match mnemonic {
"addi" => |value: i64| value.try_into().map(Kind::Add ),
@ -138,16 +136,16 @@ impl<'a> Parsable<'a> for Inst {
match *args {
// Disallow `slti` and `sltiu` in short form
[LineArg::Register(_), LineArg::Literal(_)] if ["slti", "sltiu"].contains(&mnemonic) => {
[LineArg::Register(_), LineArg::Expr(_)] if ["slti", "sltiu"].contains(&mnemonic) => {
Err(ParseError::InvalidArguments)
},
// Else parse both `$dst, $lhs, value` and `$dst, value`.
[LineArg::Register(lhs @ dst), LineArg::Literal(value)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(value)] => Ok(Self {
[LineArg::Register(lhs @ dst), LineArg::Expr(ref expr)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Expr(ref expr)] => Ok(Self {
dst,
lhs,
kind: to_kind(value).map_err(|_| ParseError::LiteralOutOfRange)?,
kind: to_kind(ctx.eval_expr(expr)?).map_err(|_| ParseError::LiteralOutOfRange)?,
}),
_ => Err(ParseError::InvalidArguments),
}

View File

@ -169,14 +169,15 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let inst = match mnemonic {
"cop0" | "cop1" | "cop2" | "cop3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
let imm = match *args {
[LineArg::Literal(imm)] => imm.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
let imm = match args {
[LineArg::Expr(imm)] => ctx
.eval_expr(imm)?
.try_into()
.map_err(|_| ParseError::LiteralOutOfRange)?,
_ => return Err(ParseError::InvalidArguments),
};
@ -189,9 +190,12 @@ impl<'a> Parsable<'a> for Inst {
"mtc3" | "ctc0" | "ctc1" | "ctc2" | "ctc3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
let (reg, imm) = match *args {
[LineArg::Register(dst), LineArg::Literal(src)] => {
(dst, src.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
},
[LineArg::Register(dst), LineArg::Expr(ref imm)] => (
dst,
ctx.eval_expr(imm)?
.try_into()
.map_err(|_| ParseError::LiteralOutOfRange)?,
),
_ => return Err(ParseError::InvalidArguments),
};
@ -224,14 +228,11 @@ impl<'a> Parsable<'a> for Inst {
"lwc0" | "lwc1" | "lwc2" | "lwc3" | "swc0" | "swc1" | "swc2" | "swc3" => {
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
let (dst, src, offset) = match *args {
[LineArg::Literal(dst), LineArg::Register(src)] => {
(dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?, src, 0)
},
[LineArg::Literal(dst), LineArg::RegisterOffset { register: src, offset }] => (
dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
src,
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
),
[LineArg::Expr(ref dst), LineArg::Register(src)] => (ctx.eval_expr_as(dst)?, src, 0),
[LineArg::Expr(ref dst), LineArg::RegisterOffset {
register: src,
ref offset,
}] => (ctx.eval_expr_as(dst)?, src, ctx.eval_expr_as(offset)?),
_ => return Err(ParseError::InvalidArguments),
};

View File

@ -124,21 +124,17 @@ impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
// Note: Literals are absolute, not relative
// Calculates the offset between a position and the current one
// with a possible offset
let offset_of = |pos: Pos, offset: i64| -> Result<i16, ParseError> {
use std::ops::{Add, Div, Sub};
pos.sub(ctx.cur_pos())
.add(offset)
// Calculates the offset between an argument's position and the current one
let target_arg_to_offset = |arg| -> Result<i16, ParseError> {
use std::ops::{Div, Sub};
ctx.arg_pos(arg)?
.sub(ctx.cur_pos())
.div(4)
.sub(1)
.try_into()
.map_err(|_| ParseError::RelativeJumpTooFar)
};
// Calculates the offset of a literal/label/label offset argument
let target_arg_to_offset = |arg| ctx.arg_pos_offset(arg).and_then(|(pos, offset)| offset_of(pos, offset));
let (arg, offset, kind) = match mnemonic {
"b" => match args {
[target] => (Register::Zr, target_arg_to_offset(target)?, Kind::Equal(Register::Zr)),

View File

@ -8,7 +8,7 @@ use crate::inst::{
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Signed, Truncated, ZeroExtended};
use std::{array, convert::TryInto};
use std::array;
/// Instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -131,18 +131,15 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, addr, offset) = match *args {
[LineArg::Register(value), LineArg::Register(addr)] => (value, addr, 0),
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => (
value,
addr,
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
),
[LineArg::Register(value), LineArg::RegisterOffset {
register: addr,
ref offset,
}] => (value, addr, ctx.eval_expr_as(offset)?),
_ => return Err(ParseError::InvalidArguments),
};

View File

@ -8,7 +8,7 @@ use crate::inst::{
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use std::{array, convert::TryInto};
use std::array;
/// Load instructions
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -47,17 +47,15 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
if mnemonic != "lui" {
return Err(ParseError::UnknownMnemonic);
}
match *args {
[LineArg::Register(dst), LineArg::Literal(value)] => Ok(Self {
[LineArg::Register(dst), LineArg::Expr(ref expr)] => Ok(Self {
dst,
value: value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
value: ctx.eval_expr_as(expr)?,
}),
_ => Err(ParseError::InvalidArguments),
}

View File

@ -7,7 +7,7 @@ use crate::inst::{
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use std::{array, convert::TryInto};
use std::array;
/// Shift immediate instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -106,9 +106,7 @@ impl TryEncode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let kind = match mnemonic {
"sll" => Kind::LeftLogical,
"srl" => Kind::RightLogical,
@ -117,11 +115,11 @@ impl<'a> Parsable<'a> for Inst {
};
match *args {
[LineArg::Register(lhs @ dst), LineArg::Literal(rhs)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Literal(rhs)] => Ok(Self {
[LineArg::Register(lhs @ dst), LineArg::Expr(ref rhs)] |
[LineArg::Register(dst), LineArg::Register(lhs), LineArg::Expr(ref rhs)] => Ok(Self {
dst,
lhs,
rhs: rhs.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
rhs: ctx.eval_expr_as(rhs)?,
kind,
}),
_ => Err(ParseError::InvalidArguments),

View File

@ -8,7 +8,7 @@ use crate::inst::{
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Signed, Truncated, ZeroExtended};
use std::{array, convert::TryInto};
use std::array;
/// Store instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -119,18 +119,15 @@ impl Encode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, addr, offset) = match *args {
[LineArg::Register(value), LineArg::Register(addr)] => (value, addr, 0),
[LineArg::Register(value), LineArg::RegisterOffset { register: addr, offset }] => (
value,
addr,
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
),
[LineArg::Register(value), LineArg::RegisterOffset {
register: addr,
ref offset,
}] => (value, addr, ctx.eval_expr_as(offset)?),
_ => return Err(ParseError::InvalidArguments),
};

View File

@ -7,7 +7,7 @@ use crate::inst::{
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::{array, convert::TryInto};
use std::array;
/// Sys instruction func
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -87,17 +87,15 @@ impl TryEncode for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let kind = match mnemonic {
"sys" => Kind::Sys,
"break" => Kind::Break,
_ => return Err(ParseError::UnknownMnemonic),
};
let comment = match *args {
[LineArg::Literal(comment)] => comment.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
let comment = match args {
[LineArg::Expr(comment)] => ctx.eval_expr_as(comment)?,
_ => return Err(ParseError::InvalidArguments),
};

View File

@ -7,7 +7,6 @@ use ascii::{AsciiChar, AsciiStr};
use dcb_util::NextFromBytes;
use std::{
array,
convert::TryInto,
io::{self, Write},
};
@ -163,23 +162,21 @@ impl<'a> Directive<'a> {
impl<'a> Parsable<'a> for Directive<'a> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let inst = match mnemonic {
"dw" => match *args {
[LineArg::Literal(value)] => Self::Dw(value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
"dw" => match args {
[LineArg::Expr(expr)] => Self::Dw(ctx.eval_expr_as(expr)?),
[ref arg] => Self::Dw(ctx.arg_pos(arg)?.0),
_ => return Err(ParseError::InvalidArguments),
},
"dh" => match *args {
[LineArg::Literal(value)] => Self::Dh(value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
"dh" => match args {
[LineArg::Expr(expr)] => Self::Dh(ctx.eval_expr_as(expr)?),
_ => return Err(ParseError::InvalidArguments),
},
"db" => match *args {
[LineArg::Literal(value)] => Self::Db(value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
"db" => match args {
[LineArg::Expr(expr)] => Self::Db(ctx.eval_expr_as(expr)?),
_ => return Err(ParseError::InvalidArguments),
},
".ascii" => match *args {
[LineArg::String(ref s)] => {
Self::Ascii(AsciiStr::from_ascii(s).map_err(|_| ParseError::NonAsciiString)?)
},
".ascii" => match args {
[LineArg::String(s)] => Self::Ascii(AsciiStr::from_ascii(s).map_err(|_| ParseError::NonAsciiString)?),
_ => return Err(ParseError::InvalidArguments),
},
_ => return Err(ParseError::UnknownMnemonic),

View File

@ -6,11 +6,11 @@ pub mod line;
// Exports
pub use error::ParseError;
pub use line::{Line, LineArg};
pub use line::{Line, LineArg, LineArgExpr, LineLabelFunc};
// Imports
use crate::Pos;
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};
/// Instruction parsing
pub trait Parsable<'a>: Sized + 'a {
@ -26,34 +26,60 @@ pub trait ParseCtx {
/// Returns the position of a label
fn label_pos(&self, label: &str) -> Option<Pos>;
/// Retrieves a position from an argument
fn arg_pos(&self, arg: &LineArg) -> Result<Pos, ParseError> {
match *arg {
LineArg::Literal(pos) => pos.try_into().map(Pos).map_err(|_| ParseError::LiteralOutOfRange),
LineArg::Label(ref label) => self.label_pos(label).ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self
.label_pos(label)
.map(|pos| pos + offset)
.ok_or(ParseError::UnknownLabel),
_ => Err(ParseError::InvalidArguments),
/// Evaluates an expression
fn eval_expr(&self, expr: &LineArgExpr) -> Result<i64, ParseError> {
match *expr {
LineArgExpr::Literal(num) => Ok(num),
LineArgExpr::Label {
ref label,
offset,
ref func,
} => {
// Get the label value
let value: i64 = self.label_pos(label).ok_or(ParseError::UnknownLabel)?.0.into();
// Then add the offset
let value = value
.checked_add(offset.unwrap_or(0))
.ok_or(ParseError::LiteralOutOfRange)?;
// And evaluate any function on it
let value = func.as_ref().map_or(Ok(value), |func| self.eval_func(value, func))?;
Ok(value)
},
}
}
/// Retrieves a position and offset from an argument
fn arg_pos_offset(&self, arg: &LineArg) -> Result<(Pos, i64), ParseError> {
match *arg {
LineArg::Literal(pos) => pos
/// Evaluates an expression as `T`, returning `LiteralOutOfBounds` else
fn eval_expr_as<T: TryFrom<i64>>(&self, expr: &LineArgExpr) -> Result<T, ParseError> {
self.eval_expr(expr)?
.try_into()
.map_err(|_| ParseError::LiteralOutOfRange)
}
/// Evaluates a function on a literal
fn eval_func(&self, value: i64, func: &LineLabelFunc) -> Result<i64, ParseError> {
// Converts a value into a position
let to_pos = |value: i64| value.try_into().map(Pos).map_err(|_| ParseError::LiteralOutOfRange);
let value = match func {
// For address, first get the value as a position to make sure it's within range
LineLabelFunc::AddrLo => i64::from(to_pos(value)?.0 & 0xFFFF),
LineLabelFunc::AddrHi => i64::from(to_pos(value)?.0 >> 16u32),
};
Ok(value)
}
/// Retrieves a position from an argument
fn arg_pos(&self, arg: &LineArg) -> Result<Pos, ParseError> {
match arg {
LineArg::Expr(expr) => self
.eval_expr(expr)?
.try_into()
.map(|pos| (Pos(pos), 0))
.map(Pos)
.map_err(|_| ParseError::LiteralOutOfRange),
LineArg::Label(ref label) => self
.label_pos(label)
.map(|pos| (pos, 0))
.ok_or(ParseError::UnknownLabel),
LineArg::LabelOffset { ref label, offset } => self
.label_pos(label)
.map(|pos| (pos, offset))
.ok_or(ParseError::UnknownLabel),
_ => Err(ParseError::InvalidArguments),
}
}

View File

@ -6,7 +6,7 @@ pub mod error;
use std::str::FromStr;
// Exports
pub use error::{ParseLineError, ReadArgError, ReadLiteralError, ReadNameError};
pub use error::{ParseLineError, ReadArgError, ReadFuncError, ReadLiteralError, ReadNameError};
// Imports
use crate::inst::Register;
@ -48,8 +48,8 @@ impl Line {
continue;
},
// If we got '#', we got a mnemonic with no arguments
Some('#') => {
// If we got '#' or eof, we got a mnemonic with no arguments
Some('#') | None => {
return Ok(Self {
labels,
inst: Some(LineInst {
@ -59,12 +59,12 @@ impl Line {
});
},
// If we got a space or eof, we got a mnemonic
Some(' ') | None => {
// If we got a space or eof, we found the mnemonic.
// On a space, break and read arguments
Some(' ') => {
line = rest.as_str().trim_start();
break name.to_owned();
},
_ => return Err(ParseLineError::InvalidNameSuffix),
}
};
@ -72,14 +72,6 @@ impl Line {
// Then read all arguments
let mut args = vec![];
loop {
// If the line starts with a comment, there are no arguments
if line.starts_with('#') {
return Ok(Self {
labels: vec![],
inst: Some(LineInst { mnemonic, args }),
});
}
// Read an argument
let (arg, rest) = self::read_arg(line)?;
args.push(arg);
@ -134,6 +126,10 @@ pub enum LineArg {
/// `<reg>`
Register(Register),
/// Mnemonic
/// `^<mnemonic>`
Mnemonic(String),
/// Register offset
/// `<offset>(<reg>)`
RegisterOffset {
@ -141,30 +137,41 @@ pub enum LineArg {
register: Register,
/// The offset
offset: i64,
offset: LineArgExpr,
},
/// Expression
Expr(LineArgExpr),
}
/// Line argument expression
#[derive(PartialEq, Clone, Debug)]
pub enum LineArgExpr {
/// Literal
/// `<literal>`
Literal(i64),
/// Label
/// `<name>`
Label(String),
/// LabelOffset
/// `<name>+<offset>`
LabelOffset {
/// `<name>(`+<offset>`)?(@<func>)?`
Label {
/// The label
label: String,
/// The offset
offset: i64,
},
offset: Option<i64>,
/// Mnemonic
/// `^<mnemonic>`
Mnemonic(String),
/// The function
func: Option<LineLabelFunc>,
},
}
/// Line label functions
#[derive(PartialEq, Clone, Debug)]
pub enum LineLabelFunc {
/// Lower 16 bits of address
AddrLo,
/// Higher 16 bits of address
AddrHi,
}
/// Reads a name
@ -201,14 +208,16 @@ fn read_arg(s: &str) -> Result<(LineArg, &str), ReadArgError> {
// If we got '^', it's a mnemonic
Some((_, '^')) => self::read_name(chars.as_str())
.map(|(name, rest)| (LineArg::Label(name.to_owned()), rest))
.map(|(name, rest)| (LineArg::Mnemonic(name.to_owned()), rest))
.map_err(ReadArgError::ReadLabel),
// If it's numeric, 0..9 or '+' / '-', it's a literal
Some((_, '0'..='9' | '+' | '-')) => {
// Read the number
let (num, rest) = self::read_literal(s).map_err(ReadArgError::ReadLiteral)?;
// Else try to read an expression
Some(_) => {
// Read the expression
let (expr, rest) = self::read_expr(s)?;
// Then check if we have a register
let rest = rest.trim_start();
match rest.strip_prefix('(') {
// If the rest starts with '(', read it as a register offset
Some(rest) => match rest.split_once(')') {
@ -224,38 +233,58 @@ fn read_arg(s: &str) -> Result<(LineArg, &str), ReadArgError> {
Ok((
LineArg::RegisterOffset {
register: reg,
offset: num,
offset: expr,
},
rest,
))
},
None => Err(ReadArgError::MissingRegisterOffsetDelimiter),
},
None => Ok((LineArg::Literal(num), rest)),
None => Ok((LineArg::Expr(expr), rest)),
}
},
None => Err(ReadArgError::Empty),
}
}
/// Reads an expression
fn read_expr(s: &str) -> Result<(LineArgExpr, &str), ReadArgError> {
let mut chars = s.char_indices();
match chars.next() {
// If it's numeric, 0..9 or '+' / '-', it's a simple literal
Some((_, '0'..='9' | '+' | '-')) => self::read_literal(s)
.map(|(num, rest)| (LineArgExpr::Literal(num), rest))
.map_err(ReadArgError::ReadLiteral),
// If it starts with a label char, it's a label
Some((_, c)) if self::is_valid_first_name_char(c) => {
// Read the label
let (label, rest) = self::read_name(s).map_err(ReadArgError::ReadLabel)?;
// If there's a '+' after, read an offset too
match rest.strip_prefix('+') {
Some(rest) => {
// Read the offset
let (offset, rest) = self::read_literal(rest).map_err(ReadArgError::ReadLabelOffset)?;
let (offset, rest) = match rest.strip_prefix('+') {
Some(rest) => self::read_literal(rest)
.map(|(num, rest)| (Some(num), rest))
.map_err(ReadArgError::ReadLabelOffset)?,
None => (None, rest),
};
Ok((
LineArg::LabelOffset {
label: label.to_owned(),
offset,
},
rest,
))
},
None => Ok((LineArg::Label(label.to_owned()), rest)),
}
// If there's a '@' after, read a function too
let (func, rest) = match rest.strip_prefix('@') {
Some(rest) => self::read_func(rest)
.map(|(func, rest)| (Some(func), rest))
.map_err(ReadArgError::ReadLabelFunc)?,
None => (None, rest),
};
let label = LineArgExpr::Label {
label: label.to_owned(),
offset,
func,
};
Ok((label, rest))
},
// Else it's an invalid char
@ -276,6 +305,13 @@ fn read_reg(s: &str) -> Result<(Register, &str), ReadArgError> {
}
}
/// Reads a func
fn read_func(s: &str) -> Result<(LineLabelFunc, &str), ReadFuncError> {
None.or_else(|| s.strip_prefix("addr_hi").map(|rest| (LineLabelFunc::AddrHi, rest)))
.or_else(|| s.strip_prefix("addr_lo").map(|rest| (LineLabelFunc::AddrLo, rest)))
.ok_or(ReadFuncError::Unknown)
}
/// Reads a string
fn read_string(s: &str) -> Result<(String, &str), ReadArgError> {
let mut is_escaping = false;

View File

@ -43,6 +43,14 @@ pub enum ReadLiteralError {
Parse(#[from] std::num::ParseIntError),
}
/// Func reading error
#[derive(Debug, thiserror::Error)]
pub enum ReadFuncError {
/// Parse
#[error("Unknown functions")]
Unknown,
}
/// Argument reading error
#[derive(Debug, thiserror::Error)]
pub enum ReadArgError {
@ -70,6 +78,10 @@ pub enum ReadArgError {
#[error("Unable to read label offset")]
ReadLabelOffset(#[source] ReadLiteralError),
/// Read label func
#[error("Unable to read label func")]
ReadLabelFunc(#[source] ReadFuncError),
/// Expected register
#[error("Expected register")]
ExpectedRegister,

View File

@ -157,9 +157,10 @@ impl Encodable for Inst {
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
let to_kind = match mnemonic {
"li" => |_ctx: &Ctx, arg: &LineArg| match *arg {
"li" => |ctx: &Ctx, arg: &LineArg| match arg {
// Try `i16`, `u16` then `u32` for the literal
LineArg::Literal(value) => {
LineArg::Expr(expr) => {
let value = ctx.eval_expr(expr)?;
if let Ok(value) = value.try_into() {
Ok(Kind::HalfWordSigned(value))
} else if let Ok(value) = value.try_into() {

View File

@ -5,10 +5,7 @@ use super::{Decodable, Encodable};
use crate::inst::{
basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
};
use std::{
array,
convert::{TryFrom, TryInto},
};
use std::{array, convert::TryFrom};
/// No-op
///
@ -50,15 +47,14 @@ impl Encodable for Inst {
}
impl<'a> Parsable<'a> for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(
mnemonic: &'a str, args: &'a [LineArg], _ctx: &'a Ctx,
) -> Result<Self, ParseError> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
if mnemonic != "nop" {
return Err(ParseError::UnknownMnemonic);
}
let len = match *args {
[LineArg::Literal(len)] => len.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
let len = match args {
[] => 1,
[LineArg::Expr(len)] => ctx.eval_expr_as(len)?,
_ => return Err(ParseError::InvalidArguments),
};

View File

@ -18,7 +18,7 @@ use anyhow::Context;
use dcb_bytes::Bytes;
use dcb_exe::{
inst::{
parse::{Line, LineArg},
parse::{Line, LineArg, LineArgExpr},
Inst, InstSize, Label, LabelName, Parsable, ParseCtx,
},
Data, Pos,
@ -107,7 +107,7 @@ fn main() -> Result<(), anyhow::Error> {
if let Some(mut inst) = line.inst {
// Modify any local labels
for arg in &mut inst.args {
if let LineArg::Label(name) | LineArg::LabelOffset { label: name, .. } = arg {
if let LineArg::Expr(LineArgExpr::Label { label: name, .. }) = arg {
// If the label isn't local, continue
if !name.starts_with('.') {
continue;

View File

@ -1,89 +1,89 @@
? pos: 0x8001414c
arg: 1
: "something10@hi"
: "something10@addr_hi"
? pos: 0x80014154
arg: 1
: "something10@lo"
: "something10@addr_lo"
? pos: 0x80013f1c
arg: 1
: "ZeroStart@hi"
: "ZeroStart@addr_hi"
? pos: 0x80013f20
arg: 1
: "ZeroStart@lo"
: "ZeroStart@addr_lo"
? pos: 0x80013f30
arg: 1
: "ZeroStart@lo"
: "ZeroStart@addr_lo"
? pos: 0x80013f34
arg: 1
: "data_w686@hi"
: "data_w686@addr_hi"
? pos: 0x80013f38
arg: 2
: "data_w686@lo"
: "data_w686@addr_lo"
? pos: 0x80013f3c
arg: 1
: "data_w686@lo"
: "data_w686@addr_lo"
? pos: 0x80013f60
arg: 1
: "main_loop_data1@hi"
: "main_loop_data1@addr_hi"
? pos: 0x80013f68
arg: 1
: "main_loop_data1@lo"
: "main_loop_data1@addr_lo"
? pos: 0x80013f6c
arg: 1
: "ZeroStart@lo"
: "ZeroStart@addr_lo"
? pos: 0x80013f7c
arg: 1
: "ZeroStart@lo"
: "ZeroStart@addr_lo"
? pos: 0x80013f78
arg: 1
: "data_w686@hi"
: "data_w686@addr_hi"
? pos: 0x80013f84
arg: 1
: "data_w686@lo"
: "data_w686@addr_lo"
? pos: 0x80013f80
arg: 1
: "main_loop_data1@hi"
: "main_loop_data1@addr_hi"
? pos: 0x80013f88
arg: 1
: "main_loop_data1@lo"
: "main_loop_data1@addr_lo"
? pos: 0x80013fd0
arg: 1
: "ZeroStart@hi"
: "ZeroStart@addr_hi"
? pos: 0x80013fd4
arg: 1
: "ZeroStart@lo"
: "ZeroStart@addr_lo"
? pos: 0x80013ff4
arg: 1
: "something11_data6@hi"
: "something11_data6@addr_hi"
? pos: 0x8001400c
arg: 1
: "something11_data6@lo"
: "something11_data6@addr_lo"
? pos: 0x80013ff8
arg: 1
: "something11_data1@hi"
: "something11_data1@addr_hi"
? pos: 0x80014008
arg: 1
: "something11_data1@lo"
: "something11_data1@addr_lo"
? pos: 0x80013ffc
arg: 1
: "something11_data3@hi"
: "something11_data3@addr_hi"
? pos: 0x80014004
arg: 1
: "something11_data3@lo"
: "something11_data3@addr_lo"
? pos: 0x80014010
arg: 1
: "something11_data5@hi"
: "something11_data5@addr_hi"
? pos: 0x8001401c
arg: 1
: "something11_data5@lo"
: "something11_data5@addr_lo"