main Inst, pseudo::Inst and Directive are now Parsable.

This commit is contained in:
Filipe Rodrigues 2021-04-26 16:32:19 +01:00
parent 9b79f3b5c9
commit be3a9d6ec0
12 changed files with 223 additions and 31 deletions

View File

@ -21,7 +21,7 @@ pub use reg::Register;
pub use size::InstSize;
// Imports
use self::{basic::Decode as _, pseudo::Decodable as _};
use self::{basic::Decode as _, parse::LineArg, pseudo::Decodable as _};
use crate::{DataTable, FuncTable, Pos};
use std::{borrow::Borrow, ops::Deref};
@ -96,6 +96,29 @@ impl<'a> Inst<'a> {
}
}
impl<'a> Parsable<'a> for Inst<'a> {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &'a str, args: &'a [LineArg], ctx: &'a Ctx) -> Result<Self, ParseError> {
#[rustfmt::skip]
let parsers: &[&dyn Fn() -> Result<Self, ParseError>] = &[
&|| basic ::Inst::parse(mnemonic, args, ctx).map(Self::Basic),
&|| pseudo ::Inst::parse(mnemonic, args, ctx).map(Self::Pseudo),
&|| Directive::parse(mnemonic, args, ctx).map(Self::Directive),
];
// Try to parse each one one by one.
// If we get an unknown mnemonic, try the next, else return the error.
for parser in parsers {
match parser() {
Ok(inst) => return Ok(inst),
Err(ParseError::UnknownMnemonic) => continue,
Err(err) => return Err(err),
}
}
Err(ParseError::UnknownMnemonic)
}
}
impl<'a> InstDisplay<'a> for Inst<'a> {
type Args = impl Iterator<Item = InstFmtArg<'a>>;
type Mnemonic = impl std::fmt::Display;

View File

@ -49,6 +49,22 @@ impl Kind {
Self::WordRight => "lwr",
}
}
/// Returns this kind from it's mnemonic
#[must_use]
pub fn from_mnemonic(mnemonic: &str) -> Option<Self> {
let kind = match mnemonic {
"lb" => Self::Byte,
"lh" => Self::HalfWord,
"lwl" => Self::WordLeft,
"lw" => Self::Word,
"lbu" => Self::ByteUnsigned,
"lhu" => Self::HalfWordUnsigned,
"lwr" => Self::WordRight,
_ => return None,
};
Some(kind)
}
}
/// Load instructions
@ -116,16 +132,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> {
let kind = match mnemonic {
"lb" => Kind::Byte,
"lh" => Kind::HalfWord,
"lwl" => Kind::WordLeft,
"lw" => Kind::Word,
"lbu" => Kind::ByteUnsigned,
"lhu" => Kind::HalfWordUnsigned,
"lwr" => Kind::WordRight,
_ => return Err(ParseError::UnknownMnemonic),
};
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),

View File

@ -41,6 +41,20 @@ impl Kind {
Self::WordRight => "swr",
}
}
/// Returns this kind from it's mnemonic
#[must_use]
pub fn from_mnemonic(mnemonic: &str) -> Option<Self> {
let kind = match mnemonic {
"sb" => Self::Byte,
"sh" => Self::HalfWord,
"swl" => Self::WordLeft,
"sw" => Self::Word,
"swr" => Self::WordRight,
_ => return None,
};
Some(kind)
}
}
/// Store instructions
@ -106,14 +120,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> {
let kind = match mnemonic {
"sb" => Kind::Byte,
"sh" => Kind::HalfWord,
"swl" => Kind::WordLeft,
"sw" => Kind::Word,
"swr" => Kind::WordRight,
_ => return Err(ParseError::UnknownMnemonic),
};
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),

View File

@ -1,12 +1,13 @@
//! Directives
// Imports
use super::{DisplayCtx, InstDisplay, InstFmtArg, InstSize};
use super::{parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError};
use crate::{DataType, Pos};
use ascii::{AsciiChar, AsciiStr};
use dcb_util::NextFromBytes;
use std::{
array,
convert::TryInto,
io::{self, Write},
};
@ -155,6 +156,33 @@ 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)?),
[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)?),
_ => return Err(ParseError::InvalidArguments),
},
"db" => match *args {
[LineArg::Literal(value)] => Self::Db(value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
_ => return Err(ParseError::InvalidArguments),
},
".ascii" => match *args {
[LineArg::String(ref s)] => Self::Ascii(AsciiStr::from_ascii(s).map_err(|_| ParseError::NonAsciiString)?),
_ => return Err(ParseError::InvalidArguments),
},
_ => return Err(ParseError::UnknownMnemonic),
};
Ok(inst)
}
}
impl<'a> InstDisplay<'a> for Directive<'a> {
type Args = array::IntoIter<InstFmtArg<'a>, 1>;
type Mnemonic = &'static str;

View File

@ -26,4 +26,8 @@ pub enum ParseError {
/// Target is not properly aligned
#[error("Target is not properly aligned")]
TargetAlign,
/// String is non-ascii
#[error("String is non-ascii")]
NonAsciiString,
}

View File

@ -12,7 +12,7 @@ pub mod nop;
pub mod store;
// Imports
use super::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize};
use super::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError};
use core::fmt;
/// A pseudo instruction
@ -61,6 +61,31 @@ 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> {
#[rustfmt::skip]
let parsers: &[&dyn Fn() -> Result<Self, ParseError>] = &[
&|| load_imm::Inst::parse(mnemonic, args, ctx).map(Self::LoadImm),
&|| nop ::Inst::parse(mnemonic, args, ctx).map(Self::Nop),
&|| move_reg::Inst::parse(mnemonic, args, ctx).map(Self::MoveReg),
&|| load ::Inst::parse(mnemonic, args, ctx).map(Self::Load),
&|| store ::Inst::parse(mnemonic, args, ctx).map(Self::Store),
];
// Try to parse each one one by one.
// If we get an unknown mnemonic, try the next, else return the error.
for parser in parsers {
match parser() {
Ok(inst) => return Ok(inst),
Err(ParseError::UnknownMnemonic) => continue,
Err(err) => return Err(err),
}
}
Err(ParseError::UnknownMnemonic)
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = impl Iterator<Item = InstFmtArg<'a>>;
type Mnemonic = impl fmt::Display;

View File

@ -3,7 +3,11 @@
// Imports
use super::{Decodable, Encodable};
use crate::{
inst::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Register},
inst::{
basic::{self, load::Kind},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{Join, SignExtended, Signed, Split};
@ -25,7 +29,7 @@ pub struct Inst {
pub target: Pos,
/// Kind
pub kind: basic::load::Kind,
pub kind: Kind,
}
impl Decodable for Inst {
@ -72,6 +76,19 @@ 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 kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, target) = match *args {
[LineArg::Register(value), ref arg] => (value, ctx.arg_pos(arg)?),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { value, target, kind })
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = array::IntoIter<InstFmtArg<'a>, 2>;
type Mnemonic = &'static str;

View File

@ -3,7 +3,7 @@
// Imports
use super::{Decodable, Encodable};
use crate::{
inst::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Register},
inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register},
Pos,
};
use int_conv::{Join, SignExtended, Signed, Split};
@ -140,6 +140,37 @@ 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 {
// Try `u16`, `i16` then `u32` for the literal
LineArg::Literal(value) => {
if let Ok(value) = value.try_into() {
Ok(Kind::HalfWordUnsigned(value))
} else if let Ok(value) = value.try_into() {
Ok(Kind::HalfWordSigned(value))
} else if let Ok(value) = value.try_into() {
Ok(Kind::Word(value))
} else {
Err(ParseError::LiteralOutOfRange)
}
},
_ => Err(ParseError::InvalidArguments),
},
"la" => |ctx: &Ctx, arg: &LineArg| ctx.arg_pos(arg).map(Kind::Address),
_ => return Err(ParseError::UnknownMnemonic),
};
let (dst, kind) = match *args {
[LineArg::Register(dst), ref arg] => (dst, to_kind(ctx, arg)?),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { dst, kind })
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = array::IntoIter<InstFmtArg<'a>, 2>;
type Mnemonic = &'static str;

View File

@ -2,7 +2,7 @@
// Imports
use super::{Decodable, Encodable};
use crate::inst::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Register};
use crate::inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register};
use std::{array, convert::TryInto};
/// Move register instruction
@ -48,6 +48,21 @@ 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> {
if mnemonic != "move" {
return Err(ParseError::UnknownMnemonic);
}
let (dst, src) = match *args {
[LineArg::Register(dst), LineArg::Register(src)] => (dst, src),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { dst, src })
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = array::IntoIter<InstFmtArg<'a>, 2>;
type Mnemonic = &'static str;

View File

@ -2,8 +2,11 @@
// Imports
use super::{Decodable, Encodable};
use crate::inst::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Register};
use std::{array, convert::TryFrom};
use crate::inst::{basic, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register};
use std::{
array,
convert::{TryFrom, TryInto},
};
/// No-op
///
@ -44,6 +47,21 @@ 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> {
if mnemonic != "nop" {
return Err(ParseError::UnknownMnemonic);
}
let len = match *args {
[LineArg::Literal(len)] => len.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { len })
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = array::IntoIter<InstFmtArg<'a>, 1>;
type Mnemonic = &'static str;

View File

@ -3,7 +3,11 @@
// Imports
use super::{Decodable, Encodable};
use crate::{
inst::{basic, DisplayCtx, InstDisplay, InstFmtArg, InstSize, Register},
inst::{
basic::{self, store::Kind},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, InstSize, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{Join, SignExtended, Signed, Split};
@ -25,7 +29,7 @@ pub struct Inst {
pub target: Pos,
/// Kind
pub kind: basic::store::Kind,
pub kind: Kind,
}
impl Decodable for Inst {
@ -71,6 +75,19 @@ 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 kind = Kind::from_mnemonic(mnemonic).ok_or(ParseError::UnknownMnemonic)?;
let (value, target) = match *args {
[LineArg::Register(value), ref arg] => (value, ctx.arg_pos(arg)?),
_ => return Err(ParseError::InvalidArguments),
};
Ok(Self { value, target, kind })
}
}
impl<'a> InstDisplay<'a> for Inst {
type Args = array::IntoIter<InstFmtArg<'a>, 2>;
type Mnemonic = &'static str;

View File

@ -18,7 +18,7 @@ use anyhow::Context;
use dcb_bytes::Bytes;
use dcb_exe::{
inst::{
parse::{self, InstParser},
parse::{line::InstParser, LineArg},
Inst, Label, LabelName,
},
Data, Pos,
@ -91,7 +91,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 parse::Arg::Label(name) | parse::Arg::LabelOffset { label: name, .. } = arg {
if let LineArg::Label(name) | LineArg::LabelOffset { label: name, .. } = arg {
// If the label isn't local, continue
if !name.starts_with('.') {
continue;