From e560fc5657c0254b3d1bc3862331ab43561f19ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 17 Oct 2020 22:52:07 +0200 Subject: [PATCH] DRY arithmetic parsing --- crsn/src/asm/parse/arg_parser.rs | 35 ++- crsn_arith/src/parse.rs | 488 ++++--------------------------- 2 files changed, 82 insertions(+), 441 deletions(-) diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index fbb6192..596be39 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -189,7 +189,7 @@ impl<'a> TokenParser<'a> { Ok(Some((wr, rd1, rd2, mask))) } else { - Err(CrsnError::Parse("Instruction needs 2 (RW Rd) or 3 (Wr Rd Rd) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 2 (RW,Rd) or 3 (Wr,Rd,Rd) arguments!".into(), self.start_pos.clone())) } } else { Ok(None) @@ -232,7 +232,7 @@ impl<'a> TokenParser<'a> { Ok(Some((wr, rd, mask))) } else { - Err(CrsnError::Parse("Instruction needs 1 (RW) or 2 (Wr Rd) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 1 (RW) or 2 (Wr,Rd) arguments!".into(), self.start_pos.clone())) } } else { Ok(None) @@ -262,7 +262,7 @@ impl<'a> TokenParser<'a> { Ok(Some((wr1, wr2, mask))) } else { - Err(CrsnError::Parse("Instruction needs 2 (RW RW) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 2 (RW,RW) arguments!".into(), self.start_pos.clone())) } } else { Ok(None) @@ -270,6 +270,7 @@ impl<'a> TokenParser<'a> { } /// Parse combining binary instruction operands (i.e. add) without masks + /// Accepts (Wr, Rd, Rd) and (RdWr, Rd) pub fn parse_wr_rd_rd(&mut self) -> Result<(Wr, Rd, Rd), CrsnError> { if self.len() == 2 { let rw = self.next_rdwr()?; @@ -281,11 +282,32 @@ impl<'a> TokenParser<'a> { let rd2 = self.next_rd()?; Ok((wr, rd1, rd2)) } else { - Err(CrsnError::Parse("Instruction needs 2 (RW Rd) or 3 (Wr Rd Rd) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 2 (RW,Rd) or 3 (Wr,Rd,Rd) arguments!".into(), self.start_pos.clone())) + } + } + + /// Parse combining binary instruction operands (i.e. add) without masks + /// Accepts (Wr, Rd, Rd) and (RdWr, Rd) + pub fn parse_wr_rd_rd_or_n(&mut self, n : Value) -> Result<(Wr, Rd, Rd), CrsnError> { + if self.len() == 1 { + let rw = self.next_rdwr()?; + Ok((rw.wr(), rw.rd(), Rd::immediate(n))) + } else if self.len() == 2 { + let rw = self.next_rdwr()?; + let rd = self.next_rd()?; + Ok((rw.wr(), rw.rd(), rd)) + } else if self.len() == 3 { + let wr = self.next_wr()?; + let rd1 = self.next_rd()?; + let rd2 = self.next_rd()?; + Ok((wr, rd1, rd2)) + } else { + Err(CrsnError::Parse("Instruction needs 1 (RW,1), 2 (RW,Rd) or 3 (Wr,Rd,Rd) arguments!".into(), self.start_pos.clone())) } } /// Parse unary instruction operands (i.e. complement) without masks + /// Accepts (Wr, Rd) and (RdWr) pub fn parse_wr_rd(&mut self) -> Result<(Wr, Rd), CrsnError> { if self.len() == 1 { let rw = self.next_rdwr()?; @@ -295,18 +317,19 @@ impl<'a> TokenParser<'a> { let rd = self.next_rd()?; Ok((wr, rd)) } else { - Err(CrsnError::Parse("Instruction needs 1 (RW) or 2 (Wr Rd) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 1 (RW) or 2 (Wr,Rd) arguments!".into(), self.start_pos.clone())) } } /// Parse a swap-type binary instruction operands (i.e. exchange) without masks + /// Accepts (RdWr, RdWr) pub fn parse_rdwr_rdwr(&mut self, _keyword: &str, _prefix: &str, _pos: &SourcePosition) -> Result<(RdWr, RdWr), CrsnError> { if self.len() == 2 { let rw1 = self.next_rdwr()?; let rw2 = self.next_rdwr()?; Ok((rw1, rw2)) } else { - Err(CrsnError::Parse("Instruction needs 2 (RW RW) arguments!".into(), self.start_pos.clone())) + Err(CrsnError::Parse("Instruction needs 2 (RW,RW) arguments!".into(), self.start_pos.clone())) } } } diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index 99d9d2a..3e085f7 100644 --- a/crsn_arith/src/parse.rs +++ b/crsn_arith/src/parse.rs @@ -11,27 +11,25 @@ use crate::defs::ArithOp; pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "cmp" => { - ArithOp::Compare { - a: args.next_rd()?, - b: args.next_rd()?, - } + let parsed = ArithOp::Compare { a: args.next_rd()?, b: args.next_rd()? }; + args.ensure_empty("two input arguments")?; + parsed } "rcmp" => { - ArithOp::RangeTest { - val: args.next_rd()?, - a: args.next_rd()?, - b: args.next_rd()?, - } + let parsed = ArithOp::RangeTest { val: args.next_rd()?, a: args.next_rd()?, b: args.next_rd()? }; + args.ensure_empty("3 arguments (value, min, max)")?; + parsed } "tst" => { let arg = args.next_rd()?; + args.ensure_empty("1 input argument")?; ArithOp::Test { a: arg } } "rng" => { - match args.len() { + let parsed = match args.len() { 1 => { ArithOp::Rng { dst: args.next_wr()?, @@ -56,94 +54,34 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP _ => { return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), op_pos.clone())); } - } + }; + args.ensure_empty("1 (dst) or 3 (dst, min, max) arguments")?; + parsed } "inc" => { - let dst = args.next_rdwr()?; - ArithOp::Add { - dst: dst.wr(), - a: dst.rd(), - b: Rd::immediate(1), - } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::Add { dst, a, b: Rd::immediate(1) } } "dec" => { - let dst = args.next_rdwr()?; - ArithOp::Sub { - dst: dst.wr(), - a: dst.rd(), - b: Rd::immediate(1), - } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::Sub { dst, a, b: Rd::immediate(1) } } "add" => { - match args.len() { - 3 => { - ArithOp::Add { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Add { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::Add { dst, a, b } } "sub" => { - match args.len() { - 3 => { - ArithOp::Sub { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Sub { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::Sub { dst, a, b } } "mul" => { - match args.len() { - 3 => { - ArithOp::Mul { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Mul { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::Mul { dst, a, b } } "divr" => { @@ -174,403 +112,83 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP } "div" => { - match args.len() { - 3 => { - ArithOp::Div { - dst: args.next_wr()?, - rem: Wr::discard(), - a: args.next_rd()?, - div: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - let div = args.next_rd()?; - ArithOp::Div { - dst: dst.wr(), - rem: Wr::discard(), - a: dst.rd(), - div, - } - } - _ => { - return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, div) = args.parse_wr_rd_rd()?; + ArithOp::Div { dst, rem: Wr::discard(), a, div } } "mod" => { - match args.len() { - 3 => { - ArithOp::Mod { - dst: args.next_wr()?, - a: args.next_rd()?, - div: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - let div = args.next_rd()?; - ArithOp::Mod { - dst: dst.wr(), - a: dst.rd(), - div, - } - } - _ => { - return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, div) = args.parse_wr_rd_rd()?; + ArithOp::Mod { dst, a, div } } "and" => { - match args.len() { - 3 => { - ArithOp::And { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::And { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("And requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::And { dst, a, b } } "or" => { - match args.len() { - 3 => { - ArithOp::Or { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Or { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::Or { dst, a, b } } "xor" => { - match args.len() { - 3 => { - ArithOp::Xor { - dst: args.next_wr()?, - a: args.next_rd()?, - b: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Xor { - dst: dst.wr(), - a: dst.rd(), - b: args.next_rd()?, - } - } - _ => { - return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, b) = args.parse_wr_rd_rd()?; + ArithOp::Xor { dst, a, b } } "cpl" => { - match args.len() { - 2 => { - ArithOp::Cpl { - dst: args.next_wr()?, - a: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Cpl { - dst: dst.wr(), - a: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::Cpl { dst, a } } "rol" => { - match args.len() { - 3 => { - ArithOp::Rol { - dst: args.next_wr()?, - a: args.next_rd()?, - n: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Rol { - dst: dst.wr(), - a: dst.rd(), - n: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Rol { - dst: dst.wr(), - a: dst.rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; + ArithOp::Rol { dst, a, n } } "ror" => { - match args.len() { - 3 => { - ArithOp::Ror { - dst: args.next_wr()?, - a: args.next_rd()?, - n: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Ror { - dst: dst.wr(), - a: dst.rd(), - n: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Ror { - dst: dst.wr(), - a: dst.rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; + ArithOp::Ror { dst, a, n } } "lsl" | "asl" => { - match args.len() { - 3 => { - ArithOp::Lsl { - dst: args.next_wr()?, - a: args.next_rd()?, - n: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Lsl { - dst: dst.wr(), - a: dst.rd(), - n: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Lsl { - dst: dst.wr(), - a: dst.rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; + ArithOp::Lsl { dst, a, n } } "lsr" => { - match args.len() { - 3 => { - ArithOp::Lsr { - dst: args.next_wr()?, - a: args.next_rd()?, - n: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Lsr { - dst: dst.wr(), - a: dst.rd(), - n: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Lsr { - dst: dst.wr(), - a: dst.rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; + ArithOp::Lsr { dst, a, n } } "asr" => { - match args.len() { - 3 => { - ArithOp::Asr { - dst: args.next_wr()?, - a: args.next_rd()?, - n: args.next_rd()?, - } - } - 2 => { - let dst = args.next_rdwr()?; - ArithOp::Asr { - dst: dst.wr(), - a: dst.rd(), - n: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Asr { - dst: dst.wr(), - a: dst.rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into(), op_pos.clone())); - } - } + let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; + ArithOp::Asr { dst, a, n } } "sw32" => { - match args.len() { - 2 => { - ArithOp::Sw32 { - dst: args.next_wr()?, - src: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Sw32 { - dst: dst.wr(), - src: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("SW32 requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, src) = args.parse_wr_rd()?; + ArithOp::Sw32 { dst, src } } "sw16" => { - match args.len() { - 2 => { - ArithOp::Sw16 { - dst: args.next_wr()?, - src: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Sw16 { - dst: dst.wr(), - src: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("SW16 requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, src) = args.parse_wr_rd()?; + ArithOp::Sw16 { dst, src } } "sw8" => { - match args.len() { - 2 => { - ArithOp::Sw8 { - dst: args.next_wr()?, - src: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Sw8 { - dst: dst.wr(), - src: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("SW8 requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, src) = args.parse_wr_rd()?; + ArithOp::Sw8 { dst, src } } "rev" => { - match args.len() { - 2 => { - ArithOp::Rev { - dst: args.next_wr()?, - src: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Rev { - dst: dst.wr(), - src: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("REV requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, src) = args.parse_wr_rd()?; + ArithOp::Rev { dst, src } } "rbit" => { - match args.len() { - 2 => { - ArithOp::Rbit { - dst: args.next_wr()?, - src: args.next_rd()?, - } - } - 1 => { - let dst = args.next_rdwr()?; - ArithOp::Rbit { - dst: dst.wr(), - src: dst.rd(), - } - } - _ => { - return Err(CrsnError::Parse("RBIT requires 1 or 2 arguments".into(), op_pos.clone())); - } - } + let (dst, src) = args.parse_wr_rd()?; + ArithOp::Rbit { dst, src } } other => {