1use self::ext::*;
5use b2c2_casl2 as casl2;
6use b2c2_compiler_common::*;
7use b2c2_parser as parser;
8use b2c2_tokenizer as tokenizer;
9use std::cmp::Reverse;
10use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet};
11use std::convert::TryFrom;
12use std::fmt::Write;
13
14mod assign_elem_stmt;
15mod assign_stmt;
16mod bool_arr_func;
17mod bool_func;
18mod cmp_bin_op;
19mod do_stmt;
20mod exprs;
21mod ext;
22mod fill_stmt;
23mod for_stmt;
24mod input_stmt;
25mod int_arr_func;
26mod int_bin_op;
27mod int_func;
28pub mod optimize;
29mod print_stmt;
30mod select_stmt;
31mod stmts;
32mod str_bin_op;
33mod str_func;
34pub mod subroutine;
35pub mod utils;
36
37#[cfg(test)]
38mod test;
39
40type CompileError = String;
41
42pub fn compile(
44 program_name: Option<String>,
45 src: &[parser::Statement],
46) -> Result<Vec<casl2::Statement>, CompileError> {
47 if let Some(program_name) = program_name.as_ref() {
48 for sub_name in src.iter().filter_map(|stmt| {
49 if let parser::Statement::ExternSub { name, .. } = stmt {
50 Some(name)
51 } else {
52 None
53 }
54 }) {
55 if sub_name == program_name {
56 return Err(format!(
57 "ソースコード内で既に使用されている名前です: {}",
58 program_name
59 ));
60 }
61 }
62 }
63
64 let mut compiler = Compiler::new(program_name)?;
65
66 for stmt in src.iter() {
67 compiler.compile(stmt);
68 }
69
70 Ok(compiler.finish())
71}
72
73#[derive(Default, Clone, Debug)]
74pub struct Flag {
75 pub remove_comment: bool,
77 pub remove_nop: bool,
79 pub remove_unreferenced_label: bool,
81 pub split_subroutines: bool,
83 pub program_name: Option<String>,
85 pub try_make_snippets: bool,
87 pub for_debug_basic: bool,
89}
90
91type CodeWithName = Vec<(String, Vec<casl2::Statement>)>;
92
93pub fn compile_with_flag(
95 src: &[parser::Statement],
96 flag: Flag,
97) -> Result<CodeWithName, CompileError> {
98 let statements = compile(flag.program_name.clone(), src)?;
99
100 Ok(flag.apply(statements))
101}
102
103impl Flag {
104 pub fn apply(&self, mut statements: Vec<casl2::Statement>) -> CodeWithName {
105 if self.remove_comment {
106 statements = optimize::remove_comment(&statements);
107 }
108
109 if self.remove_unreferenced_label {
110 statements = optimize::remove_unreferenced_label(&statements);
111 }
112
113 if self.try_make_snippets {
114 statements = optimize::collect_duplicates(statements);
115 }
116
117 if self.remove_nop {
118 statements = optimize::remove_nop(&statements);
119 }
120
121 if !self.split_subroutines {
122 let name = casl2::utils::get_program_name(&statements)
123 .unwrap()
124 .to_string();
125 return vec![(name, statements)];
126 }
127
128 utils::split_subroutines(statements)
129 }
130}
131
132#[derive(Clone)]
133pub struct LabelSet {
134 pub argument_labels: HashMap<String, (ValueLabel, parser::ArgumentInfo)>,
135 pub arr_argument_labels: HashMap<String, (ArrayLabel, parser::ArgumentInfo)>,
136 pub str_argument_labels: HashMap<String, (StrLabels, parser::ArgumentInfo)>,
137 pub bool_var_labels: HashMap<String, ValueLabel>,
138 pub int_var_labels: HashMap<String, ValueLabel>,
139 pub str_var_labels: HashMap<String, StrLabels>,
140 pub bool_arr_labels: HashMap<String, ArrayLabel>,
141 pub int_arr_labels: HashMap<String, ArrayLabel>,
142}
143
144#[derive(Clone)]
145pub enum ExtraInfo {
146 For {
147 counter: ValueLabel,
148 to: Option<String>,
149 step: Option<String>,
150 },
151 Condition(casl2::Register),
152 RelatedCode(String),
153 SelectInt(casl2::Register),
154 SelectStr {
155 len_value: casl2::Register,
156 pos_address: casl2::Register,
157 },
158}
159
160#[derive(Clone)]
161pub struct DebugInfo {
162 pub label_set: LabelSet,
163 pub status_hint: Vec<(usize, String, Option<ExtraInfo>)>,
164}
165
166pub fn compile_for_debugger(
168 src: &[parser::Statement],
169 flag: &Flag,
170) -> Result<(DebugInfo, CodeWithName), CompileError> {
171 if let Some(program_name) = &flag.program_name {
172 for sub_name in src.iter().filter_map(|stmt| {
173 if let parser::Statement::ExternSub { name, .. } = stmt {
174 Some(name)
175 } else {
176 None
177 }
178 }) {
179 if sub_name == program_name {
180 return Err(format!(
181 "ソースコード内で既に使用されている名前です: {}",
182 program_name
183 ));
184 }
185 }
186 }
187
188 let mut compiler = Compiler::new(flag.program_name.clone())?;
189
190 compiler.for_debug_basic = flag.for_debug_basic;
191 compiler.add_debugger_hint_message(|| "Sub MAIN".to_string());
192 compiler.nest_depth = 1;
193 compiler.add_debugger_hint_message(|| "(initialize)".to_string());
194
195 for stmt in src.iter() {
196 compiler.compile(stmt);
197 }
198
199 let label_set = LabelSet {
200 argument_labels: compiler.argument_labels.clone(),
201 arr_argument_labels: compiler.arr_argument_labels.clone(),
202 str_argument_labels: compiler.str_argument_labels.clone(),
203 bool_var_labels: compiler.bool_var_labels.clone(),
204 int_var_labels: compiler.int_var_labels.clone(),
205 str_var_labels: compiler.str_var_labels.clone(),
206 bool_arr_labels: compiler.bool_arr_labels.clone(),
207 int_arr_labels: compiler.int_arr_labels.clone(),
208 };
209
210 let debug_info = DebugInfo {
211 label_set,
212 status_hint: if flag.for_debug_basic {
213 let mut hint = compiler.debugger_hint.clone();
214 hint.push((0, "End Sub".to_string(), None));
215 if let Some(pn) = compiler.program_name.as_ref() {
216 let (_, msg, _) = hint.first_mut().unwrap();
217 *msg = msg.replace("MAIN", pn);
218 }
219 hint
220 } else {
221 Vec::new()
222 },
223 };
224
225 let statements = compiler.finish();
226
227 Ok((debug_info, flag.apply(statements)))
228}
229
230#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
232pub enum StrLabelType {
233 Const(String), Lit(String), Temp, Var, ArgRef, ArgVal, MemRef(usize), MemVal(usize),
241}
242
243#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
245pub struct StrLabels {
246 pub pos: String,
247 pub len: String,
248 pub label_type: StrLabelType,
249}
250
251#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
254pub enum ArrayLabel {
255 TempArrayOfBoolean(StrLabels, usize),
256 TempArrayOfInteger(StrLabels, usize),
257 VarArrayOfBoolean(String, usize),
258 VarArrayOfInteger(String, usize),
259 VarRefArrayOfBoolean(String, usize),
260 VarRefArrayOfInteger(String, usize),
261 MemArrayOfBoolean { offset: usize, size: usize },
262 MemArrayOfInteger { offset: usize, size: usize },
263 MemRefArrayOfBoolean { offset: usize, size: usize },
264 MemRefArrayOfInteger { offset: usize, size: usize },
265}
266
267#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
268pub enum ValueLabel {
269 VarBoolean(String),
270 VarInteger(String),
271 VarRefBoolean(String),
272 VarRefInteger(String),
273 MemBoolean(usize),
274 MemInteger(usize),
275 MemRefBoolean(usize),
276 MemRefInteger(usize),
277}
278
279struct Compiler {
280 for_debug_basic: bool,
282 nest_depth: usize,
284
285 debugger_hint: Vec<(usize, String, Option<ExtraInfo>)>,
287
288 program_name: Option<String>,
290 original_program_name: Option<String>,
291
292 arguments: Vec<parser::ArgumentInfo>,
294
295 argument_labels: HashMap<String, (ValueLabel, parser::ArgumentInfo)>,
297
298 arr_argument_labels: HashMap<String, (ArrayLabel, parser::ArgumentInfo)>,
300
301 str_argument_labels: HashMap<String, (StrLabels, parser::ArgumentInfo)>,
303
304 callables: HashMap<String, Vec<parser::ArgumentInfo>>,
306
307 var_id: usize,
309
310 lit_id: usize,
312
313 local_var_id: usize,
315
316 temp_int_var_id: usize,
318 temp_str_var_id: usize,
319
320 jump_id: usize,
322
323 bool_var_labels: HashMap<String, ValueLabel>,
325
326 int_var_labels: HashMap<String, ValueLabel>,
328
329 str_var_labels: HashMap<String, StrLabels>,
331
332 bool_arr_labels: HashMap<String, ArrayLabel>,
334
335 int_arr_labels: HashMap<String, ArrayLabel>,
337
338 lit_str_labels: HashMap<String, StrLabels>,
340
341 temp_int_var_labels: BinaryHeap<Reverse<String>>,
343 engaged_temp_int_var_labels: HashSet<String>,
345 save_temp_int_var_labels: HashSet<String>,
347
348 temp_str_var_labels: BinaryHeap<Reverse<StrLabels>>,
350
351 subroutine_codes: HashMap<subroutine::Id, Vec<casl2::Statement>>,
353
354 loop_labels: HashMap<usize, String>,
356
357 exit_labels: HashMap<usize, String>,
359
360 registers_used: u8,
367
368 used_registers_order: Vec<casl2::Register>,
376 stacked_registers: Vec<casl2::Register>,
377
378 statements: Vec<casl2::Statement>,
380
381 has_eof: bool,
383
384 var_total_size: usize,
386
387 option_restore_registers: bool,
389
390 option_initialize_variables: bool,
392
393 option_external_eof: bool,
395
396 option_use_allocator: bool,
398
399 option_local_allocation_size: Option<usize>,
401
402 allocate_memory_relative_position: usize,
404
405 allocate_arguments_size: usize,
407
408 maximum_allocate_temporary_area_size: usize,
410}
411
412impl Compiler {
414 fn new(program_name: Option<String>) -> Result<Self, CompileError> {
416 if let Some(name) = program_name.as_ref() {
417 if !is_valid_program_name(name) {
418 return Err(format!("禁止されている名前です: {}", name));
419 }
420 }
421
422 Ok(Self {
423 for_debug_basic: false,
424 nest_depth: 0,
425 debugger_hint: Vec::new(),
426 program_name,
427 original_program_name: None,
428 arguments: Vec::new(),
429 argument_labels: HashMap::new(),
430 arr_argument_labels: HashMap::new(),
431 str_argument_labels: HashMap::new(),
432 callables: HashMap::new(),
433 var_id: 0,
434 lit_id: 0,
435 local_var_id: 0,
436 temp_int_var_id: 0,
437 temp_str_var_id: 0,
438 jump_id: 0,
439 bool_var_labels: HashMap::new(),
440 int_var_labels: HashMap::new(),
441 str_var_labels: HashMap::new(),
442 bool_arr_labels: HashMap::new(),
443 int_arr_labels: HashMap::new(),
444 lit_str_labels: HashMap::new(),
445 temp_int_var_labels: BinaryHeap::new(),
446 engaged_temp_int_var_labels: HashSet::new(),
447 save_temp_int_var_labels: HashSet::new(),
448 temp_str_var_labels: BinaryHeap::new(),
449 subroutine_codes: HashMap::new(),
450 loop_labels: HashMap::new(),
451 exit_labels: HashMap::new(),
452 registers_used: 0,
453 used_registers_order: {
454 use casl2::Register::*;
455 vec![Gr7, Gr6, Gr5, Gr4, Gr3, Gr2, Gr1]
456 },
457 stacked_registers: Vec::new(),
458 statements: Vec::new(),
459 has_eof: false,
460 var_total_size: 0,
461 option_restore_registers: true,
462 option_initialize_variables: true,
463 option_external_eof: false,
464 option_use_allocator: false,
465 option_local_allocation_size: None,
466 allocate_memory_relative_position: 0,
467 allocate_arguments_size: 0,
468 maximum_allocate_temporary_area_size: 0,
469 })
470 }
471}
472
473impl Compiler {
475 fn get_current_debugger_hint(&self) -> Option<casl2::Command> {
477 if !self.for_debug_basic {
478 return None;
479 }
480 let len = self.debugger_hint.len();
481 if len > 0 {
482 Some(casl2::Command::DebugBasicStep { id: len - 1 })
483 } else {
484 None
485 }
486 }
487
488 fn set_debugger_hint_extra_info<F>(&mut self, extra: F)
489 where
490 F: FnOnce() -> ExtraInfo,
491 {
492 if !self.for_debug_basic {
493 return;
494 }
495 if let Some((_, _, v)) = self.debugger_hint.last_mut() {
496 *v = Some(extra());
497 }
498 }
499
500 fn show_debugger_hint(&mut self) {
502 if let Some(cmd) = self.get_current_debugger_hint() {
503 self.code(cmd);
504 }
505 }
506
507 fn add_debugger_hint_message<F>(&mut self, hint: F)
509 where
510 F: FnOnce() -> String,
511 {
512 if !self.for_debug_basic {
513 return;
514 }
515 let nest = self.nest_depth;
516 self.debugger_hint.push((nest, hint(), None));
517 }
518
519 fn add_debugger_hint<F>(&mut self, hint: F)
521 where
522 F: FnOnce() -> String,
523 {
524 if !self.for_debug_basic {
525 return;
526 }
527 if let Some(cmd) = self.get_current_debugger_hint() {
528 self.code(cmd);
529 }
530 let nest = self.nest_depth;
531 self.debugger_hint.push((nest, hint(), None));
532 }
533}
534
535impl subroutine::Gen for Compiler {
537 fn var_label(&mut self) -> String {
538 self.get_new_local_var_label()
539 }
540
541 fn jump_label(&mut self) -> String {
542 self.get_new_jump_label()
543 }
544}
545
546impl Compiler {
548 fn get_new_local_var_label(&mut self) -> String {
550 self.local_var_id += 1;
551 format!("V{:03}", self.local_var_id)
552 }
553
554 fn get_new_jump_label(&mut self) -> String {
556 self.jump_id += 1;
557 format!("J{:03}", self.jump_id)
558 }
559
560 fn get_loop_label(&mut self, exit_id: usize) -> String {
562 if let Some(label) = self.loop_labels.get(&exit_id) {
563 label.clone()
564 } else {
565 let label = self.get_new_jump_label();
566 self.loop_labels.insert(exit_id, label.clone());
567 label
568 }
569 }
570
571 fn get_exit_label(&mut self, exit_id: usize) -> String {
573 if let Some(label) = self.exit_labels.get(&exit_id) {
574 label.clone()
575 } else {
576 let label = self.get_new_jump_label();
577 self.exit_labels.insert(exit_id, label.clone());
578 label
579 }
580 }
581
582 fn get_temp_int_var_label(&mut self) -> String {
584 if let Some(Reverse(label)) = self.temp_int_var_labels.pop() {
585 self.engaged_temp_int_var_labels.insert(label.clone());
586 return label;
587 }
588 self.temp_int_var_id += 1;
589 let label = format!("T{:03}", self.temp_int_var_id);
590 self.engaged_temp_int_var_labels.insert(label.clone());
591 label
592 }
593
594 fn return_temp_int_var_label(&mut self, label: String) {
596 self.engaged_temp_int_var_labels.remove(&label);
597 self.temp_int_var_labels.push(Reverse(label));
598 }
599
600 fn get_temp_str_var_label(&mut self) -> StrLabels {
602 if let Some(Reverse(labels)) = self.temp_str_var_labels.pop() {
603 return labels;
604 }
605 self.temp_str_var_id += 1;
606 StrLabels {
607 len: format!("TL{:03}", self.temp_str_var_id),
608 pos: format!("TB{:03}", self.temp_str_var_id),
609 label_type: StrLabelType::Temp,
610 }
611 }
612
613 fn return_temp_str_var_label(&mut self, labels: StrLabels) {
615 if matches!(labels.label_type, StrLabelType::Temp) {
616 self.temp_str_var_labels.push(Reverse(labels));
617 }
618 }
619
620 fn return_if_temp_arr_label(&mut self, label: ArrayLabel) {
622 if let Some(str_labels) = label.release() {
623 self.temp_str_var_labels.push(Reverse(str_labels));
624 }
625 }
626
627 fn get_lit_str_labels(&mut self, literal: &str) -> StrLabels {
629 if let Some(labels) = self.lit_str_labels.get(literal) {
630 return labels.clone();
631 }
632 self.lit_id += 1;
633 let labels = StrLabels {
634 len: format!("LL{:03}", self.lit_id),
635 pos: format!("LB{:03}", self.lit_id),
636 label_type: StrLabelType::Const(literal.to_string()),
637 };
638 self.lit_str_labels.insert(literal.into(), labels.clone());
639 labels
640 }
641
642 fn get_lit_str_label_if_exists(&mut self, literal: &str) -> StrLabels {
644 if let Some(labels) = self.lit_str_labels.get(literal) {
645 return labels.clone();
646 }
647 if literal.is_empty() {
648 StrLabels {
649 len: "=0".to_string(),
650 pos: "=0".to_string(),
651 label_type: StrLabelType::Lit(literal.to_string()),
652 }
653 } else {
654 StrLabels {
655 len: format!("={}", literal.chars().count()),
656 pos: format!("='{}'", literal.replace('\'', "''")),
657 label_type: StrLabelType::Lit(literal.to_string()),
658 }
659 }
660 }
661
662 fn load_subroutine(&mut self, req_id: subroutine::Id) -> String {
664 let mut loading_ids = vec![req_id];
665 while let Some(id) = loading_ids.pop() {
666 if self.subroutine_codes.contains_key(&id) {
667 continue;
668 }
669 let subroutine::Src {
670 mut dependencies,
671 statements,
672 } = subroutine::get_src(self, id);
673 loading_ids.append(&mut dependencies);
674 self.subroutine_codes.insert(id, statements);
675 }
676 req_id.label()
677 }
678
679 fn is_idle_register(&self, reg: casl2::Register) -> bool {
681 (self.registers_used & (1 << reg as isize)) == 0
682 }
683
684 fn get_idle_register(&mut self) -> casl2::Register {
686 let len = self.used_registers_order.len();
687 let reg = self.used_registers_order[len - 7];
688 if !self.is_idle_register(reg) {
689 self.stacked_registers.push(reg);
690 self.code(casl2::Command::P {
691 code: casl2::P::Push,
692 adr: casl2::Adr::Dec(0),
693 x: Some(TryFrom::try_from(reg).unwrap()),
694 });
695 }
696 self.registers_used |= 1 << reg as isize;
697 self.used_registers_order.push(reg);
698 reg
699 }
700
701 fn restore_register(&mut self, reg: casl2::Register) {
703 if !self.is_idle_register(reg) {
704 return;
705 }
706 self.registers_used |= 1 << reg as isize;
707 self.code(casl2::Command::Pop { r: reg });
708 let poped = self.stacked_registers.pop();
709 assert_eq!(poped, Some(reg));
710 }
711
712 fn set_register_used(&mut self, reg: casl2::Register) {
714 assert!(self.is_idle_register(reg));
715 self.registers_used |= 1 << reg as isize;
716 self.used_registers_order.push(reg);
717 }
718
719 fn set_register_idle(&mut self, reg: casl2::Register) {
721 assert!(!self.is_idle_register(reg));
722 self.registers_used ^= 1 << reg as isize;
723 let poped = self.used_registers_order.pop();
724 assert_eq!(poped, Some(reg));
725 }
726
727 fn get_save_registers_src(&mut self, regs: &[casl2::Register]) -> (String, String) {
730 let mut saves = String::new();
731 let mut recovers = String::new();
732
733 for reg in regs.iter() {
734 if !self.is_idle_register(*reg) {
735 writeln!(&mut saves, " PUSH 0,{}", reg).unwrap();
736 writeln!(&mut recovers, " POP {}", reg).unwrap();
737 }
738 }
739
740 (saves, recovers)
741 }
742
743 fn get_int_var_label(&self, var_name: &str) -> ValueLabel {
745 self.int_var_labels
746 .get(var_name)
747 .cloned()
748 .unwrap_or_else(|| {
749 let (label, arg) = self.argument_labels.get(var_name).unwrap();
750 assert_eq!(arg.var_name, var_name);
751 assert!(matches!(arg.var_type, parser::VarType::Integer));
752 label.clone()
753 })
754 }
755
756 fn get_ref_int_var_label(&self, var_name: &str) -> ValueLabel {
758 let (label, arg) = self.argument_labels.get(var_name).unwrap();
759 assert_eq!(arg.var_name, var_name);
760 assert!(matches!(arg.var_type, parser::VarType::RefInteger));
761 label.clone()
762 }
763
764 fn get_bool_var_label(&self, var_name: &str) -> ValueLabel {
766 self.bool_var_labels
767 .get(var_name)
768 .cloned()
769 .unwrap_or_else(|| {
770 let (label, arg) = self.argument_labels.get(var_name).unwrap();
771 assert_eq!(arg.var_name, var_name);
772 assert!(matches!(arg.var_type, parser::VarType::Boolean));
773 label.clone()
774 })
775 }
776
777 fn get_ref_bool_var_label(&self, var_name: &str) -> ValueLabel {
779 let (label, arg) = self.argument_labels.get(var_name).unwrap();
780 assert_eq!(arg.var_name, var_name);
781 assert!(matches!(arg.var_type, parser::VarType::RefBoolean));
782 label.clone()
783 }
784
785 fn get_str_var_labels(&self, var_name: &str) -> StrLabels {
787 self.str_var_labels
788 .get(var_name)
789 .cloned()
790 .unwrap_or_else(|| {
791 let (labels, arg) = self.str_argument_labels.get(var_name).unwrap();
792 assert_eq!(arg.var_name, var_name);
793 assert!(matches!(arg.var_type, parser::VarType::String));
794 assert!(matches!(
795 labels.label_type,
796 StrLabelType::ArgVal | StrLabelType::MemVal(..)
797 ));
798 labels.clone()
799 })
800 }
801
802 fn get_ref_str_var_labels(&self, var_name: &str) -> StrLabels {
804 let (labels, arg) = self.str_argument_labels.get(var_name).unwrap();
805 assert_eq!(arg.var_name, var_name);
806 assert!(matches!(arg.var_type, parser::VarType::RefString));
807 assert!(matches!(
808 labels.label_type,
809 StrLabelType::ArgRef | StrLabelType::MemRef(..)
810 ));
811 labels.clone()
812 }
813
814 fn get_bool_arr_label(&self, var_name: &str) -> ArrayLabel {
816 self.bool_arr_labels
817 .get(var_name)
818 .cloned()
819 .unwrap_or_else(|| {
820 let (label, arg) = self.arr_argument_labels.get(var_name).unwrap();
821 assert_eq!(arg.var_name, var_name);
822 assert!(matches!(
823 label,
824 ArrayLabel::VarArrayOfBoolean(..) | ArrayLabel::MemArrayOfBoolean { .. }
825 ));
826 label.clone()
827 })
828 }
829
830 fn get_ref_bool_arr_label(&self, var_name: &str) -> ArrayLabel {
832 let (label, arg) = self.arr_argument_labels.get(var_name).unwrap();
833 assert_eq!(arg.var_name, var_name);
834 assert!(matches!(
835 label,
836 ArrayLabel::VarRefArrayOfBoolean(..) | ArrayLabel::MemRefArrayOfBoolean { .. }
837 ));
838 label.clone()
839 }
840
841 fn get_int_arr_label(&self, var_name: &str) -> ArrayLabel {
843 self.int_arr_labels
844 .get(var_name)
845 .cloned()
846 .unwrap_or_else(|| {
847 let (label, arg) = self.arr_argument_labels.get(var_name).unwrap();
848 assert_eq!(arg.var_name, var_name);
849 assert!(matches!(
850 label,
851 ArrayLabel::VarArrayOfInteger(..) | ArrayLabel::MemArrayOfInteger { .. }
852 ));
853 label.clone()
854 })
855 }
856
857 fn get_ref_int_arr_label(&self, var_name: &str) -> ArrayLabel {
859 let (label, arg) = self.arr_argument_labels.get(var_name).unwrap();
860 assert_eq!(arg.var_name, var_name);
861 assert!(matches!(
862 label,
863 ArrayLabel::VarRefArrayOfInteger(..) | ArrayLabel::MemRefArrayOfInteger { .. }
864 ));
865 label.clone()
866 }
867}
868
869impl Compiler {
871 fn finish(mut self) -> Vec<casl2::Statement> {
873 if self.var_total_size > 1 && self.option_initialize_variables {
875 self.load_subroutine(subroutine::Id::UtilFill);
876 }
877 let allocator_code = self
879 .option_local_allocation_size
880 .map(|size| subroutine::get_util_allocator_code(&mut self, size));
881 self.add_debugger_hint(|| "End Sub".to_string());
882 let dbg_cmd = self.get_current_debugger_hint();
883 let Self {
884 for_debug_basic,
885 program_name,
886 arguments,
887 argument_labels,
888 arr_argument_labels,
889 str_argument_labels,
890 callables,
891 bool_var_labels,
892 int_var_labels,
893 str_var_labels,
894 bool_arr_labels,
895 int_arr_labels,
896 lit_str_labels,
897 temp_int_var_labels,
898 save_temp_int_var_labels,
899 temp_str_var_labels,
900 subroutine_codes,
901 mut statements,
902 has_eof,
903 var_total_size,
904 option_restore_registers,
905 option_initialize_variables,
906 option_external_eof,
907 option_use_allocator,
908 allocate_memory_relative_position,
909 allocate_arguments_size,
910 maximum_allocate_temporary_area_size,
911 ..
912 } = self;
913
914 let save_temp_int_var_labels = save_temp_int_var_labels
915 .into_iter()
916 .collect::<BTreeSet<_>>()
917 .into_iter()
918 .collect::<Vec<_>>();
919
920 statements.labeled("EXIT", casl2::Command::Nop);
922
923 if option_use_allocator {
925 statements.comment("Release Memory");
926 statements.code(
927 r#" LAD GR0,1
928 LD GR1,MEM
929 CALL ALLOC
930 POP GR1
931 ST GR1,MEM"#,
932 );
933 }
934
935 if option_use_allocator && !save_temp_int_var_labels.is_empty() {
937 statements.comment("Recover Temporary Values");
938 for label in save_temp_int_var_labels.iter() {
939 statements.code(format!(
940 r#" POP GR0
941 ST GR0,{}"#,
942 label
943 ));
944 }
945 }
946
947 if option_restore_registers {
949 statements.code(casl2::Command::Rpop);
950 }
951
952 if let Some(cmd) = dbg_cmd {
954 statements.code(cmd);
955 }
956
957 statements.code(casl2::Command::Ret);
959
960 if !option_use_allocator {
961 for arg in arguments.iter() {
963 statements.comment(arg.to_string());
964 match arg.var_type {
965 parser::VarType::Boolean
966 | parser::VarType::RefBoolean
967 | parser::VarType::Integer
968 | parser::VarType::RefInteger => {
969 let (label, _) = argument_labels.get(&arg.var_name).unwrap();
970 statements.labeled(label.label(), casl2::Command::Ds { size: 1 });
971 }
972 parser::VarType::RefArrayOfBoolean(_)
973 | parser::VarType::RefArrayOfInteger(_) => {
974 let (label, _) = arr_argument_labels.get(&arg.var_name).unwrap();
975 statements.labeled(label.label(), casl2::Command::Ds { size: 1 });
976 }
977 parser::VarType::ArrayOfBoolean(size)
978 | parser::VarType::ArrayOfInteger(size) => {
979 let (label, _) = arr_argument_labels.get(&arg.var_name).unwrap();
980 statements.labeled(label.label(), casl2::Command::Ds { size: size as u16 });
981 }
982 parser::VarType::String => {
983 let (labels, _) = str_argument_labels.get(&arg.var_name).unwrap();
984 statements.labeled(&labels.len, casl2::Command::Ds { size: 1 });
985 statements.labeled(&labels.pos, casl2::Command::Ds { size: 256 });
986 }
987 parser::VarType::RefString => {
988 let (labels, _) = str_argument_labels.get(&arg.var_name).unwrap();
989 statements.labeled(&labels.len, casl2::Command::Ds { size: 1 });
990 statements.labeled(&labels.pos, casl2::Command::Ds { size: 1 });
991 }
992 }
993 }
994 }
995
996 let mut first_var_label: Option<String> = None;
998
999 if !option_use_allocator {
1000 for (label, var_name) in bool_var_labels
1002 .into_iter()
1003 .map(|(k, v)| (v, k))
1004 .collect::<BTreeSet<_>>()
1005 {
1006 if first_var_label.is_none() {
1007 first_var_label = Some(label.label());
1008 }
1009 statements.comment(format!("Dim {} As Boolean", var_name));
1010 statements.labeled(label.label(), casl2::Command::Ds { size: 1 });
1011 }
1012
1013 for (label, var_name) in int_var_labels
1015 .into_iter()
1016 .map(|(k, v)| (v, k))
1017 .collect::<BTreeSet<_>>()
1018 {
1019 if first_var_label.is_none() {
1020 first_var_label = Some(label.label());
1021 }
1022 statements.comment(format!("Dim {} As Integer", var_name));
1023 statements.labeled(label.label(), casl2::Command::Ds { size: 1 });
1024 }
1025
1026 for (labels, var_name) in str_var_labels
1028 .into_iter()
1029 .map(|(k, v)| (v, k))
1030 .collect::<BTreeSet<_>>()
1031 {
1032 if first_var_label.is_none() {
1033 first_var_label = Some(labels.len.clone());
1034 }
1035 let StrLabels { pos, len, .. } = labels;
1036 statements.comment(format!("Dim {} As String", var_name));
1037 statements.labeled(len, casl2::Command::Ds { size: 1 });
1038 statements.labeled(pos, casl2::Command::Ds { size: 256 });
1039 }
1040
1041 for (label, var_name) in bool_arr_labels
1043 .into_iter()
1044 .map(|(k, v)| (v, k))
1045 .collect::<BTreeSet<_>>()
1046 {
1047 if first_var_label.is_none() {
1048 first_var_label = Some(label.label());
1049 }
1050 statements.comment(format!("Dim {}({}) As Boolean", var_name, label.size() - 1));
1051 statements.labeled(
1052 label.label(),
1053 casl2::Command::Ds {
1054 size: label.size() as u16,
1055 },
1056 );
1057 }
1058
1059 for (label, var_name) in int_arr_labels
1061 .into_iter()
1062 .map(|(k, v)| (v, k))
1063 .collect::<BTreeSet<_>>()
1064 {
1065 if first_var_label.is_none() {
1066 first_var_label = Some(label.label());
1067 }
1068 statements.comment(format!("Dim {}({}) As Integer", var_name, label.size() - 1));
1069 statements.labeled(
1070 label.label(),
1071 casl2::Command::Ds {
1072 size: label.size() as u16,
1073 },
1074 );
1075 }
1076 }
1077
1078 if has_eof && !option_external_eof {
1080 statements.labeled("EOF", casl2::Command::Ds { size: 1 });
1081 }
1082
1083 if option_use_allocator {
1085 statements.labeled("MEM", casl2::Command::Ds { size: 1 });
1086 }
1087
1088 let mut temp_statements = Vec::<casl2::Statement>::new();
1090
1091 if let Some(name) = program_name {
1093 temp_statements.code(casl2::Statement::Code {
1094 label: Some(name.into()),
1095 command: casl2::Command::Start { entry_point: None },
1096 comment: None,
1097 });
1098 } else {
1099 let mut name = "MAIN".to_string();
1100 if callables.contains_key(&name) {
1101 for i in 0.. {
1102 name = format!("MAIN{}", i);
1103 if !callables.contains_key(&name) {
1104 break;
1105 }
1106 }
1107 }
1108 temp_statements.code(casl2::Statement::Code {
1109 label: Some(name.into()),
1110 command: casl2::Command::Start { entry_point: None },
1111 comment: None,
1112 });
1113 }
1114
1115 if for_debug_basic {
1117 temp_statements.code(casl2::Command::DebugBasicStep { id: 0 });
1118 }
1119
1120 if option_restore_registers {
1122 temp_statements.code(casl2::Command::Rpush);
1123 }
1124
1125 if option_use_allocator && !save_temp_int_var_labels.is_empty() {
1126 let use_gr7 = arguments.iter().any(|arg| {
1128 matches!(arg.register1, casl2::IndexRegister::Gr7)
1129 || matches!(arg.register2, Some(casl2::IndexRegister::Gr7))
1130 });
1131 temp_statements.comment("Save Temporary Values");
1132 if use_gr7 {
1133 temp_statements.code(" LD GR0,GR7");
1134 }
1135 let mut save_temp_int_var_labels = save_temp_int_var_labels;
1136 while let Some(label) = save_temp_int_var_labels.pop() {
1137 temp_statements.code(format!(
1138 r#" LD GR7,{}
1139 PUSH 0,GR7"#,
1140 label
1141 ));
1142 }
1143 if use_gr7 {
1144 temp_statements.code(" LD GR7,GR0");
1145 }
1146 }
1147
1148 if option_use_allocator {
1149 let use_gr1 = arguments.iter().any(|arg| {
1151 matches!(arg.register1, casl2::IndexRegister::Gr1)
1152 || matches!(arg.register2, Some(casl2::IndexRegister::Gr1))
1153 });
1154 temp_statements.comment("Allocate Memory");
1155 if use_gr1 {
1156 temp_statements.code(
1157 r#" LD GR0,GR1
1158 LD GR1,MEM
1159 PUSH 0,GR1
1160 LD GR1,GR0
1161 PUSH 0,GR1"#,
1162 );
1163 } else {
1164 temp_statements.code(
1165 r#" LD GR1,MEM
1166 PUSH 0,GR1"#,
1167 );
1168 }
1169 let size = allocate_memory_relative_position + maximum_allocate_temporary_area_size;
1170 temp_statements.code(format!(
1171 r#" XOR GR0,GR0
1172 LAD GR1,{size}
1173 CALL ALLOC
1174 ST GR0,MEM"#,
1175 size = size
1176 ));
1177 if use_gr1 {
1178 temp_statements.code(" POP GR1");
1179 }
1180 }
1181
1182 let mut idle_register = {
1183 use casl2::IndexRegister::*;
1184 let mut regs = vec![Gr1, Gr2, Gr3, Gr4, Gr5, Gr6, Gr7];
1185 for arg in arguments.iter() {
1186 regs.retain(|r| *r != arg.register1);
1187 if let Some(r2) = arg.register2 {
1188 regs.retain(|r| *r != r2);
1189 }
1190 }
1191 regs.pop()
1192 };
1193
1194 for arg in arguments.iter() {
1196 temp_statements.comment(format!("Argument {}", arg.var_name));
1197 match arg.var_type {
1198 parser::VarType::Boolean
1199 | parser::VarType::RefBoolean
1200 | parser::VarType::Integer
1201 | parser::VarType::RefInteger => {
1202 let (label, _) = argument_labels.get(&arg.var_name).unwrap();
1203 if option_use_allocator {
1204 if let Some(reg) = idle_register {
1205 temp_statements.code(format!(
1206 r#" LD {reg},MEM
1207 LAD {reg},{offset},{reg}
1208 ST {arg},0,{reg}"#,
1209 reg = reg,
1210 offset = label.get_offset().unwrap(),
1211 arg = arg.register1
1212 ));
1213 } else {
1214 temp_statements.code(format!(
1215 r#" LD GR0,{reg}
1216 LD {reg},MEM
1217 LAD {reg},{offset},{reg}
1218 ST GR0,0,{reg}"#,
1219 reg = arg.register1,
1220 offset = label.get_offset().unwrap()
1221 ));
1222 idle_register = Some(arg.register1);
1223 }
1224 } else {
1225 temp_statements.code(format!(
1226 r#" ST {reg},{label}"#,
1227 reg = arg.register1,
1228 label = label.label()
1229 ));
1230 }
1231 }
1232 parser::VarType::RefArrayOfBoolean(_)
1233 | parser::VarType::ArrayOfBoolean(_)
1234 | parser::VarType::ArrayOfInteger(_)
1235 | parser::VarType::RefArrayOfInteger(_) => {
1236 let (label, _) = arr_argument_labels.get(&arg.var_name).unwrap();
1237 if option_use_allocator {
1238 if let Some(reg) = idle_register {
1239 temp_statements.code(format!(
1240 r#" LD {reg},MEM
1241 LAD {reg},{offset},{reg}
1242 ST {arg},0,{reg}"#,
1243 reg = reg,
1244 offset = label.get_offset().unwrap(),
1245 arg = arg.register1
1246 ));
1247 } else {
1248 temp_statements.code(format!(
1249 r#" LD GR0,{reg}
1250 LD {reg},MEM
1251 LAD {reg},{offset},{reg}
1252 ST GR0,0,{reg}"#,
1253 reg = arg.register1,
1254 offset = label.get_offset().unwrap()
1255 ));
1256 idle_register = Some(arg.register1);
1257 }
1258 } else {
1259 temp_statements.code(format!(
1260 r#" ST {reg},{label}"#,
1261 reg = arg.register1,
1262 label = label.label()
1263 ));
1264 }
1265 }
1266 parser::VarType::String | parser::VarType::RefString => {
1267 let (labels, _) = str_argument_labels.get(&arg.var_name).unwrap();
1268 if option_use_allocator {
1269 if let Some(reg) = idle_register {
1270 temp_statements.code(format!(
1271 r#" LD {reg},MEM
1272 LAD {reg},{lenoff},{reg}
1273 ST {reglen},0,{reg}
1274 ST {regpos},1,{reg}"#,
1275 lenoff = labels.get_offset().unwrap(),
1276 reglen = arg.register1,
1277 reg = reg,
1278 regpos = arg.register2.unwrap()
1279 ));
1280 } else {
1281 let reg = arg.register1;
1282 temp_statements.code(format!(
1283 r#" LD GR0,{reg}
1284 LD {reg},MEM
1285 LAD {reg},{lenoff},{reg}
1286 ST GR0,0,{reg}
1287 ST {regpos},1,{reg}"#,
1288 lenoff = labels.get_offset().unwrap(),
1289 reg = reg,
1290 regpos = arg.register2.unwrap()
1291 ));
1292 idle_register = Some(reg);
1293 }
1294 } else {
1295 temp_statements.code(format!(
1296 r#" ST {reglen},{len}
1297 ST {regpos},{pos}"#,
1298 reglen = arg.register1,
1299 len = labels.len,
1300 regpos = arg.register2.unwrap(),
1301 pos = labels.pos
1302 ));
1303 }
1304 }
1305 }
1306 }
1307
1308 for arg in arguments.iter() {
1310 match arg.var_type {
1311 parser::VarType::Boolean
1312 | parser::VarType::RefBoolean
1313 | parser::VarType::Integer
1314 | parser::VarType::RefInteger
1315 | parser::VarType::RefArrayOfBoolean(_)
1316 | parser::VarType::RefArrayOfInteger(_)
1317 | parser::VarType::RefString => {}
1318
1319 parser::VarType::ArrayOfBoolean(size) | parser::VarType::ArrayOfInteger(size) => {
1320 temp_statements.comment(format!("Copy Into {}", arg.var_name));
1321 let (label, _) = arr_argument_labels.get(&arg.var_name).unwrap();
1322 if option_use_allocator {
1323 temp_statements.code(format!(
1324 r#" LD GR1,MEM
1325 LAD GR1,{offset},GR1
1326 LD GR2,GR1
1327 LD GR3,0,GR1
1328 LAD GR4,{size}
1329 CALL {copy}"#,
1330 offset = label.get_offset().unwrap(),
1331 size = size,
1332 copy = subroutine::Id::UtilCopyStr.label()
1333 ));
1334 } else {
1335 temp_statements.code(format!(
1336 r#" LAD GR1,{label}
1337 LD GR2,GR1
1338 LD GR3,0,GR1
1339 LAD GR4,{size}
1340 CALL {copy}"#,
1341 label = label.label(),
1342 size = size,
1343 copy = subroutine::Id::UtilCopyStr.label()
1344 ));
1345 }
1346 }
1347 parser::VarType::String => {
1348 temp_statements.comment(format!("Copy Into {}", arg.var_name));
1349 let (labels, _) = str_argument_labels.get(&arg.var_name).unwrap();
1350 if option_use_allocator {
1351 temp_statements.code(format!(
1352 r#" LD GR2,MEM
1353 LAD GR2,{offset},GR2
1354 LAD GR1,1,GR2
1355 LD GR3,0,GR1
1356 LD GR4,0,GR2
1357 CALL {copy}"#,
1358 offset = labels.get_offset().unwrap(),
1359 copy = subroutine::Id::UtilCopyStr.label()
1360 ));
1361 } else {
1362 temp_statements.code(format!(
1363 r#" LAD GR1,{pos}
1364 LAD GR2,{len}
1365 LD GR3,0,GR1
1366 LD GR4,0,GR2
1367 CALL {copy}"#,
1368 pos = labels.pos,
1369 len = labels.len,
1370 copy = subroutine::Id::UtilCopyStr.label()
1371 ));
1372 }
1373 }
1374 }
1375 }
1376
1377 if option_initialize_variables {
1379 if option_use_allocator {
1380 use std::cmp::Ordering;
1381 match var_total_size.cmp(&1) {
1382 Ordering::Equal => {
1383 temp_statements.comment("Init Variable");
1384 temp_statements.code(format!(
1385 r#" XOR GR0,GR0
1386 LD GR1,MEM
1387 LAD GR1,{offset},GR1
1388 ST GR0,0,GR1"#,
1389 offset = allocate_arguments_size
1390 ));
1391 }
1392 Ordering::Greater => {
1393 temp_statements.comment("Init Variables");
1394 temp_statements.code(format!(
1395 r#" LD GR1,MEM
1396 LAD GR1,{offset},GR1
1397 XOR GR2,GR2
1398 LAD GR3,{size}
1399 CALL {fill}"#,
1400 offset = allocate_arguments_size,
1401 size = var_total_size,
1402 fill = subroutine::Id::UtilFill.label()
1403 ));
1404 }
1405 _ => {}
1406 }
1407 } else {
1408 match first_var_label {
1409 Some(label) if var_total_size == 1 => {
1410 temp_statements.comment("Init Variable");
1411 temp_statements.extend(
1412 casl2::parse(&format!(
1413 r#" XOR GR0,GR0
1414 ST GR0,{label}"#,
1415 label = label
1416 ))
1417 .unwrap(),
1418 );
1419 }
1420 Some(label) => {
1421 temp_statements.comment("Init Variables");
1422 temp_statements.extend(
1423 casl2::parse(&format!(
1424 r#" LAD GR1,{start}
1425 XOR GR2,GR2
1426 LAD GR3,{size}
1427 CALL {fill}"#,
1428 start = label,
1429 size = var_total_size,
1430 fill = subroutine::Id::UtilFill.label()
1431 ))
1432 .unwrap(),
1433 );
1434 }
1435 _ => {}
1436 }
1437 }
1438 }
1439
1440 temp_statements.extend(statements);
1442 let mut statements = temp_statements;
1443
1444 let mut temp_int_var_labels = temp_int_var_labels;
1446 while let Some(Reverse(label)) = temp_int_var_labels.pop() {
1447 statements.labeled(label, casl2::Command::Ds { size: 1 });
1448 }
1449
1450 let mut temp_str_var_labels = temp_str_var_labels;
1452 while let Some(Reverse(labels)) = temp_str_var_labels.pop() {
1453 let StrLabels { pos, len, .. } = labels;
1454 statements.labeled(len, casl2::Command::Ds { size: 1 });
1455 statements.labeled(pos, casl2::Command::Ds { size: 256 });
1456 }
1457
1458 for (labels, literal) in lit_str_labels
1460 .into_iter()
1461 .map(|(k, v)| (v, k))
1462 .collect::<BTreeSet<_>>()
1463 {
1464 let StrLabels { pos, len, .. } = labels;
1465 statements.labeled(
1466 len,
1467 casl2::Command::Dc {
1468 constants: vec![casl2::Constant::Dec(literal.chars().count() as i16)],
1469 },
1470 );
1471 if literal.is_empty() {
1472 statements.labeled(pos, casl2::Command::Ds { size: 0 });
1473 } else {
1474 statements.labeled(
1475 pos,
1476 casl2::Command::Dc {
1477 constants: vec![casl2::Constant::Str(literal.clone())],
1478 },
1479 );
1480 }
1481 }
1482
1483 if let Some(src) = allocator_code {
1485 statements.code(src);
1486 }
1487
1488 for (_, code) in subroutine_codes.into_iter().collect::<BTreeMap<_, _>>() {
1490 statements.code(code);
1491 }
1492
1493 statements.code(casl2::Command::End);
1495
1496 statements
1497 }
1498}
1499
1500impl Compiler {
1502 fn compile(&mut self, stmt: &parser::Statement) {
1504 use parser::Statement::*;
1505 match stmt {
1506 CompileOption { option } => self.set_option(option),
1507 ProgramName { name } => self.compile_program_name(name),
1508 Argument { arguments } => self.compile_argument(arguments),
1509 Call { name, arguments } => self.compile_call_exterun_sub(name, arguments),
1510 ExitProgram => self.compile_exit_program(),
1511 ExternSub { name, arguments } => self.compile_extern_sub(name, arguments),
1512 AssignAddInto { var_name, value } => self.compile_assign_add_into(var_name, value),
1513 AssignRefAddInto { var_name, value } => {
1514 self.compile_assign_ref_add_into(var_name, value)
1515 }
1516 AssignAddIntoElement {
1517 var_name,
1518 index,
1519 value,
1520 } => self.compile_assign_add_into_element(var_name, index, value),
1521 AssignRefAddIntoElement {
1522 var_name,
1523 index,
1524 value,
1525 } => self.compile_assign_ref_add_into_element(var_name, index, value),
1526 AssignBoolean { var_name, value } => self.compile_assign_boolean(var_name, value),
1527 AssignRefBoolean { var_name, value } => {
1528 self.compile_assign_ref_boolean(var_name, value)
1529 }
1530 AssignBooleanElement {
1531 var_name,
1532 index,
1533 value,
1534 } => self.compile_assign_boolean_element(var_name, index, value),
1535 AssignRefBooleanElement {
1536 var_name,
1537 index,
1538 value,
1539 } => self.compile_assign_ref_boolean_element(var_name, index, value),
1540 AssignIntegerElement {
1541 var_name,
1542 index,
1543 value,
1544 } => self.compile_assign_integer_element(var_name, index, value),
1545 AssignRefIntegerElement {
1546 var_name,
1547 index,
1548 value,
1549 } => self.compile_assign_ref_integer_element(var_name, index, value),
1550 AssignCharacterElement {
1551 var_name,
1552 index,
1553 value,
1554 } => self.compile_assign_character_element(var_name, index, value),
1555 AssignRefCharacterElement {
1556 var_name,
1557 index,
1558 value,
1559 } => self.compile_assign_ref_character_element(var_name, index, value),
1560 AssignInteger { var_name, value } => self.compile_assign_integer(var_name, value),
1561 AssignRefInteger { var_name, value } => {
1562 self.compile_assign_ref_integer(var_name, value)
1563 }
1564 AssignString { var_name, value } => self.compile_assign_string(var_name, value),
1565 AssignRefString { var_name, value } => self.compile_assign_ref_string(var_name, value),
1566 AssignSubInto { var_name, value } => self.compile_assign_sub_into(var_name, value),
1567 AssignRefSubInto { var_name, value } => {
1568 self.compile_assign_ref_sub_into(var_name, value)
1569 }
1570 AssignSubIntoElement {
1571 var_name,
1572 index,
1573 value,
1574 } => self.compile_assign_sub_into_element(var_name, index, value),
1575 AssignRefSubIntoElement {
1576 var_name,
1577 index,
1578 value,
1579 } => self.compile_assign_ref_sub_into_element(var_name, index, value),
1580 AssignBooleanArray { var_name, value } => {
1581 self.compile_assign_boolean_array(var_name, value)
1582 }
1583 AssignRefBooleanArray { var_name, value } => {
1584 self.compile_assign_ref_boolean_array(var_name, value)
1585 }
1586 AssignIntegerArray { var_name, value } => {
1587 self.compile_assign_integer_array(var_name, value)
1588 }
1589 AssignRefIntegerArray { var_name, value } => {
1590 self.compile_assign_ref_integer_array(var_name, value)
1591 }
1592 ContinueDo { exit_id } => self.compile_continue_loop(*exit_id, "Do"),
1593 ContinueFor { exit_id } => self.compile_continue_loop(*exit_id, "For"),
1594 Dim { var_name, var_type } => self.compile_dim(var_name, var_type),
1595 Mid {
1596 var_name,
1597 var_is_ref,
1598 offset,
1599 length,
1600 value,
1601 } => self.compile_mid(var_name, *var_is_ref, offset, length, value),
1602 DoLoop { exit_id, block } => self.compile_do_loop(*exit_id, block),
1603 DoLoopUntil {
1604 exit_id,
1605 condition,
1606 block,
1607 } => self.compile_do_loop_until(*exit_id, condition, block),
1608 DoLoopWhile {
1609 exit_id,
1610 condition,
1611 block,
1612 } => self.compile_do_loop_while(*exit_id, condition, block),
1613 DoUntilLoop {
1614 exit_id,
1615 condition,
1616 block,
1617 } => self.compile_do_until_loop(*exit_id, condition, block),
1618 DoWhileLoop {
1619 exit_id,
1620 condition,
1621 block,
1622 } => self.compile_do_while_loop(*exit_id, condition, block),
1623 ExitDo { exit_id } => self.compile_exit_block(*exit_id, "Do"),
1624 ExitFor { exit_id } => self.compile_exit_block(*exit_id, "For"),
1625 ExitSelect { exit_id } => self.compile_exit_block(*exit_id, "Select"),
1626 For { step: None, .. } => self.compile_for_with_literal_step(stmt, 1),
1627 For {
1628 step: Some(parser::Expr::LitInteger(step)),
1629 ..
1630 } => self.compile_for_with_literal_step(stmt, *step),
1631 For { .. } => self.compile_for(stmt),
1632 If {
1633 condition,
1634 block,
1635 else_blocks,
1636 } => self.compile_if(condition, block, else_blocks),
1637 SelectInteger {
1638 exit_id,
1639 value,
1640 case_blocks,
1641 } => self.compile_select_integer(*exit_id, value, case_blocks),
1642 SelectString {
1643 exit_id,
1644 value,
1645 case_blocks,
1646 } => self.compile_select_string(*exit_id, value, case_blocks),
1647 InputElementInteger { var_name, index } => {
1648 self.compile_input_element_integer(var_name, index)
1649 }
1650 InputInteger { var_name } => self.compile_input_integer(var_name),
1651 InputString { var_name } => self.compile_input_string(var_name),
1652 InputRefElementInteger { var_name, index } => {
1653 self.compile_input_ref_element_integer(var_name, index)
1654 }
1655 InputRefInteger { var_name } => self.compile_input_ref_integer(var_name),
1656 InputRefString { var_name } => self.compile_input_ref_string(var_name),
1657 PrintLitBoolean { value } => self.compile_print_lit_boolean(*value),
1658 PrintLitInteger { value } => self.compile_print_lit_integer(*value),
1659 PrintLitString { value } => self.compile_print_lit_string(value),
1660 PrintVarString { var_name } => self.compile_print_var_string(var_name),
1661 PrintExprBoolan { value } => self.compile_print_expr_boolean(value),
1662 PrintExprInteger { value } => self.compile_print_expr_integer(value),
1663 PrintExprString { value } => self.compile_print_expr_string(value),
1664 FillArrayOfBoolean { var_name, value } => {
1665 self.compile_fill_boolean_array(var_name, value)
1666 }
1667 FillRefArrayOfBoolean { var_name, value } => {
1668 self.compile_fill_ref_boolean_array(var_name, value)
1669 }
1670 FillArrayOfInteger { var_name, value } => {
1671 self.compile_fill_integer_array(var_name, value)
1672 }
1673 FillRefArrayOfInteger { var_name, value } => {
1674 self.compile_fill_ref_integer_array(var_name, value)
1675 }
1676 FillString { var_name, value } => self.compile_fill_string(var_name, value),
1677 FillRefString { var_name, value } => self.compile_fill_ref_string(var_name, value),
1678
1679 ElseIf { .. }
1681 | Else { .. }
1682 | CaseInteger { .. }
1683 | CaseString { .. }
1684 | CaseElse { .. } => unreachable!("BUG"),
1685
1686 ProvisionalDo { .. }
1688 | ProvisionalFor { .. }
1689 | ProvitionalIf { .. }
1690 | ProvisionalElseIf { .. }
1691 | ProvisionalElse
1692 | ProvisionalSelectInteger { .. }
1693 | ProvisionalCaseInteger { .. }
1694 | ProvisionalSelectString { .. }
1695 | ProvisionalCaseString { .. }
1696 | ProvisionalCaseElse => unreachable!("BUG"),
1697 }
1698 }
1699}
1700
1701impl ArrayLabel {
1702 fn label(&self) -> String {
1703 use ArrayLabel::*;
1704 match self {
1705 TempArrayOfBoolean(labels, _) | TempArrayOfInteger(labels, _) => labels.pos.clone(),
1706 VarArrayOfBoolean(label, _)
1707 | VarArrayOfInteger(label, _)
1708 | VarRefArrayOfBoolean(label, _)
1709 | VarRefArrayOfInteger(label, _) => label.clone(),
1710
1711 MemArrayOfBoolean { .. }
1712 | MemArrayOfInteger { .. }
1713 | MemRefArrayOfBoolean { .. }
1714 | MemRefArrayOfInteger { .. } => unreachable!("BUG"),
1715 }
1716 }
1717
1718 fn ld_first_elem(&self, reg: casl2::Register) -> String {
1719 use ArrayLabel::*;
1720 match self {
1721 TempArrayOfBoolean(labels, _) | TempArrayOfInteger(labels, _) => {
1722 format!(r#" LD {reg},{pos}"#, reg = reg, pos = labels.pos)
1723 }
1724 VarArrayOfBoolean(label, _) | VarArrayOfInteger(label, _) => {
1725 format!(r#" LD {reg},{pos}"#, reg = reg, pos = label)
1726 }
1727 VarRefArrayOfBoolean(label, _) | VarRefArrayOfInteger(label, _) => {
1728 format!(
1729 r#" LD {reg},{pos}
1730 LD {reg},0,{reg}"#,
1731 reg = reg,
1732 pos = label
1733 )
1734 }
1735 MemArrayOfBoolean { offset, .. } | MemArrayOfInteger { offset, .. } => {
1736 format!(
1737 r#" LD {reg},MEM
1738 LD {reg},{offset},{reg}"#,
1739 reg = reg,
1740 offset = offset
1741 )
1742 }
1743 MemRefArrayOfBoolean { offset, .. } | MemRefArrayOfInteger { offset, .. } => {
1744 format!(
1745 r#" LD {reg},MEM
1746 LD {reg},{offset},{reg}
1747 LD {reg},0,{reg}"#,
1748 reg = reg,
1749 offset = offset
1750 )
1751 }
1752 }
1753 }
1754
1755 fn st_first_elem(&self, value: casl2::Register, extra: casl2::Register) -> String {
1756 use ArrayLabel::*;
1757 match self {
1758 TempArrayOfBoolean(labels, _) | TempArrayOfInteger(labels, _) => {
1759 format!(r#" ST {value},{pos}"#, value = value, pos = labels.pos)
1760 }
1761 VarArrayOfBoolean(label, _) | VarArrayOfInteger(label, _) => {
1762 format!(r#" ST {value},{pos}"#, value = value, pos = label)
1763 }
1764 VarRefArrayOfBoolean(label, _) | VarRefArrayOfInteger(label, _) => {
1765 assert!(!matches!(extra, casl2::Register::Gr0));
1766 format!(
1767 r#" LD {reg},{pos}
1768 ST {value},0,{reg}"#,
1769 value = value,
1770 reg = extra,
1771 pos = label
1772 )
1773 }
1774 MemArrayOfBoolean { offset, .. } | MemArrayOfInteger { offset, .. } => {
1775 assert!(!matches!(extra, casl2::Register::Gr0));
1776 format!(
1777 r#" LD {reg},MEM
1778 ST {value},{offset},{reg}"#,
1779 reg = extra,
1780 value = value,
1781 offset = offset
1782 )
1783 }
1784 MemRefArrayOfBoolean { offset, .. } | MemRefArrayOfInteger { offset, .. } => {
1785 assert!(!matches!(extra, casl2::Register::Gr0));
1786 format!(
1787 r#" LD {reg},MEM
1788 LD {reg},{offset},{reg}
1789 ST {value},0,{reg}"#,
1790 reg = extra,
1791 value = value,
1792 offset = offset
1793 )
1794 }
1795 }
1796 }
1797
1798 fn lad_pos(&self, reg: casl2::Register) -> String {
1799 use ArrayLabel::*;
1800 match self {
1801 TempArrayOfBoolean(labels, _) | TempArrayOfInteger(labels, _) => {
1802 format!(r#" LAD {reg},{pos}"#, reg = reg, pos = labels.pos)
1803 }
1804 VarArrayOfBoolean(label, _) | VarArrayOfInteger(label, _) => {
1805 format!(r#" LAD {reg},{pos}"#, reg = reg, pos = label)
1806 }
1807 VarRefArrayOfBoolean(label, _) | VarRefArrayOfInteger(label, _) => {
1808 format!(r#" LD {reg},{pos}"#, reg = reg, pos = label)
1809 }
1810 MemArrayOfBoolean { offset, .. } | MemArrayOfInteger { offset, .. } => {
1811 assert!(!matches!(reg, casl2::Register::Gr0));
1812 format!(
1813 r#" LD {reg},MEM
1814 LAD {reg},{offset},{reg}"#,
1815 reg = reg,
1816 offset = offset
1817 )
1818 }
1819 MemRefArrayOfBoolean { offset, .. } | MemRefArrayOfInteger { offset, .. } => {
1820 assert!(!matches!(reg, casl2::Register::Gr0));
1821 format!(
1822 r#" LD {reg},MEM
1823 LD {reg},{offset},{reg}"#,
1824 reg = reg,
1825 offset = offset
1826 )
1827 }
1828 }
1829 }
1830
1831 pub fn size(&self) -> usize {
1832 use ArrayLabel::*;
1833 match self {
1834 TempArrayOfBoolean(_, size)
1835 | TempArrayOfInteger(_, size)
1836 | VarArrayOfBoolean(_, size)
1837 | VarArrayOfInteger(_, size)
1838 | VarRefArrayOfBoolean(_, size)
1839 | VarRefArrayOfInteger(_, size)
1840 | MemArrayOfBoolean { size, .. }
1841 | MemArrayOfInteger { size, .. }
1842 | MemRefArrayOfBoolean { size, .. }
1843 | MemRefArrayOfInteger { size, .. } => *size,
1844 }
1845 }
1846
1847 fn release(self) -> Option<StrLabels> {
1848 use ArrayLabel::*;
1849 match self {
1850 TempArrayOfBoolean(labels, _) | TempArrayOfInteger(labels, _) => Some(labels),
1851
1852 VarArrayOfBoolean(..)
1853 | VarArrayOfInteger(..)
1854 | VarRefArrayOfBoolean(..)
1855 | VarRefArrayOfInteger(..)
1856 | MemArrayOfBoolean { .. }
1857 | MemArrayOfInteger { .. }
1858 | MemRefArrayOfBoolean { .. }
1859 | MemRefArrayOfInteger { .. } => None,
1860 }
1861 }
1862
1863 fn element_type(&self) -> parser::ExprType {
1864 use ArrayLabel::*;
1865 match self {
1866 TempArrayOfBoolean(..)
1867 | VarArrayOfBoolean(..)
1868 | VarRefArrayOfBoolean(..)
1869 | MemArrayOfBoolean { .. }
1870 | MemRefArrayOfBoolean { .. } => parser::ExprType::Boolean,
1871
1872 TempArrayOfInteger(..)
1873 | VarArrayOfInteger(..)
1874 | VarRefArrayOfInteger(..)
1875 | MemArrayOfInteger { .. }
1876 | MemRefArrayOfInteger { .. } => parser::ExprType::Integer,
1877 }
1878 }
1879
1880 fn get_offset(&self) -> Option<usize> {
1881 use ArrayLabel::*;
1882 match self {
1883 TempArrayOfBoolean(..)
1884 | VarArrayOfBoolean(..)
1885 | VarRefArrayOfBoolean(..)
1886 | TempArrayOfInteger(..)
1887 | VarArrayOfInteger(..)
1888 | VarRefArrayOfInteger(..) => None,
1889
1890 MemArrayOfBoolean { offset, .. }
1891 | MemRefArrayOfBoolean { offset, .. }
1892 | MemArrayOfInteger { offset, .. }
1893 | MemRefArrayOfInteger { offset, .. } => Some(*offset),
1894 }
1895 }
1896}
1897
1898impl StrLabels {
1899 fn lad_pos(&self, reg: casl2::Register) -> String {
1900 match &self.label_type {
1901 StrLabelType::Const(_)
1902 | StrLabelType::Lit(_)
1903 | StrLabelType::Temp
1904 | StrLabelType::Var
1905 | StrLabelType::ArgVal => {
1906 format!(r#" LAD {reg},{pos}"#, reg = reg, pos = self.pos)
1907 }
1908 StrLabelType::ArgRef => {
1909 format!(r#" LD {reg},{pos}"#, reg = reg, pos = self.pos)
1910 }
1911 StrLabelType::MemVal(offset) => {
1912 format!(
1913 r#" LD {reg},MEM
1914 LAD {reg},{offset},{reg}"#,
1915 reg = reg,
1916 offset = *offset + 1
1917 )
1918 }
1919 StrLabelType::MemRef(offset) => {
1920 format!(
1921 r#" LD {reg},MEM
1922 LD {reg},{offset},{reg}"#,
1923 reg = reg,
1924 offset = *offset + 1
1925 )
1926 }
1927 }
1928 }
1929
1930 fn lad_len(&self, reg: casl2::Register) -> String {
1931 match &self.label_type {
1932 StrLabelType::Const(_)
1933 | StrLabelType::Lit(_)
1934 | StrLabelType::Temp
1935 | StrLabelType::Var
1936 | StrLabelType::ArgVal => {
1937 format!(r#" LAD {reg},{len}"#, reg = reg, len = self.len)
1938 }
1939 StrLabelType::ArgRef => {
1940 format!(r#" LD {reg},{len}"#, reg = reg, len = self.len)
1941 }
1942 StrLabelType::MemVal(offset) => {
1943 format!(
1944 r#" LD {reg},MEM
1945 LAD {reg},{offset},{reg}"#,
1946 reg = reg,
1947 offset = *offset
1948 )
1949 }
1950 StrLabelType::MemRef(offset) => {
1951 format!(
1952 r#" LD {reg},MEM
1953 LD {reg},{offset},{reg}"#,
1954 reg = reg,
1955 offset = *offset
1956 )
1957 }
1958 }
1959 }
1960
1961 fn ld_len(&self, reg: casl2::Register) -> String {
1962 match &self.label_type {
1963 StrLabelType::Const(s) | StrLabelType::Lit(s) => {
1964 if s.is_empty() {
1965 format!(r#" XOR {reg},{reg}"#, reg = reg)
1966 } else {
1967 format!(r#" LAD {reg},{len}"#, reg = reg, len = s.chars().count())
1968 }
1969 }
1970 StrLabelType::Temp | StrLabelType::Var | StrLabelType::ArgVal => {
1971 format!(r#" LD {reg},{len}"#, reg = reg, len = self.len)
1972 }
1973 StrLabelType::ArgRef => {
1974 assert!(!matches!(reg, casl2::Register::Gr0));
1975 format!(
1976 r#" LD {reg},{len}
1977 LD {reg},0,{reg}"#,
1978 reg = reg,
1979 len = self.len
1980 )
1981 }
1982 StrLabelType::MemVal(offset) => {
1983 format!(
1984 r#" LD {reg},MEM
1985 LD {reg},{offset},{reg}"#,
1986 reg = reg,
1987 offset = *offset
1988 )
1989 }
1990 StrLabelType::MemRef(offset) => {
1991 format!(
1992 r#" LD {reg},MEM
1993 LD {reg},{offset},{reg}
1994 LD {reg},0,{reg}"#,
1995 reg = reg,
1996 offset = *offset
1997 )
1998 }
1999 }
2000 }
2001
2002 fn get_offset(&self) -> Option<usize> {
2003 match &self.label_type {
2004 StrLabelType::Const(_)
2005 | StrLabelType::Lit(_)
2006 | StrLabelType::Temp
2007 | StrLabelType::Var
2008 | StrLabelType::ArgVal
2009 | StrLabelType::ArgRef => None,
2010
2011 StrLabelType::MemVal(offset) | StrLabelType::MemRef(offset) => Some(*offset),
2012 }
2013 }
2014}
2015
2016impl ValueLabel {
2017 pub fn label(&self) -> String {
2018 match self {
2019 Self::VarBoolean(label)
2020 | Self::VarInteger(label)
2021 | Self::VarRefBoolean(label)
2022 | Self::VarRefInteger(label) => label.clone(),
2023
2024 Self::MemBoolean(..)
2025 | Self::MemInteger(..)
2026 | Self::MemRefBoolean(..)
2027 | Self::MemRefInteger(..) => unreachable!("BUG"),
2028 }
2029 }
2030
2031 fn lad_pos(&self, reg: casl2::Register) -> String {
2032 match self {
2033 Self::VarBoolean(label) | Self::VarInteger(label) => {
2034 format!(" LAD {reg},{label}", reg = reg, label = label)
2035 }
2036 Self::VarRefBoolean(label) | Self::VarRefInteger(label) => {
2037 format!(" LD {reg},{label}", reg = reg, label = label)
2038 }
2039 Self::MemBoolean(offset) | Self::MemInteger(offset) => {
2040 assert!(!matches!(reg, casl2::Register::Gr0));
2041 format!(
2042 r#" LD {reg},MEM
2043 LAD {reg},{offset},{reg}"#,
2044 reg = reg,
2045 offset = offset
2046 )
2047 }
2048 Self::MemRefBoolean(offset) | Self::MemRefInteger(offset) => {
2049 assert!(!matches!(reg, casl2::Register::Gr0));
2050 format!(
2051 r#" LD {reg},MEM
2052 LD {reg},{offset},{reg}"#,
2053 reg = reg,
2054 offset = offset
2055 )
2056 }
2057 }
2058 }
2059
2060 fn ld_value(&self, reg: casl2::Register) -> String {
2061 match self {
2062 Self::VarBoolean(label) | Self::VarInteger(label) => {
2063 format!(" LD {reg},{label}", reg = reg, label = label)
2064 }
2065 Self::VarRefBoolean(label) | Self::VarRefInteger(label) => {
2066 assert!(!matches!(reg, casl2::Register::Gr0));
2067 format!(
2068 r#" LD {reg},{label}
2069 LD {reg},0,{reg}"#,
2070 reg = reg,
2071 label = label
2072 )
2073 }
2074 Self::MemBoolean(offset) | Self::MemInteger(offset) => {
2075 assert!(!matches!(reg, casl2::Register::Gr0));
2076 format!(
2077 r#" LD {reg},MEM
2078 LD {reg},{offset},{reg}"#,
2079 reg = reg,
2080 offset = offset
2081 )
2082 }
2083 Self::MemRefBoolean(offset) | Self::MemRefInteger(offset) => {
2084 assert!(!matches!(reg, casl2::Register::Gr0));
2085 format!(
2086 r#" LD {reg},MEM
2087 LD {reg},{offset},{reg}
2088 LD {reg},0,{reg}"#,
2089 reg = reg,
2090 offset = offset
2091 )
2092 }
2093 }
2094 }
2095
2096 fn st_value(&self, value: casl2::Register, extra: casl2::Register) -> String {
2097 match self {
2098 Self::VarBoolean(label) | Self::VarInteger(label) => {
2099 format!(" ST {value},{label}", value = value, label = label)
2100 }
2101 Self::VarRefBoolean(label) | Self::VarRefInteger(label) => {
2102 assert!(!matches!(extra, casl2::Register::Gr0));
2103 format!(
2104 r#" LD {extra},{label}
2105 ST {value},0,{extra}"#,
2106 extra = extra,
2107 label = label,
2108 value = value
2109 )
2110 }
2111 Self::MemBoolean(offset) | Self::MemInteger(offset) => {
2112 assert!(!matches!(extra, casl2::Register::Gr0));
2113 format!(
2114 r#" LD {extra},MEM
2115 ST {value},{offset},{extra}"#,
2116 extra = extra,
2117 value = value,
2118 offset = offset
2119 )
2120 }
2121 Self::MemRefBoolean(offset) | Self::MemRefInteger(offset) => {
2122 assert!(!matches!(extra, casl2::Register::Gr0));
2123 format!(
2124 r#" LD {extra},MEM
2125 LD {extra},{offset},{extra}
2126 ST {value},0,{extra}"#,
2127 extra = extra,
2128 offset = offset,
2129 value = value
2130 )
2131 }
2132 }
2133 }
2134
2135 fn get_offset(&self) -> Option<usize> {
2136 match self {
2137 Self::VarBoolean(..)
2138 | Self::VarRefBoolean(..)
2139 | Self::VarInteger(..)
2140 | Self::VarRefInteger(..) => None,
2141
2142 Self::MemBoolean(offset)
2143 | Self::MemRefBoolean(offset)
2144 | Self::MemInteger(offset)
2145 | Self::MemRefInteger(offset) => Some(*offset),
2146 }
2147 }
2148}