ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/
1use std::iter::Peekable; 2use std::str::Chars; 3 4pub type Error = &'static str; 5 6pub fn assemble(asm: &str) -> Result<Vec<u8>, Error> { 7 Assembler::new(asm).assemble() 8} 9 10struct Assembler<'a> { 11 iter: Peekable<Chars<'a>>, 12 output: Vec<u8>, 13} 14 15enum IntPadding { 16 NoPadding, 17 PaddedTo(usize), 18} 19 20impl<'a> Assembler<'a> { 21 fn new(buf: &'a str) -> Assembler<'a> { 22 Assembler { 23 iter: buf.chars().peekable(), 24 output: Vec::new(), 25 } 26 } 27 28 fn expect(&mut self, c: char) -> Option<()> { 29 match self.iter.next() { 30 Some(d) => { 31 if c == d { 32 Some(()) 33 } else { 34 None 35 } 36 } 37 None => None, 38 } 39 } 40 41 fn emit(&mut self, s: &str) { 42 self.output.extend_from_slice(s.as_bytes()); 43 } 44 45 fn read_to(&mut self, any_of: &str) -> Option<String> { 46 let mut s = String::new(); 47 loop { 48 if let Some(c) = self.iter.peek() 49 && any_of.contains(*c) 50 { 51 return Some(s); 52 } 53 54 match self.iter.next() { 55 Some(c) => s.push(c), 56 None => return None, 57 } 58 } 59 } 60 61 fn parse_int(s: &str) -> Option<usize> { 62 let is_hex = s.starts_with("0x"); 63 let base = if is_hex { 16 } else { 10 }; 64 let mut ret = 0; 65 let mut iter = s.chars(); 66 if is_hex { 67 // TODO: advance_by? 68 iter.nth(1); 69 } 70 71 for c in iter { 72 ret *= base; 73 ret += c.to_digit(base)?; 74 } 75 76 return Some(ret as usize); 77 } 78 79 fn encode_int(mut n: usize, p: IntPadding) -> String { 80 let mut s = String::new(); 81 while n > 0 { 82 if n % 2 == 1 { 83 s += "C"; 84 } else { 85 s += "I"; 86 } 87 88 n /= 2; 89 } 90 91 if let IntPadding::PaddedTo(p) = p { 92 for _ in s.len()..(p - 1) { 93 s += "I"; 94 } 95 } 96 97 s += "P"; 98 return s; 99 } 100 101 fn emit_consts(&mut self, s: &str) { 102 for c in s.chars() { 103 match c { 104 'I' => self.emit("C"), 105 'C' => self.emit("F"), 106 'F' => self.emit("P"), 107 'P' => self.emit("IC"), 108 _ => {} 109 } 110 } 111 } 112 113 fn assemble(mut self) -> Result<Vec<u8>, Error> { 114 loop { 115 match self.iter.next() { 116 Some('I') => self.emit("C"), 117 Some('C') => self.emit("F"), 118 Some('F') => self.emit("P"), 119 Some('P') => self.emit("IC"), 120 Some('!') => { 121 self.expect('{').ok_or("Skip followed by non-{")?; 122 let n = self.read_to("}").ok_or("Skip failed to terminate")?; 123 let n = Self::parse_int(&n).ok_or("Invalid int inside skip")?; 124 self.emit("IP"); 125 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 126 self.expect('}').ok_or("Skip failed to terminate")?; 127 } 128 Some('?') => { 129 self.expect('{').ok_or("Search followed by non-?")?; 130 let s = self.read_to("}").ok_or("Search failed to terminate")?; 131 self.emit("IFF"); 132 self.emit_consts(&s); 133 self.expect('}').ok_or("Search failed to terminate")?; 134 } 135 Some('(') => self.emit("IIP"), 136 Some(')') => self.emit("IIC"), 137 Some(';') => self.emit("IIC"), 138 Some('"') => { 139 let n = self.read_to("\",").ok_or("Reference failed terminate")?; 140 let n = Self::parse_int(&n).ok_or("Reference group index invalid")?; 141 let l = match self.iter.next() { 142 Some('"') => "0", 143 Some(',') => &self.read_to("\",").ok_or("Reference failed to terminate")?, 144 _ => return Err("Reference failed to terminate"), 145 }; 146 let l = Self::parse_int(&l).ok_or("Reference level invalid")?; 147 self.emit("IP"); 148 self.emit(&Self::encode_int(l, IntPadding::NoPadding)); 149 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 150 } 151 Some('|') => { 152 let n = self.read_to("|").ok_or("Length failed to terminate")?; 153 let n = Self::parse_int(&n).ok_or("Length group index invalid")?; 154 self.emit("IIP"); 155 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 156 } 157 Some('n') => { 158 self.expect('{'); 159 let n = self 160 .read_to("},") 161 .ok_or("Int constant failed to terminate")?; 162 let n = Self::parse_int(&n).ok_or("Int constant invalid")?; 163 match self.iter.next() { 164 Some('}') => { 165 self.emit(&Self::encode_int(n, IntPadding::NoPadding)); 166 } 167 Some(',') => { 168 let pad = self 169 .read_to("}") 170 .ok_or("Int constant failed to terminate")?; 171 let pad = 172 Self::parse_int(&pad).ok_or("Int constant padding invalid")?; 173 self.emit_consts(&Self::encode_int(n, IntPadding::PaddedTo(pad))); 174 self.expect('}').ok_or("Int constant failed to terminate")?; 175 } 176 _ => return Err("Int constant failed to terminate"), 177 }; 178 } 179 Some(' ') | Some('\n') => {} 180 None => return Ok(self.output), 181 Some(c) => { 182 println!("{}", c); 183 return Err("Invalid character"); 184 } 185 } 186 } 187 } 188} 189 190// TODO: Tests