1use std::fmt;
33
34use rucc_base::{Interner, Symbol};
35use rucc_target::{Constraint, PhysReg, RegClass, RegFile, Role};
36
37use crate::func::Func;
38use crate::inst::{BlockCall, Mem, Opcode, Operand, Param, Reg};
39
40#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct ParseError {
47 pub line: u32,
49 pub message: String,
51}
52
53impl fmt::Display for ParseError {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "line {}: {}", self.line, self.message)
56 }
57}
58
59impl std::error::Error for ParseError {}
60
61pub fn parse(text: &str, names: &mut Interner, regs: &RegFile) -> Result<Vec<Func>, ParseError> {
70 Parser { text, pos: 0, line: 1, names, regs }.funcs()
71}
72
73#[derive(Clone, Copy, PartialEq, Eq)]
79enum Written {
80 Virtual { number: u32, class: Option<RegClass> },
82 Physical { reg: PhysReg, class: RegClass },
84}
85
86#[derive(Clone, Copy)]
88struct PendingOperand {
89 reg: Written,
90 role: Role,
91 constraint: Constraint,
92}
93
94#[derive(Clone, Copy, Default)]
96struct PendingMem {
97 base: Option<PendingOperand>,
98 index: Option<PendingOperand>,
99 scale: u8,
100 disp: i32,
101 symbol: Option<Symbol>,
102}
103
104struct PendingCall {
106 block: u32,
107 args: Vec<Written>,
108}
109
110struct PendingInst {
112 opcode: Symbol,
113 operands: Vec<PendingOperand>,
114 mem: Option<PendingMem>,
115 imm: Option<i64>,
116 symbol: Option<Symbol>,
117 succs: Vec<PendingCall>,
118 line: u32,
119}
120
121struct PendingBlock {
123 number: u32,
124 params: Vec<Written>,
125 insts: Vec<PendingInst>,
126 line: u32,
127}
128
129struct Parser<'a, 'n> {
131 text: &'a str,
132 pos: usize,
133 line: u32,
134 names: &'n mut Interner,
135 regs: &'n RegFile,
136}
137
138impl<'a> Parser<'a, '_> {
139 fn funcs(mut self) -> Result<Vec<Func>, ParseError> {
142 let mut funcs = Vec::new();
143 loop {
144 self.skip_blank_lines();
145 if self.at_end() {
146 return Ok(funcs);
147 }
148 funcs.push(self.func()?);
149 }
150 }
151
152 fn func(&mut self) -> Result<Func, ParseError> {
153 self.expect("mfunc")?;
154 let name = self.symbol()?;
155 self.expect("{")?;
156 self.end_of_line()?;
157
158 let mut blocks: Vec<PendingBlock> = Vec::new();
159 loop {
160 self.skip_blank_lines();
161 if self.eat("}") {
162 self.end_of_line()?;
163 break;
164 }
165 if self.at_end() {
166 return self.fail("the function is not closed");
167 }
168 blocks.push(self.block()?);
169 }
170 self.build(name, blocks)
171 }
172
173 fn block(&mut self) -> Result<PendingBlock, ParseError> {
174 let line = self.line;
175 let number = self.label()?;
176 let mut params = Vec::new();
177 if self.eat("(") {
178 loop {
179 params.push(self.written(true)?);
180 if !self.eat(",") {
181 break;
182 }
183 }
184 self.expect(")")?;
185 }
186 self.expect(":")?;
187 self.end_of_line()?;
188
189 let mut insts = Vec::new();
190 loop {
191 self.spaces();
192 if self.at_end() || self.at("\n") || self.at("}") || self.at_label() {
193 break;
194 }
195 insts.push(self.inst()?);
196 }
197 Ok(PendingBlock { number, params, insts, line })
198 }
199
200 fn inst(&mut self) -> Result<PendingInst, ParseError> {
201 let line = self.line;
202 let mut operands = Vec::new();
203 if self.at("%") || self.at("$") || self.peek_word() == "early" {
204 loop {
205 operands.push(self.operand(true)?);
206 if !self.eat(",") {
207 break;
208 }
209 }
210 self.expect("=")?;
211 }
212 let opcode = self.opcode()?;
213
214 let mut inst = PendingInst {
215 opcode,
216 operands,
217 mem: None,
218 imm: None,
219 symbol: None,
220 succs: Vec::new(),
221 line,
222 };
223 self.spaces();
224 if !self.at("\n") && !self.at_end() {
225 loop {
226 self.item(&mut inst)?;
227 if !self.eat(",") {
228 break;
229 }
230 }
231 }
232 self.end_of_line()?;
233 Ok(inst)
234 }
235
236 fn item(&mut self, inst: &mut PendingInst) -> Result<(), ParseError> {
238 self.spaces();
239 if self.at("%") || self.at("$") || self.peek_word() == "early" {
240 inst.operands.push(self.operand(false)?);
241 return Ok(());
242 }
243 if self.at("@") {
244 let symbol = self.symbol()?;
245 if inst.symbol.is_some() {
246 return self.fail("the instruction already names a symbol");
247 }
248 inst.symbol = Some(symbol);
249 return Ok(());
250 }
251 if self.at("[") {
252 let mem = self.mem()?;
253 if inst.mem.is_some() {
254 return self.fail("the instruction already has a memory operand");
255 }
256 inst.mem = Some(mem);
257 return Ok(());
258 }
259 if self.at_label() {
260 let call = self.block_call()?;
261 inst.succs.push(call);
262 return Ok(());
263 }
264 let value = self.i64()?;
265 if inst.imm.is_some() {
266 return self.fail("the instruction already has an immediate");
267 }
268 inst.imm = Some(value);
269 Ok(())
270 }
271
272 fn operand(&mut self, written: bool) -> Result<PendingOperand, ParseError> {
274 let early = self.eat_word("early");
275 if early && !written {
276 return self.fail("only an operand an instruction writes can be early");
277 }
278 let reg = self.written(written)?;
279 let role = match (written, early) {
280 (false, _) => Role::Use,
281 (true, false) => Role::Def,
282 (true, true) => Role::EarlyDef,
283 };
284 let mut constraint = Constraint::Reg;
285 if self.eat("(") {
286 constraint = self.constraint()?;
287 self.expect(")")?;
288 }
289 Ok(PendingOperand { reg, role, constraint })
290 }
291
292 fn constraint(&mut self) -> Result<Constraint, ParseError> {
293 if self.at("$") {
294 let Written::Physical { reg, .. } = self.written(false)? else {
295 return self.fail("a register is fixed to a physical register");
296 };
297 return Ok(Constraint::Fixed(reg));
298 }
299 match self.word() {
300 "any" => Ok(Constraint::Any),
301 "stack" => Ok(Constraint::Stack),
302 "reuse" => {
303 let at = self.u32()?;
304 match u8::try_from(at) {
305 Ok(at) => Ok(Constraint::Reuse(at)),
306 Err(_) => self.fail(format!("no instruction has {at} operands")),
307 }
308 }
309 other => self.fail(format!("`{other}` is not something an operand can be")),
310 }
311 }
312
313 fn written(&mut self, declared: bool) -> Result<Written, ParseError> {
318 self.spaces();
319 if self.eat("$") {
320 let name = self.glued_word();
321 return match self.regs.reg_named(name) {
322 Some((class, reg)) => Ok(Written::Physical { reg, class }),
323 None => self.fail(format!("this target has no register called `{name}`")),
324 };
325 }
326 self.expect("%")?;
327 let number = self.u32()?;
328 if !declared {
329 return Ok(Written::Virtual { number, class: None });
330 }
331 self.expect(":")?;
332 let name = self.word();
333 match self.regs.class_named(name) {
334 Some(class) => Ok(Written::Virtual { number, class: Some(class) }),
335 None => self.fail(format!("this target has no register class called `{name}`")),
336 }
337 }
338
339 fn mem(&mut self) -> Result<PendingMem, ParseError> {
347 self.expect("[")?;
348 let mut mem = PendingMem { scale: 1, ..PendingMem::default() };
349 let mut negative = false;
350 loop {
351 self.spaces();
352 if self.at("@") {
353 if mem.symbol.is_some() {
354 return self.fail("an address names one symbol");
355 }
356 mem.symbol = Some(self.symbol()?);
357 } else if self.at("%") || self.at("$") {
358 let operand = PendingOperand {
359 reg: self.written(false)?,
360 role: Role::Use,
361 constraint: Constraint::Reg,
362 };
363 if mem.base.is_none() {
364 mem.base = Some(operand);
365 } else if mem.index.is_none() {
366 mem.index = Some(operand);
367 if self.eat("*") {
368 let scale = self.u32()?;
369 match u8::try_from(scale) {
370 Ok(scale) => mem.scale = scale,
371 Err(_) => return self.fail(format!("{scale} is not a scale")),
372 }
373 }
374 } else {
375 return self.fail("an address names at most two registers");
376 }
377 } else {
378 let disp = self.i64()?;
379 let disp = if negative { -disp } else { disp };
380 match i32::try_from(disp) {
381 Ok(disp) => mem.disp = disp,
382 Err(_) => return self.fail(format!("{disp} is too far for a displacement")),
383 }
384 }
385 if self.eat("+") {
386 negative = false;
387 } else if self.eat("-") {
388 negative = true;
389 } else {
390 break;
391 }
392 }
393 self.expect("]")?;
394 Ok(mem)
395 }
396
397 fn block_call(&mut self) -> Result<PendingCall, ParseError> {
399 let block = self.label()?;
400 let mut args = Vec::new();
401 if self.eat("(") {
402 loop {
403 args.push(self.written(false)?);
406 if !self.eat(",") {
407 break;
408 }
409 }
410 self.expect(")")?;
411 }
412 Ok(PendingCall { block, args })
413 }
414
415 fn build(&mut self, name: Symbol, pending: Vec<PendingBlock>) -> Result<Func, ParseError> {
418 let mut func = Func::new(name);
419 for (index, block) in pending.iter().enumerate() {
420 if block.number as usize != index {
421 self.line = block.line;
422 return self.fail(format!(
423 "this is block {index} of the function and the text calls it block{}",
424 block.number
425 ));
426 }
427 func.create_block();
428 }
429 let blocks: Vec<_> = func.blocks().collect();
430
431 let mut next = 0;
434 for (block, read) in blocks.iter().zip(&pending) {
435 for param in &read.params {
436 match *param {
437 Written::Virtual { number, class } => {
438 self.line = read.line;
439 self.expect_number(number, next)?;
440 let Some(class) = class else {
441 return self
442 .fail(format!("%{number} arrives without saying its class"));
443 };
444 func.append_param(*block, class);
445 next += 1;
446 }
447 Written::Physical { reg, class } => {
448 func.append_given_param(*block, Param { reg: Reg::physical(reg), class });
449 }
450 }
451 }
452 for inst in &read.insts {
453 for operand in &inst.operands {
454 if operand.role == Role::Use {
455 continue;
456 }
457 if let Written::Virtual { number, class } = operand.reg {
458 self.line = inst.line;
459 self.expect_number(number, next)?;
460 let Some(class) = class else {
461 return self.fail(format!("%{number} is written without a class"));
462 };
463 func.new_vreg(class);
464 next += 1;
465 }
466 }
467 }
468 }
469
470 for (block, read) in blocks.iter().zip(&pending) {
471 let last = read.insts.len().saturating_sub(1);
472 for (at, inst) in read.insts.iter().enumerate() {
473 self.line = inst.line;
474 if !inst.succs.is_empty() && at != last {
475 return self.fail("only the last instruction of a block says where it goes");
476 }
477 let mut operands = Vec::new();
480 for operand in &inst.operands {
481 operands.push(self.resolve(&func, operand)?);
482 }
483 let mem = match inst.mem {
484 Some(mem) => Some(Mem {
485 base: match mem.base {
486 Some(operand) => Some(self.resolve(&func, &operand)?),
487 None => None,
488 },
489 index: match mem.index {
490 Some(operand) => Some(self.resolve(&func, &operand)?),
491 None => None,
492 },
493 scale: mem.scale,
494 disp: mem.disp,
495 symbol: mem.symbol,
496 }),
497 None => None,
498 };
499 let mut builder = func.build(*block, Opcode::new(inst.opcode));
500 for operand in operands {
501 builder = builder.operand(operand);
502 }
503 if let Some(mem) = mem {
504 builder = builder.mem(mem);
505 }
506 if let Some(symbol) = inst.symbol {
507 builder = builder.symbol(symbol);
508 }
509 if let Some(value) = inst.imm {
510 builder = builder.imm(value);
511 }
512 builder.finish();
513 }
514 let Some(terminator) = read.insts.last() else { continue };
515 self.line = terminator.line;
516 let mut succs = Vec::new();
517 for call in &terminator.succs {
518 let Some(&target) = blocks.get(call.block as usize) else {
519 return self
520 .fail(format!("block{} is branched to and never begins", call.block));
521 };
522 let mut args = Vec::new();
523 for (at, arg) in call.args.iter().enumerate() {
524 args.push(match *arg {
525 Written::Physical { reg, .. } => Reg::physical(reg),
526 Written::Virtual { number, .. } => {
527 let class = func[target].params.get(at).map(|param| param.class);
528 let Some(class) = class else {
529 return self.fail(format!(
530 "block{} takes {} arguments and is given more",
531 call.block,
532 func[target].params.len()
533 ));
534 };
535 self.virtual_reg(&func, number, class)?
536 }
537 });
538 }
539 if args.len() != func[target].params.len() {
540 return self.fail(format!(
541 "block{} takes {} arguments and is given {}",
542 call.block,
543 func[target].params.len(),
544 args.len()
545 ));
546 }
547 succs.push(BlockCall::with(target, args));
548 }
549 *func.succs_mut(*block) = succs;
550 }
551 Ok(func)
552 }
553
554 fn resolve(&self, func: &Func, operand: &PendingOperand) -> Result<Operand, ParseError> {
561 let (reg, class) = match operand.reg {
562 Written::Physical { reg, class } => (Reg::physical(reg), class),
563 Written::Virtual { number, class } => {
564 let reg = Reg::virtual_reg(number);
565 match (class, func.class_of(reg)) {
566 (Some(class), _) => (reg, class),
567 (None, Some(class)) => (reg, class),
568 (None, None) => {
569 return self.fail(format!("%{number} is read and never written"));
570 }
571 }
572 }
573 };
574 Ok(Operand { reg, class, role: operand.role, constraint: operand.constraint })
575 }
576
577 fn virtual_reg(&self, func: &Func, number: u32, class: RegClass) -> Result<Reg, ParseError> {
579 let reg = Reg::virtual_reg(number);
580 match func.class_of(reg) {
581 None => self.fail(format!("%{number} is read and never written")),
582 Some(found) if found != class => {
583 self.fail(format!("%{number} is passed to a parameter of another class"))
584 }
585 Some(_) => Ok(reg),
586 }
587 }
588
589 fn expect_number(&self, number: u32, next: u32) -> Result<(), ParseError> {
591 if number == next {
592 return Ok(());
593 }
594 self.fail(format!("this is %{next} of the function and the text calls it %{number}"))
595 }
596
597 fn fail<T>(&self, message: impl Into<String>) -> Result<T, ParseError> {
600 Err(ParseError { line: self.line, message: message.into() })
601 }
602
603 fn at(&self, text: &str) -> bool {
604 self.text[self.pos..].starts_with(text)
605 }
606
607 fn at_end(&self) -> bool {
608 self.pos >= self.text.len()
609 }
610
611 fn at_label(&self) -> bool {
613 let rest = self.text[self.pos..].trim_start_matches([' ', '\t']);
614 let Some(rest) = rest.strip_prefix("block") else { return false };
615 rest.starts_with(|c: char| c.is_ascii_digit())
616 }
617
618 fn peek(&self) -> Option<u8> {
619 self.text.as_bytes().get(self.pos).copied()
620 }
621
622 fn spaces(&mut self) {
623 while matches!(self.peek(), Some(b' ' | b'\t')) {
624 self.pos += 1;
625 }
626 }
627
628 fn eat(&mut self, text: &str) -> bool {
629 self.spaces();
630 if self.at(text) {
631 self.pos += text.len();
632 return true;
633 }
634 false
635 }
636
637 fn expect(&mut self, text: &str) -> Result<(), ParseError> {
638 if self.eat(text) {
639 return Ok(());
640 }
641 self.fail(format!("expected `{text}`"))
642 }
643
644 fn word(&mut self) -> &'a str {
645 self.spaces();
646 self.glued_word()
647 }
648
649 fn glued_word(&mut self) -> &'a str {
651 let start = self.pos;
652 while self.peek().is_some_and(is_name_byte) {
653 self.pos += 1;
654 }
655 &self.text[start..self.pos]
656 }
657
658 fn peek_word(&self) -> &'a str {
659 let rest = self.text[self.pos..].trim_start_matches([' ', '\t']);
660 let end = rest
661 .find(|c: char| !(c.is_ascii_alphanumeric() || c == '_' || c == '.'))
662 .unwrap_or(rest.len());
663 &rest[..end]
664 }
665
666 fn eat_word(&mut self, word: &str) -> bool {
667 if self.peek_word() != word {
668 return false;
669 }
670 self.word();
671 true
672 }
673
674 fn label(&mut self) -> Result<u32, ParseError> {
676 self.expect("block")?;
677 self.u32()
678 }
679
680 fn symbol(&mut self) -> Result<Symbol, ParseError> {
682 self.expect("@")?;
683 let name = self.glued_word();
684 if name.is_empty() {
685 return self.fail("a symbol has a name");
686 }
687 Ok(self.names.intern(name))
688 }
689
690 fn u32(&mut self) -> Result<u32, ParseError> {
691 let word = self.word();
692 match word.parse::<u32>() {
693 Ok(number) => Ok(number),
694 Err(_) => self.fail(format!("`{word}` is not a number")),
695 }
696 }
697
698 fn i64(&mut self) -> Result<i64, ParseError> {
699 self.spaces();
700 let start = self.pos;
701 if self.at("-") {
702 self.pos += 1;
703 }
704 self.glued_word();
705 let word = &self.text[start..self.pos];
706 match word.parse::<i64>() {
707 Ok(number) => Ok(number),
708 Err(_) => self.fail(format!("`{word}` is not a number")),
709 }
710 }
711
712 fn opcode(&mut self) -> Result<Symbol, ParseError> {
714 let word = self.word();
715 if word.is_empty() {
716 return self.fail("expected an instruction");
717 }
718 Ok(self.names.intern(word))
719 }
720
721 fn end_of_line(&mut self) -> Result<(), ParseError> {
722 self.spaces();
723 if self.at_end() {
724 return Ok(());
725 }
726 if !self.at("\n") {
727 let rest = self.text[self.pos..].lines().next().unwrap_or_default();
728 return self.fail(format!("`{rest}` is left over at the end of the line"));
729 }
730 self.pos += 1;
731 self.line += 1;
732 Ok(())
733 }
734
735 fn skip_blank_lines(&mut self) {
736 loop {
737 let held = self.pos;
738 self.spaces();
739 if self.at("\n") {
740 self.pos += 1;
741 self.line += 1;
742 continue;
743 }
744 self.pos = held;
745 return;
746 }
747 }
748}
749
750fn is_name_byte(byte: u8) -> bool {
752 byte.is_ascii_alphanumeric() || byte == b'_' || byte == b'.'
753}
754
755#[cfg(test)]
756mod tests {
757 use super::*;
758 use crate::fixtures::{AFTER, BEFORE, REGS};
759 use crate::print::{print, print_func};
760
761 fn round_trip(text: &str) {
763 let mut names = Interner::new();
764 let funcs = parse(text, &mut names, ®S).expect("the fixture is what the printer writes");
765 let [func] = &funcs[..] else { panic!("the text is one function") };
766 assert_eq!(print_func(func, &names, ®S), text);
767 }
768
769 fn error(text: &str) -> String {
771 let mut names = Interner::new();
772 parse(text, &mut names, ®S).expect_err("the text does not add up").to_string()
773 }
774
775 #[test]
776 fn a_function_before_allocation_round_trips() {
777 round_trip(BEFORE);
778 }
779
780 #[test]
781 fn a_function_after_allocation_round_trips() {
782 round_trip(AFTER);
783 }
784
785 #[test]
786 fn two_functions_round_trip() {
787 let text = format!("{BEFORE}\n{AFTER}");
788 let mut names = Interner::new();
789 let funcs = parse(&text, &mut names, ®S).expect("both fixtures are readable");
790 assert_eq!(funcs.len(), 2);
791 assert_eq!(print(&funcs, &names, ®S), text);
792 }
793
794 #[test]
795 fn an_empty_text_is_no_functions() {
796 let mut names = Interner::new();
797 assert!(parse("\n\n", &mut names, ®S).expect("nothing is readable").is_empty());
798 }
799
800 #[test]
801 fn a_register_nothing_writes_is_refused() {
802 let text = "mfunc @f {\nblock0:\n x64.ret %3\n}\n";
803 assert_eq!(error(text), "line 3: %3 is read and never written");
804 }
805
806 #[test]
807 fn a_register_numbered_out_of_order_is_refused() {
808 let text = "mfunc @f {\nblock0:\n %1:gpr = x64.mov_ri 4\n x64.ret %1\n}\n";
809 assert_eq!(error(text), "line 3: this is %0 of the function and the text calls it %1");
810 }
811
812 #[test]
813 fn a_block_numbered_out_of_order_is_refused() {
814 let text = "mfunc @f {\nblock1:\n x64.ret $rax\n}\n";
815 assert_eq!(
816 error(text),
817 "line 2: this is block 0 of the function and the text calls it block1"
818 );
819 }
820
821 #[test]
822 fn a_register_the_target_does_not_have_is_refused() {
823 let text = "mfunc @f {\nblock0:\n x64.ret $r13\n}\n";
824 assert_eq!(error(text), "line 3: this target has no register called `r13`");
825 }
826
827 #[test]
828 fn a_class_the_target_does_not_have_is_refused() {
829 let text = "mfunc @f {\nblock0:\n %0:vec = x64.mov_ri 4\n x64.ret $rax\n}\n";
830 assert_eq!(error(text), "line 3: this target has no register class called `vec`");
831 }
832
833 #[test]
834 fn an_argument_of_another_class_is_refused() {
835 let text = "\
836mfunc @f {
837block0:
838 %0:xmm = x64.movd_xr $rax
839 x64.jmp block1(%0)
840
841block1(%1:gpr):
842 x64.ret $rax
843}
844";
845 assert_eq!(error(text), "line 4: %0 is passed to a parameter of another class");
846 }
847
848 #[test]
849 fn a_block_given_the_wrong_number_of_arguments_is_refused() {
850 let text = "\
851mfunc @f {
852block0(%0:gpr):
853 x64.jmp block1(%0)
854
855block1(%1:gpr, %2:gpr):
856 x64.ret $rax
857}
858";
859 assert_eq!(error(text), "line 3: block1 takes 2 arguments and is given 1");
860 }
861
862 #[test]
863 fn a_branch_to_a_block_that_never_begins_is_refused() {
864 let text = "mfunc @f {\nblock0:\n x64.jmp block4\n}\n";
865 assert_eq!(error(text), "line 3: block4 is branched to and never begins");
866 }
867
868 #[test]
869 fn a_branch_before_the_end_of_a_block_is_refused() {
870 let text = "mfunc @f {\nblock0:\n x64.jmp block0\n x64.ret $rax\n}\n";
871 assert_eq!(error(text), "line 3: only the last instruction of a block says where it goes");
872 }
873
874 #[test]
875 fn a_read_operand_cannot_be_early() {
876 let text = "mfunc @f {\nblock0:\n x64.ret early $rax\n}\n";
877 assert_eq!(error(text), "line 3: only an operand an instruction writes can be early");
878 }
879
880 #[test]
881 fn a_second_immediate_is_refused() {
882 let text = "mfunc @f {\nblock0:\n x64.ret 1, 2\n}\n";
883 assert_eq!(error(text), "line 3: the instruction already has an immediate");
884 }
885
886 #[test]
887 fn a_function_that_does_not_close_is_refused() {
888 let text = "mfunc @f {\nblock0:\n x64.ret $rax\n";
889 assert_eq!(error(text), "line 4: the function is not closed");
890 }
891
892 #[test]
893 fn what_is_left_over_on_a_line_is_reported() {
894 let text = "mfunc @f {\nblock0:\n x64.ret $rax ]\n}\n";
895 assert_eq!(error(text), "line 3: `]` is left over at the end of the line");
896 }
897}