/src/regalloc.rs/bin/parser.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #![allow(unused_imports)] |
2 | | |
3 | | use std::collections::HashMap; |
4 | | use std::fs::File; |
5 | | use std::io; |
6 | | use std::io::prelude::*; |
7 | | use std::iter::Peekable; |
8 | | use std::path::{Path, PathBuf}; |
9 | | use std::str; |
10 | | use std::str::CharIndices; |
11 | | |
12 | | use regalloc::{Reg, RegClass}; |
13 | | |
14 | | use crate::test_framework::*; |
15 | | |
16 | | pub(crate) const REFTYPE_START: &'static str = "reftype_start"; |
17 | | |
18 | | #[derive(Debug)] |
19 | | pub enum ParseError { |
20 | | IoError(io::Error), |
21 | | Parse(String), |
22 | | } |
23 | | |
24 | | impl From<io::Error> for ParseError { |
25 | | fn from(err: io::Error) -> ParseError { |
26 | | ParseError::IoError(err) |
27 | | } |
28 | | } |
29 | | |
30 | | pub type ParseResult<T> = Result<T, ParseError>; |
31 | | |
32 | 0 | pub fn parse_file(path: PathBuf) -> ParseResult<Func> { |
33 | 0 | let basename = path.file_stem().unwrap().to_str().unwrap().to_string(); |
34 | 0 | let mut file = File::open(path)?; |
35 | 0 | let mut content = String::new(); |
36 | 0 | file.read_to_string(&mut content)?; |
37 | 0 | parse_content(&basename, &content) |
38 | 0 | } |
39 | | |
40 | | struct Parser<'f, 'str> { |
41 | | func: &'f mut Func, |
42 | | vars: HashMap<String, Reg>, |
43 | | |
44 | | source: &'str str, |
45 | | iter: Peekable<CharIndices<'str>>, |
46 | | line: usize, |
47 | | start: usize, |
48 | | current: usize, |
49 | | } |
50 | | |
51 | | impl<'f, 'str> Parser<'f, 'str> { |
52 | | fn new(func: &'f mut Func, source: &'str str) -> Self { |
53 | | let iter = source.char_indices().peekable(); |
54 | | Self { |
55 | | func, |
56 | | start: 0, |
57 | | current: 0, |
58 | | line: 1, |
59 | | vars: HashMap::new(), |
60 | | iter, |
61 | | source, |
62 | | } |
63 | | } |
64 | | |
65 | | // Environment. |
66 | 0 | fn define_virtual_var(&mut self, name: &str, reg_class: RegClass) -> ParseResult<()> { |
67 | 0 | if let Some(_) = self |
68 | 0 | .vars |
69 | 0 | .insert(name.into(), self.func.new_virtual_reg(reg_class)) |
70 | | { |
71 | 0 | self.error("duplicate variable declaration") |
72 | | } else { |
73 | 0 | Ok(()) |
74 | | } |
75 | 0 | } |
76 | | |
77 | 0 | fn define_real_var(&mut self, name: &str, reg_class: RegClass, index: u8) -> ParseResult<()> { |
78 | 0 | if let Some(_) = self |
79 | 0 | .vars |
80 | 0 | .insert(name.into(), Reg::new_real(reg_class, 0x0, index)) |
81 | | { |
82 | 0 | self.error("duplicate variable declaration") |
83 | | } else { |
84 | 0 | Ok(()) |
85 | | } |
86 | 0 | } |
87 | | |
88 | | fn var(&mut self, name: &str) -> Option<Reg> { |
89 | | self.vars.get(name).cloned() |
90 | | } |
91 | | |
92 | | fn define_block(&mut self, block_name: String, insts: Vec<Inst>) { |
93 | | self.func.block(&block_name, insts); |
94 | | } |
95 | | |
96 | | // Parsing. |
97 | | fn peek(&mut self) -> Option<char> { |
98 | 0 | if let Some((_, c)) = self.iter.peek() { |
99 | 0 | Some(*c) |
100 | | } else { |
101 | 0 | None |
102 | | } |
103 | 0 | } |
104 | | |
105 | 0 | fn peek_next(&self) -> Option<char> { |
106 | 0 | let mut clone = self.iter.clone(); |
107 | 0 | if let Some(_) = clone.next() { |
108 | 0 | if let Some((_, c)) = clone.peek() { |
109 | 0 | return Some(*c); |
110 | 0 | } |
111 | 0 | } |
112 | 0 | None |
113 | 0 | } |
114 | | |
115 | | fn advance(&mut self) -> Option<char> { |
116 | 0 | if let Some((i, ch)) = self.iter.next() { |
117 | 0 | self.current = i; |
118 | 0 | Some(ch) |
119 | | } else { |
120 | 0 | None |
121 | | } |
122 | 0 | } |
123 | | |
124 | | // Higher level parsing. |
125 | | fn skip_whitespace_and_comments(&mut self) { |
126 | 0 | while let Some(c) = self.peek() { |
127 | 0 | if c == ' ' || c == '\t' || c == '\r' || c == '\n' { |
128 | | // Skip whitespace. |
129 | 0 | self.advance().unwrap(); |
130 | 0 | if c == '\n' { |
131 | 0 | self.line += 1; |
132 | 0 | } |
133 | 0 | } else if c == ';' { |
134 | | // It's a comment! skip until the end of line. |
135 | 0 | self.advance().unwrap(); |
136 | 0 | while let Some(c) = self.advance() { |
137 | 0 | if c == '\n' { |
138 | 0 | self.line += 1; |
139 | 0 | break; |
140 | 0 | } |
141 | | } |
142 | | } else { |
143 | 0 | break; |
144 | | } |
145 | | } |
146 | 0 | } |
147 | | |
148 | 0 | fn read_char(&mut self) -> ParseResult<char> { |
149 | 0 | self.skip_whitespace_and_comments(); |
150 | 0 | if let Some(c) = self.advance() { |
151 | 0 | Ok(c) |
152 | | } else { |
153 | 0 | self.error("expected char") |
154 | | } |
155 | 0 | } |
156 | | |
157 | 0 | fn try_read_char(&mut self, expected: char) -> Option<char> { |
158 | 0 | self.skip_whitespace_and_comments(); |
159 | 0 | if let Some(c) = self.peek() { |
160 | 0 | if c == expected { |
161 | 0 | self.advance().unwrap(); |
162 | 0 | return Some(c); |
163 | 0 | } |
164 | 0 | } |
165 | 0 | None |
166 | 0 | } |
167 | | |
168 | 0 | fn try_read_ident_sameline(&mut self) -> Option<String> { |
169 | | // Only ignore simple spaces. |
170 | 0 | while let Some(c) = self.peek() { |
171 | 0 | if c == ' ' { |
172 | 0 | self.advance().unwrap(); |
173 | 0 | } else { |
174 | 0 | break; |
175 | | } |
176 | | } |
177 | | |
178 | 0 | if let Some(c) = self.peek() { |
179 | 0 | if !is_alpha(c) { |
180 | 0 | return None; |
181 | 0 | } |
182 | 0 | self.advance().unwrap(); |
183 | | } else { |
184 | 0 | return None; |
185 | | } |
186 | | |
187 | 0 | self.start = self.current; |
188 | 0 | while let Some(c) = self.peek() { |
189 | 0 | if !is_alpha_numeric(c) { |
190 | 0 | break; |
191 | 0 | } |
192 | 0 | self.advance().unwrap(); |
193 | | } |
194 | | |
195 | 0 | let substr = str::from_utf8(&self.source.as_bytes()[self.start..self.current + 1]).unwrap(); |
196 | 0 | Some(substr.to_string()) |
197 | 0 | } |
198 | | |
199 | | fn try_read_ident(&mut self) -> Option<String> { |
200 | | self.skip_whitespace_and_comments(); |
201 | | self.try_read_ident_sameline() |
202 | | } |
203 | | |
204 | | fn read_ident(&mut self) -> ParseResult<String> { |
205 | 0 | if let Some(string) = self.try_read_ident() { |
206 | 0 | Ok(string) |
207 | | } else { |
208 | 0 | self.error("expected identifier or keyword") |
209 | | } |
210 | 0 | } |
211 | | |
212 | 0 | fn read_block(&mut self) -> ParseResult<String> { |
213 | 0 | let block_name = self.read_ident()?; |
214 | 0 | if let Some(':') = self.peek() { |
215 | 0 | self.advance().unwrap(); |
216 | | // Ignore the block's name. |
217 | 0 | self.read_ident()?; |
218 | 0 | } |
219 | 0 | Ok(block_name) |
220 | 0 | } |
221 | | |
222 | 0 | fn read_string(&mut self) -> ParseResult<&str> { |
223 | 0 | self.skip_whitespace_and_comments(); |
224 | 0 | if let Some('"') = self.advance() { |
225 | 0 | // All good! |
226 | 0 | } else { |
227 | 0 | return self.error("expected opening \""); |
228 | | } |
229 | 0 | self.start = self.current; |
230 | 0 | while let Some(c) = self.peek() { |
231 | 0 | if c == '\n' { |
232 | 0 | self.line += 1; |
233 | 0 | } |
234 | 0 | self.advance().unwrap(); |
235 | 0 | if c == '"' { |
236 | 0 | let substr = |
237 | 0 | str::from_utf8(&self.source.as_bytes()[self.start + 1..self.current]).unwrap(); |
238 | 0 | return Ok(substr); |
239 | 0 | } |
240 | | } |
241 | 0 | self.error("unterminated string") |
242 | 0 | } |
243 | | |
244 | 0 | fn try_read_number(&mut self) -> ParseResult<Option<f64>> { |
245 | 0 | self.skip_whitespace_and_comments(); |
246 | 0 |
|
247 | 0 | let mut is_negative = false; |
248 | 0 | if let Some('-') = self.peek() { |
249 | 0 | // Consume the minus sign. |
250 | 0 | self.advance().unwrap(); |
251 | 0 | is_negative = true; |
252 | 0 | } |
253 | | |
254 | 0 | let first_digit = if let Some(c) = self.peek() { |
255 | | // A regular number. |
256 | 0 | if is_digit(c) { |
257 | 0 | self.advance().unwrap(); |
258 | 0 | c |
259 | 0 | } else if c == 'i' { |
260 | 0 | self.advance().unwrap(); |
261 | | // This must be inf. |
262 | 0 | self.expect_char('n')?; |
263 | 0 | self.expect_char('f')?; |
264 | 0 | let mut result = std::f64::INFINITY; |
265 | 0 | if is_negative { |
266 | 0 | result = -result; |
267 | 0 | } |
268 | 0 | return Ok(Some(result)); |
269 | 0 | } else if c == 'N' { |
270 | | // This must be NaN. |
271 | 0 | self.advance().unwrap(); |
272 | 0 | self.expect_char('a')?; |
273 | 0 | self.expect_char('N')?; |
274 | 0 | let mut result = std::f64::NAN; |
275 | 0 | if is_negative { |
276 | 0 | result = -result; |
277 | 0 | } |
278 | 0 | return Ok(Some(result)); |
279 | 0 | } else if is_negative { |
280 | | // We saw a minus sign, we should have had something after it. |
281 | 0 | return self.error("expected a valid number after minus sign"); |
282 | | } else { |
283 | 0 | return Ok(None); |
284 | | } |
285 | 0 | } else if is_negative { |
286 | | // We saw a minus sign, we should have had something after it. |
287 | 0 | return self.error("expected something after minus sign"); |
288 | | } else { |
289 | 0 | return Ok(None); |
290 | | }; |
291 | | |
292 | 0 | let mut number = first_digit.to_digit(10).unwrap() as f64; |
293 | 0 | let mut fractional_power_of_ten: Option<f64> = None; |
294 | 0 | while let Some(c) = self.peek() { |
295 | 0 | if is_digit(c) { |
296 | 0 | self.advance().unwrap(); |
297 | 0 | let c_num = c.to_digit(10).unwrap() as f64; |
298 | 0 | if let Some(decimal) = fractional_power_of_ten.as_mut() { |
299 | 0 | number += c_num * *decimal; |
300 | 0 | *decimal /= 10.0; |
301 | 0 | } else { |
302 | 0 | number *= 10.0; |
303 | 0 | number += c_num; |
304 | 0 | } |
305 | 0 | } else if c == '.' { |
306 | 0 | if let Some(d) = self.peek_next() { |
307 | 0 | if is_digit(d) { |
308 | 0 | self.advance().unwrap(); |
309 | 0 | if fractional_power_of_ten.is_some() { |
310 | 0 | return self.error("unexpected dot in number")?; |
311 | 0 | } |
312 | 0 | fractional_power_of_ten = Some(0.1); |
313 | | continue; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | break; |
317 | | } else { |
318 | 0 | break; |
319 | | } |
320 | | } |
321 | | |
322 | 0 | if is_negative { |
323 | 0 | number = -number; |
324 | 0 | } |
325 | | |
326 | 0 | Ok(Some(number)) |
327 | 0 | } |
328 | 0 | fn read_number(&mut self) -> ParseResult<f64> { |
329 | 0 | Ok(self.try_read_number()?.expect("expected number")) |
330 | 0 | } |
331 | | |
332 | 0 | fn try_read_int(&mut self) -> ParseResult<Option<u32>> { |
333 | 0 | if let Some(value) = self.try_read_number()? { |
334 | 0 | let as_int = value as u32; |
335 | 0 | let as_float_back = as_int as f64; |
336 | 0 | if as_float_back != value { |
337 | 0 | self.error("expected an integer, got a double") |
338 | | } else { |
339 | 0 | Ok(Some(as_int)) |
340 | | } |
341 | | } else { |
342 | 0 | Ok(None) |
343 | | } |
344 | 0 | } |
345 | 0 | fn read_int(&mut self) -> ParseResult<u32> { |
346 | 0 | Ok(self.try_read_int()?.expect("expected integer")) |
347 | 0 | } |
348 | | |
349 | | fn try_read_var(&mut self) -> ParseResult<Option<Reg>> { |
350 | 0 | if let Some(ident) = self.try_read_ident() { |
351 | 0 | if let Some(reg) = self.vars.get(&ident) { |
352 | 0 | Ok(Some(*reg)) |
353 | | } else { |
354 | 0 | self.error("expected variable") |
355 | | } |
356 | | } else { |
357 | 0 | Ok(None) |
358 | | } |
359 | 0 | } |
360 | 0 | fn read_var(&mut self) -> ParseResult<Reg> { |
361 | 0 | Ok(self.try_read_var()?.expect("expected var")) |
362 | 0 | } |
363 | | |
364 | 0 | fn to_reg_class(&self, ident: &str) -> ParseResult<RegClass> { |
365 | 0 | if ident == "i32" || ident == "I32" { |
366 | 0 | Ok(RegClass::I32) |
367 | 0 | } else if ident == "f32" || ident == "F32" { |
368 | 0 | Ok(RegClass::F32) |
369 | | } else { |
370 | 0 | self.error("unknown register class") |
371 | | } |
372 | 0 | } |
373 | | |
374 | 0 | fn read_ri(&mut self) -> ParseResult<RI> { |
375 | 0 | if let Some(reg) = self.try_read_var()? { |
376 | 0 | Ok(RI_R(reg)) |
377 | | } else { |
378 | 0 | let int = self.read_int()?; |
379 | 0 | Ok(RI_I(int)) |
380 | | } |
381 | 0 | } |
382 | | |
383 | | fn read_am(&mut self) -> ParseResult<AM> { |
384 | | // Either RR or RI. As a shortcut, allow R, meaning RI with 0 offset. |
385 | 0 | self.expect_char('[')?; |
386 | 0 | let base = self.read_var()?; |
387 | 0 | let am = if let Some(_) = self.try_read_char(',') { |
388 | 0 | if let Some(disp) = self.try_read_var()? { |
389 | 0 | AM_RR(base, disp) |
390 | | } else { |
391 | 0 | let offset = self.read_int()?; |
392 | 0 | AM_RI(base, offset) |
393 | | } |
394 | | } else { |
395 | 0 | AM_R(base) |
396 | | }; |
397 | 0 | self.expect_char(']')?; |
398 | 0 | Ok(am) |
399 | 0 | } |
400 | | |
401 | 0 | fn expect_char(&mut self, expected: char) -> ParseResult<()> { |
402 | 0 | let c = self.read_char()?; |
403 | 0 | if c != expected { |
404 | 0 | self.error(&format!("expected char '{}'", expected)) |
405 | | } else { |
406 | 0 | Ok(()) |
407 | | } |
408 | 0 | } |
409 | | |
410 | | fn is_done(&mut self) -> bool { |
411 | | self.skip_whitespace_and_comments(); |
412 | | self.peek().is_none() |
413 | | } |
414 | | |
415 | | fn error<T>(&self, msg: &str) -> ParseResult<T> { |
416 | | Err(ParseError::Parse(format!( |
417 | | "error at line {}: {}", |
418 | | self.line, msg |
419 | | ))) |
420 | | } |
421 | | } |
422 | | |
423 | 0 | pub fn parse_content(func_name: &str, content: &str) -> ParseResult<Func> { |
424 | 0 | let mut func = Func::new(func_name); |
425 | 0 |
|
426 | 0 | let mut parser = Parser::new(&mut func, content); |
427 | | |
428 | | // Look for variable declarations. |
429 | | let mut name; |
430 | | loop { |
431 | 0 | name = parser.read_ident()?; |
432 | 0 | let c = parser.read_char()?; |
433 | 0 | if &name == REFTYPE_START && c == '=' { |
434 | 0 | let index = parser.read_int()?; |
435 | 0 | parser.func.reftype_reg_start = Some(index); |
436 | 0 | } else if c == '=' { |
437 | | // variable declaration. |
438 | 0 | let real_or_class = parser.read_ident()?; |
439 | 0 | if real_or_class == "real" { |
440 | 0 | let class = parser.read_ident()?; |
441 | 0 | let reg_class = parser.to_reg_class(&class)?; |
442 | 0 | let index = parser.read_int()?; |
443 | 0 | if index > 255 { |
444 | 0 | return parser.error("expected u8"); |
445 | 0 | } |
446 | 0 | parser.define_real_var(&name, reg_class, index as u8)?; |
447 | | } else { |
448 | 0 | let reg_class = parser.to_reg_class(&real_or_class)?; |
449 | 0 | parser.define_virtual_var(&name, reg_class)?; |
450 | | } |
451 | 0 | } else if c == ':' { |
452 | | // first block declaration! |
453 | 0 | break; |
454 | | } else { |
455 | 0 | return parser.error("expected = or :"); |
456 | | } |
457 | | } |
458 | | |
459 | 0 | parser.func.set_entry(&name); |
460 | 0 | let mut next_block_name = Some(name); |
461 | | |
462 | | // Look for blocks (name already contains the name of the first block). |
463 | 0 | loop { |
464 | 0 | let mut insts = Vec::new(); |
465 | 0 | let block_name = next_block_name; |
466 | | |
467 | | // Look for instructions. |
468 | 0 | loop { |
469 | 0 | // Either: |
470 | 0 | // - nothing (empty block, no more blocks thereafter). |
471 | 0 | // - instruction (name, maybe operands). |
472 | 0 | // - next block. |
473 | 0 | if parser.is_done() { |
474 | 0 | next_block_name = None; |
475 | 0 | break; |
476 | 0 | } |
477 | | |
478 | 0 | let inst_or_block_name = parser.read_ident()?; |
479 | 0 | match inst_or_block_name.as_str() { |
480 | 0 | "add" => { |
481 | 0 | let dst = parser.read_var()?; |
482 | 0 | parser.expect_char(',')?; |
483 | 0 | let src = parser.read_var()?; |
484 | 0 | parser.expect_char(',')?; |
485 | 0 | let op = parser.read_ri()?; |
486 | 0 | insts.push(i_add(dst, src, op)); |
487 | | } |
488 | | |
489 | 0 | "addm" => { |
490 | 0 | let dst = parser.read_var()?; |
491 | 0 | parser.expect_char(',')?; |
492 | 0 | let src = parser.read_ri()?; |
493 | 0 | insts.push(i_addm(dst, src)); |
494 | | } |
495 | | |
496 | 0 | "and" => { |
497 | 0 | let dst = parser.read_var()?; |
498 | 0 | parser.expect_char(',')?; |
499 | 0 | let src = parser.read_var()?; |
500 | 0 | parser.expect_char(',')?; |
501 | 0 | let op = parser.read_ri()?; |
502 | 0 | insts.push(i_and(dst, src, op)); |
503 | | } |
504 | | |
505 | 0 | "andm" => { |
506 | 0 | let dst = parser.read_var()?; |
507 | 0 | parser.expect_char(',')?; |
508 | 0 | let src = parser.read_ri()?; |
509 | 0 | insts.push(i_andm(dst, src)); |
510 | | } |
511 | | |
512 | 0 | "copy" => { |
513 | 0 | let dst = parser.read_var()?; |
514 | 0 | parser.expect_char(',')?; |
515 | 0 | let src = parser.read_var()?; |
516 | 0 | insts.push(i_copy(dst, src)); |
517 | | } |
518 | | |
519 | 0 | "copyf" => { |
520 | 0 | let dst = parser.read_var()?; |
521 | 0 | parser.expect_char(',')?; |
522 | 0 | let src = parser.read_var()?; |
523 | 0 | insts.push(i_copyf(dst, src)); |
524 | | } |
525 | | |
526 | 0 | "cmp_eq" => { |
527 | 0 | let dst = parser.read_var()?; |
528 | 0 | parser.expect_char(',')?; |
529 | 0 | let src = parser.read_var()?; |
530 | 0 | parser.expect_char(',')?; |
531 | 0 | let ri = parser.read_ri()?; |
532 | 0 | insts.push(i_cmp_eq(dst, src, ri)); |
533 | | } |
534 | | |
535 | 0 | "cmp_eqm" => { |
536 | 0 | let dst = parser.read_var()?; |
537 | 0 | parser.expect_char(',')?; |
538 | 0 | let ri = parser.read_ri()?; |
539 | 0 | insts.push(i_cmp_eqm(dst, ri)); |
540 | | } |
541 | | |
542 | 0 | "cmp_gem" => { |
543 | 0 | let dst = parser.read_var()?; |
544 | 0 | parser.expect_char(',')?; |
545 | 0 | let ri = parser.read_ri()?; |
546 | 0 | insts.push(i_cmp_gem(dst, ri)); |
547 | | } |
548 | | |
549 | 0 | "cmp_gtm" => { |
550 | 0 | let dst = parser.read_var()?; |
551 | 0 | parser.expect_char(',')?; |
552 | 0 | let ri = parser.read_ri()?; |
553 | 0 | insts.push(i_cmp_gtm(dst, ri)); |
554 | | } |
555 | | |
556 | 0 | "cmp_ge" => { |
557 | 0 | let dst = parser.read_var()?; |
558 | 0 | parser.expect_char(',')?; |
559 | 0 | let src = parser.read_var()?; |
560 | 0 | parser.expect_char(',')?; |
561 | 0 | let ri = parser.read_ri()?; |
562 | 0 | insts.push(i_cmp_ge(dst, src, ri)); |
563 | | } |
564 | | |
565 | 0 | "cmp_gt" => { |
566 | 0 | let dst = parser.read_var()?; |
567 | 0 | parser.expect_char(',')?; |
568 | 0 | let src = parser.read_var()?; |
569 | 0 | parser.expect_char(',')?; |
570 | 0 | let ri = parser.read_ri()?; |
571 | 0 | insts.push(i_cmp_gt(dst, src, ri)); |
572 | | } |
573 | | |
574 | 0 | "cmp_lem" => { |
575 | 0 | let dst = parser.read_var()?; |
576 | 0 | parser.expect_char(',')?; |
577 | 0 | let ri = parser.read_ri()?; |
578 | 0 | insts.push(i_cmp_lem(dst, ri)); |
579 | | } |
580 | | |
581 | 0 | "cmp_ltm" => { |
582 | 0 | let dst = parser.read_var()?; |
583 | 0 | parser.expect_char(',')?; |
584 | 0 | let ri = parser.read_ri()?; |
585 | 0 | insts.push(i_cmp_ltm(dst, ri)); |
586 | | } |
587 | | |
588 | 0 | "cmp_le" => { |
589 | 0 | let dst = parser.read_var()?; |
590 | 0 | parser.expect_char(',')?; |
591 | 0 | let src = parser.read_var()?; |
592 | 0 | parser.expect_char(',')?; |
593 | 0 | let ri = parser.read_ri()?; |
594 | 0 | insts.push(i_cmp_le(dst, src, ri)); |
595 | | } |
596 | | |
597 | 0 | "cmp_lt" => { |
598 | 0 | let dst = parser.read_var()?; |
599 | 0 | parser.expect_char(',')?; |
600 | 0 | let src = parser.read_var()?; |
601 | 0 | parser.expect_char(',')?; |
602 | 0 | let ri = parser.read_ri()?; |
603 | 0 | insts.push(i_cmp_lt(dst, src, ri)); |
604 | | } |
605 | | |
606 | 0 | "fadd" => { |
607 | 0 | let dst = parser.read_var()?; |
608 | 0 | parser.expect_char(',')?; |
609 | 0 | let src_left = parser.read_var()?; |
610 | 0 | parser.expect_char(',')?; |
611 | 0 | let src_right = parser.read_var()?; |
612 | 0 | insts.push(i_fadd(dst, src_left, src_right)); |
613 | | } |
614 | | |
615 | 0 | "fdiv" => { |
616 | 0 | let dst = parser.read_var()?; |
617 | 0 | parser.expect_char(',')?; |
618 | 0 | let src_left = parser.read_var()?; |
619 | 0 | parser.expect_char(',')?; |
620 | 0 | let src_right = parser.read_var()?; |
621 | 0 | insts.push(i_fdiv(dst, src_left, src_right)); |
622 | | } |
623 | | |
624 | 0 | "fmul" => { |
625 | 0 | let dst = parser.read_var()?; |
626 | 0 | parser.expect_char(',')?; |
627 | 0 | let src_left = parser.read_var()?; |
628 | 0 | parser.expect_char(',')?; |
629 | 0 | let src_right = parser.read_var()?; |
630 | 0 | insts.push(i_fmul(dst, src_left, src_right)); |
631 | | } |
632 | | |
633 | 0 | "fsub" => { |
634 | 0 | let dst = parser.read_var()?; |
635 | 0 | parser.expect_char(',')?; |
636 | 0 | let src_left = parser.read_var()?; |
637 | 0 | parser.expect_char(',')?; |
638 | 0 | let src_right = parser.read_var()?; |
639 | 0 | insts.push(i_fsub(dst, src_left, src_right)); |
640 | | } |
641 | | |
642 | 0 | "finish" => { |
643 | 0 | let return_val = parser |
644 | 0 | .try_read_ident_sameline() |
645 | 0 | .and_then(|var_name| parser.var(&var_name)); |
646 | 0 | insts.push(i_finish(return_val)); |
647 | 0 | } |
648 | | |
649 | 0 | "goto" => { |
650 | 0 | let target = parser.read_block()?; |
651 | 0 | insts.push(i_goto(&target)); |
652 | | } |
653 | | |
654 | 0 | "if_then_else" => { |
655 | 0 | let test_var = parser.read_var()?; |
656 | 0 | parser.expect_char(',')?; |
657 | 0 | let then_block = parser.read_block()?; |
658 | 0 | parser.expect_char(',')?; |
659 | 0 | let else_block = parser.read_block()?; |
660 | 0 | insts.push(i_goto_ctf(test_var, &then_block, &else_block)); |
661 | | } |
662 | | |
663 | 0 | "imm" => { |
664 | 0 | let dst = parser.read_var()?; |
665 | 0 | parser.expect_char(',')?; |
666 | 0 | let value = parser.read_int()?; |
667 | 0 | insts.push(i_imm(dst, value)); |
668 | | } |
669 | | |
670 | 0 | "immf" => { |
671 | 0 | let dst = parser.read_var()?; |
672 | 0 | parser.expect_char(',')?; |
673 | 0 | let value = parser.read_number()?; |
674 | 0 | insts.push(i_immf(dst, value as f32)); |
675 | | } |
676 | | |
677 | 0 | "load" => { |
678 | 0 | let dst = parser.read_var()?; |
679 | 0 | parser.expect_char(',')?; |
680 | 0 | let addr = parser.read_am()?; |
681 | 0 | insts.push(i_load(dst, addr)); |
682 | | } |
683 | | |
684 | 0 | "loadf" => { |
685 | 0 | let dst = parser.read_var()?; |
686 | 0 | parser.expect_char(',')?; |
687 | 0 | let addr = parser.read_am()?; |
688 | 0 | insts.push(i_loadf(dst, addr)); |
689 | | } |
690 | | |
691 | 0 | "mod" => { |
692 | 0 | let dst = parser.read_var()?; |
693 | 0 | parser.expect_char(',')?; |
694 | 0 | let src_left = parser.read_var()?; |
695 | 0 | parser.expect_char(',')?; |
696 | 0 | let src_right = parser.read_ri()?; |
697 | 0 | insts.push(i_mod(dst, src_left, src_right)); |
698 | | } |
699 | | |
700 | 0 | "modm" => { |
701 | 0 | let dst = parser.read_var()?; |
702 | 0 | parser.expect_char(',')?; |
703 | 0 | let src_right = parser.read_ri()?; |
704 | 0 | insts.push(i_modm(dst, src_right)); |
705 | | } |
706 | | |
707 | 0 | "mul" => { |
708 | 0 | let dst = parser.read_var()?; |
709 | 0 | parser.expect_char(',')?; |
710 | 0 | let src_left = parser.read_var()?; |
711 | 0 | parser.expect_char(',')?; |
712 | 0 | let src_right = parser.read_ri()?; |
713 | 0 | insts.push(i_mul(dst, src_left, src_right)); |
714 | | } |
715 | | |
716 | 0 | "mulm" => { |
717 | 0 | let dst = parser.read_var()?; |
718 | 0 | parser.expect_char(',')?; |
719 | 0 | let src_right = parser.read_ri()?; |
720 | 0 | insts.push(i_mulm(dst, src_right)); |
721 | | } |
722 | | |
723 | 0 | "shr" => { |
724 | 0 | let dst = parser.read_var()?; |
725 | 0 | parser.expect_char(',')?; |
726 | 0 | let src_left = parser.read_var()?; |
727 | 0 | parser.expect_char(',')?; |
728 | 0 | let src_right = parser.read_ri()?; |
729 | 0 | insts.push(i_shr(dst, src_left, src_right)); |
730 | | } |
731 | | |
732 | 0 | "shrm" => { |
733 | 0 | let dst = parser.read_var()?; |
734 | 0 | parser.expect_char(',')?; |
735 | 0 | let src_right = parser.read_ri()?; |
736 | 0 | insts.push(i_shrm(dst, src_right)); |
737 | | } |
738 | | |
739 | 0 | "store" => { |
740 | 0 | let addr = parser.read_am()?; |
741 | 0 | parser.expect_char(',')?; |
742 | 0 | let src = parser.read_var()?; |
743 | 0 | insts.push(i_store(addr, src)); |
744 | | } |
745 | | |
746 | 0 | "storef" => { |
747 | 0 | let addr = parser.read_am()?; |
748 | 0 | parser.expect_char(',')?; |
749 | 0 | let src = parser.read_var()?; |
750 | 0 | insts.push(i_storef(addr, src)); |
751 | | } |
752 | | |
753 | 0 | "makeref" => { |
754 | 0 | let dst = parser.read_var()?; |
755 | 0 | parser.expect_char(',')?; |
756 | 0 | let src = parser.read_var()?; |
757 | 0 | insts.push(Inst::MakeRef { dst, src }); |
758 | | } |
759 | | |
760 | 0 | "useref" => { |
761 | 0 | let dst = parser.read_var()?; |
762 | 0 | parser.expect_char(',')?; |
763 | 0 | let src = parser.read_var()?; |
764 | 0 | insts.push(Inst::UseRef { dst, src }); |
765 | | } |
766 | | |
767 | 0 | "safepoint" => { |
768 | 0 | insts.push(Inst::Safepoint); |
769 | 0 | } |
770 | | |
771 | 0 | "sub" => { |
772 | 0 | let dst = parser.read_var()?; |
773 | 0 | parser.expect_char(',')?; |
774 | 0 | let src_left = parser.read_var()?; |
775 | 0 | parser.expect_char(',')?; |
776 | 0 | let src_right = parser.read_ri()?; |
777 | 0 | insts.push(i_sub(dst, src_left, src_right)); |
778 | | } |
779 | | |
780 | 0 | "subm" => { |
781 | 0 | let dst = parser.read_var()?; |
782 | 0 | parser.expect_char(',')?; |
783 | 0 | let src_right = parser.read_ri()?; |
784 | 0 | insts.push(i_subm(dst, src_right)); |
785 | | } |
786 | | |
787 | 0 | "printi" => { |
788 | 0 | let reg = parser.read_var()?; |
789 | 0 | insts.push(i_print_i(reg)); |
790 | | } |
791 | | |
792 | 0 | "prints" => { |
793 | 0 | let string = parser.read_string()?; |
794 | 0 | insts.push(i_print_s(string)); |
795 | | } |
796 | | |
797 | 0 | "println" => { |
798 | 0 | let string = parser.read_string()?; |
799 | 0 | insts.push(i_print_s(&format!("{}\n", string))); |
800 | | } |
801 | | |
802 | | _ => { |
803 | 0 | next_block_name = Some(inst_or_block_name); |
804 | 0 | break; |
805 | | } |
806 | | } |
807 | | } |
808 | | |
809 | 0 | if let Some(block_name) = block_name { |
810 | 0 | parser.define_block(block_name, insts); |
811 | 0 | } |
812 | | |
813 | 0 | if parser.is_done() { |
814 | 0 | break; |
815 | 0 | } |
816 | | |
817 | 0 | if parser.read_char()? != ':' { |
818 | 0 | return parser |
819 | 0 | .error("expected : after possible block name, or unexpected instruction name"); |
820 | 0 | } |
821 | | } |
822 | | |
823 | 0 | func.finish(); |
824 | 0 | Ok(func) |
825 | 0 | } |
826 | | |
827 | | fn is_digit(c: char) -> bool { |
828 | | c >= '0' && c <= '9' |
829 | | } |
830 | | |
831 | | fn is_alpha(c: char) -> bool { |
832 | | c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' || c == '-' |
833 | | } |
834 | | |
835 | | fn is_alpha_numeric(c: char) -> bool { |
836 | | is_digit(c) || is_alpha(c) |
837 | | } |