1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
use self::super::super::super::super::isa::instruction::ParseInstructionError; use self::super::super::super::super::util::parse_with_prefix; use self::super::super::LabelFragment; use self::super::AssemblerDirective; impl<'s> AssemblerDirective<'s> { #[cfg_attr(rustfmt, rustfmt_skip)] pub(in super::super) fn from_str_impl(s: &'s str) -> Result<Option<Self>, ParseInstructionError> { let mut tokens = s.split_whitespace().peekable(); let has_colon = tokens.peek() == Some(&":"); if has_colon { tokens.next(); } let operation = parse_directive(&mut tokens, s, has_colon)?; if operation.is_some() { if let Some(tok) = tokens.next() { return Err(ParseInstructionError::TooManyTokens((tok.as_ptr() as usize) - (s.as_ptr() as usize) + 1)); } } Ok(operation) } } fn parse_directive<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, had_colon: bool) -> Result<Option<AssemblerDirective<'i>>, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["origin", "label", "literal"]; match itr.next() { Some(mut tok) => { if !had_colon { if !tok.starts_with(':') { return Ok(None); } tok = &tok[1..]; } let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); if tok.eq_ignore_ascii_case("origin") { Ok(Some(parse_directive_origin(itr, orig_str, start_pos + 6 + 1)?)) } else if tok.eq_ignore_ascii_case("label") { Ok(Some(parse_directive_label(itr, orig_str, start_pos + 5 + 1)?)) } else if tok.eq_ignore_ascii_case("literal") { Ok(Some(parse_directive_literal(itr, orig_str, start_pos + 7 + 1)?)) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::EmptyString), } } fn parse_directive_origin<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, pos: usize) -> Result<AssemblerDirective<'i>, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["[16-bit origin address]"]; match itr.next() { Some(tok) => { let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); if let Some(origin) = parse_with_prefix::<u16>(tok) { Ok(AssemblerDirective::SetOrigin(origin)) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } } fn parse_directive_label<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, pos: usize) -> Result<AssemblerDirective<'i>, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["save", "load", "load-offset"]; match itr.next() { Some(tok) => { let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); if tok.eq_ignore_ascii_case("save") { Ok(AssemblerDirective::SaveLabel(parse_directive_label_name(itr, start_pos + 4 + 1)?)) } else if tok.eq_ignore_ascii_case("load") { let (frag, start_pos) = parse_directive_label_fragment(itr, orig_str, start_pos + 4 + 1)?; Ok(AssemblerDirective::LoadLabel(parse_directive_label_name(itr, start_pos)?, 0, frag)) } else if tok.eq_ignore_ascii_case("load-offset") { let (frag, start_pos) = parse_directive_label_fragment(itr, orig_str, start_pos + 11 + 1)?; let lbl = parse_directive_label_name(itr, start_pos)?; Ok(AssemblerDirective::LoadLabel(lbl, parse_label_offset(itr, orig_str, (lbl.as_ptr() as usize) - (orig_str.as_ptr() as usize) + lbl.len() + 1)?, frag)) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } } fn parse_directive_label_name<'i, I: Iterator<Item = &'i str>>(itr: &mut I, pos: usize) -> Result<&'i str, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["[label name]"]; match itr.next() { Some(tok) => Ok(tok), None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } } fn parse_directive_label_fragment<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, pos: usize) -> Result<(LabelFragment, usize), ParseInstructionError> { static VALID_TOKENS: &[&str] = &["full", "high", "low"]; match itr.next() { Some(tok) => { let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); if tok.eq_ignore_ascii_case("full") { Ok((LabelFragment::Full, start_pos + 4 + 1)) } else if tok.eq_ignore_ascii_case("high") { Ok((LabelFragment::High, start_pos + 4 + 1)) } else if tok.eq_ignore_ascii_case("low") { Ok((LabelFragment::Low, start_pos + 3 + 1)) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } } fn parse_label_offset<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, pos: usize) -> Result<i16, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["[signed 16-bit label offset]"]; match itr.next() { Some(mut tok) => { let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); let mut negative = false; if tok.starts_with('-') { tok = &tok[1..]; negative = true; } if let Some(offset) = parse_with_prefix::<u16>(tok) { Ok(if negative { -(offset as i16) } else { offset as i16 }) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } } fn parse_directive_literal<'i, I: Iterator<Item = &'i str>>(itr: &mut I, orig_str: &'i str, pos: usize) -> Result<AssemblerDirective<'i>, ParseInstructionError> { static VALID_TOKENS: &[&str] = &["\"[string]\""]; match itr.next() { Some(tok) => { let start_pos = (tok.as_ptr() as usize) - (orig_str.as_ptr() as usize); let lit = &orig_str[start_pos..]; if lit.starts_with('"') && lit.ends_with('"') { itr.count(); Ok(AssemblerDirective::InsertLiteral(&lit[1..lit.len() - 1])) } else { Err(ParseInstructionError::UnrecognisedToken(start_pos + 1, VALID_TOKENS)) } } None => Err(ParseInstructionError::MissingToken(pos, VALID_TOKENS)), } }