+ Token::I8 => put_integers::<u8, 1>(lexer, "i8", output)?,
+ Token::I16 => put_integers::<u16, 2>(lexer, "i16", output)?,
+ Token::I64 => put_integers::<i64, 8>(lexer, "i64", output)?,
+ Token::String(string) => output.extend_from_slice(string.as_bytes()),
+ Token::S(size) => {
+ let Some(Token::String(ref string)) = lexer.token else {
+ return Err(anyhow!("string expected after 's{size}'"));
+ };
+ let len = string.len();
+ if len > size {
+ return Err(anyhow!(
+ "{len}-byte string is longer than pad length {size}"
+ ));
+ }
+ output.extend_from_slice(string.as_bytes());
+ output.extend(repeat(b' ').take(size - len));
+ lexer.get()?;
+ }
+ Token::LParen => {
+ while lexer.token != Some(Token::RParen) {
+ parse_data_item(lexer, output, symbol_table)?;
+ }
+ lexer.get()?;
+ }
+ Token::Count => put_counted_items::<u32, 4>(lexer, "COUNT", output, symbol_table)?,
+ Token::Count8 => put_counted_items::<u8, 1>(lexer, "COUNT8", output, symbol_table)?,
+ Token::Hex => {
+ let Some(Token::String(ref string)) = lexer.token else {
+ return Err(anyhow!("string expected after 'hex'"));
+ };
+ let mut i = string.chars();
+ loop {
+ let Some(c0) = i.next() else { return Ok(true) };
+ let Some(c1) = i.next() else {
+ return Err(anyhow!("hex string has odd number of characters"));
+ };
+ let (Some(digit0), Some(digit1)) = (c0.to_digit(16), c1.to_digit(16)) else {
+ return Err(anyhow!("invalid digit in hex string"));
+ };
+ let byte = digit0 * 16 + digit1;
+ output.push(byte as u8);
+ }
+ }
+ Token::Label(name) => {
+ let value = output.len() as u32;
+ match symbol_table.entry(name) {
+ Entry::Vacant(v) => {
+ v.insert(Some(value));
+ }
+ Entry::Occupied(o) => {
+ if let Some(v) = o.get() {
+ if *v != value {
+ return Err(anyhow!("syntax error"));
+ }
+ }
+ }
+ };
+ }
+ Token::At(name) => {
+ let mut value = symbol_table.entry(name).or_insert(None).unwrap_or(0);
+ lexer.get()?;
+ loop {
+ let plus = match lexer.token {
+ Some(Token::Plus) => true,
+ Some(Token::Minus) => false,
+ _ => break,
+ };
+ lexer.get()?;
+
+ let operand = match lexer.token {
+ Some(Token::At(ref name)) => if let Some(value) = symbol_table.get(name) {
+ *value
+ } else {
+ symbol_table.insert(name.clone(), None);
+ None
+ }
+ .unwrap_or(0),
+ Some(Token::Integer(integer)) => integer
+ .try_into()
+ .map_err(|msg| anyhow!("bad offset literal ({msg})"))?,
+ _ => return Err(anyhow!("expecting @label or integer literal")),
+ };
+ lexer.get()?;
+
+ value = if plus {
+ value.checked_add(operand)
+ } else {
+ value.checked_sub(operand)
+ }
+ .ok_or_else(|| anyhow!("overflow in offset arithmetic"))?;
+ }
+ output.extend_from_slice(&lexer.endian.to_bytes(value));
+ }
+ _ => (),
+ };
+ if lexer.token == Some(Token::Asterisk) {
+ lexer.get()?;
+ let Token::Integer(count) = lexer.take()? else {
+ return Err(anyhow!("positive integer expected after '*'"));
+ };
+ if count < 1 {
+ return Err(anyhow!("positive integer expected after '*'"));
+ };
+ let final_len = output.len();
+ for _ in 1..count {
+ output.extend_from_within(initial_len..final_len);
+ }
+ }
+ match lexer.token {
+ Some(Token::Semicolon) => {
+ lexer.get()?;
+ }
+ Some(Token::RParen) => (),
+ _ => return Err(anyhow!("';' expected")),