mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-04 00:21:57 +00:00
main Inst, pseudo::Inst and Directive are now Parsable.
This commit is contained in:
parent
9b79f3b5c9
commit
be3a9d6ec0
@ -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;
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user