b2c2_compiler/
lib.rs

1// b2c2-compiler crate
2// author: Leonardone @ NEETSDKASU
3
4use 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
42// 正しい src が来ることを前提とする (不正な src の判定は面倒くさい)
43pub 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    // コメントを除去
76    pub remove_comment: bool,
77    // NOPを除去
78    pub remove_nop: bool,
79    // 未参照ラベルを除去
80    pub remove_unreferenced_label: bool,
81    // サブルーチンを分割
82    pub split_subroutines: bool,
83    // プログラム名の指定
84    pub program_name: Option<String>,
85    // 重複コードのスニペット化を試みる
86    pub try_make_snippets: bool,
87    // debugger用コンパイルモード
88    pub for_debug_basic: bool,
89}
90
91type CodeWithName = Vec<(String, Vec<casl2::Statement>)>;
92
93// 条件付き(?)コンパイル
94pub 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
166// デバッグ用コンパイル
167pub 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// 文字列ラベルのタイプ判定に使う
231#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
232pub enum StrLabelType {
233    Const(String), // IN/OUTの定数 LB**/LL**
234    Lit(String),   // リテラル ='abc'/=3
235    Temp,          // 一時変数 TB**/TL**
236    Var,           // 文字列変数 SB**/SL**
237    ArgRef,        // 引数(参照型) ARG*/ARG*
238    ArgVal,        // 引数 ARG*/ARG*
239    MemRef(usize), // メモリ(MEMからのオフセット)
240    MemVal(usize),
241}
242
243// 文字列のラベル
244#[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// 配列参照
252// (一時的な配列は一時的な文字列変数の文字領域(pos)を借用する(長さ領域(len)の値は使用しない))
253#[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    // debugger用コンパイルモードか
281    for_debug_basic: bool,
282    // ブロックネストの深さ (debugger用)
283    nest_depth: usize,
284
285    // debuggerで利用するためのヒント (ネストの深さ、ヒントメッセージ)
286    debugger_hint: Vec<(usize, String, Option<ExtraInfo>)>,
287
288    // プログラム名
289    program_name: Option<String>,
290    original_program_name: Option<String>,
291
292    // プログラム引数リスト
293    arguments: Vec<parser::ArgumentInfo>,
294
295    // プログラム引数のラベル (真理値/整数) (引数名, (ラベル, 引数情報))
296    argument_labels: HashMap<String, (ValueLabel, parser::ArgumentInfo)>,
297
298    // プログラム引数のラベル (真理値配列/整数配列) (引数名, (ラベル, 引数情報))
299    arr_argument_labels: HashMap<String, (ArrayLabel, parser::ArgumentInfo)>,
300
301    // プログラム引数のラベル (文字列) (引数名, (ラベル, 引数情報))
302    str_argument_labels: HashMap<String, (StrLabels, parser::ArgumentInfo)>,
303
304    // 外部プログラム呼び出し情報
305    callables: HashMap<String, Vec<parser::ArgumentInfo>>,
306
307    // ソース定義の変数のId (真理値/整数/文字列の全体で一意)
308    var_id: usize,
309
310    // IN/OUTで使用する文字列定数のId
311    lit_id: usize,
312
313    // 組み込みサブルーチンのローカル変数・定数のId (名前重複を防ぐが目的) (DS/DCは各サブルーチン内で定義する)
314    local_var_id: usize,
315
316    // 式展開時などの一時変数のId
317    temp_int_var_id: usize,
318    temp_str_var_id: usize,
319
320    // ループや条件分岐に使うジャンプ先ラベルのId (全体で一意)
321    jump_id: usize,
322
323    // 真理値変数のラベル対応を保持 (変数名, ラベル)
324    bool_var_labels: HashMap<String, ValueLabel>,
325
326    // 整数変数のラベル対応を保持 (変数名, ラベル)
327    int_var_labels: HashMap<String, ValueLabel>,
328
329    // 文字列変数のラベル対応を保持 (変数名, (長さラベル, 内容位置ラベル))
330    str_var_labels: HashMap<String, StrLabels>,
331
332    // 真理値配列のラベル対応を保持 (配列名, (ラベル, 配列サイズ))
333    bool_arr_labels: HashMap<String, ArrayLabel>,
334
335    // 整数配列のラベル対応を保持 (配列名, (ラベル, 配列サイズ))
336    int_arr_labels: HashMap<String, ArrayLabel>,
337
338    // IN/OUTで使用する文字列定数のラベル対応を保持 (文字列定数, (長さラベル, 内容位置ラベル)))
339    lit_str_labels: HashMap<String, StrLabels>,
340
341    // 式展開時の一時変数(整数/真理値)のラベルを保持 (ラベル) (主にForループの終点とステップで使用)
342    temp_int_var_labels: BinaryHeap<Reverse<String>>,
343    // 使用中の一時変数
344    engaged_temp_int_var_labels: HashSet<String>,
345    // Call呼び出し時にForで使用中な一時変数を保持
346    save_temp_int_var_labels: HashSet<String>,
347
348    // 式展開時の一時変数(文字列)のラベルを保持 (長さラベル, 内容位置ラベル)
349    temp_str_var_labels: BinaryHeap<Reverse<StrLabels>>,
350
351    // 組み込みサブルーチンのコードを保持 (サブルーチンの固有名, コード)
352    subroutine_codes: HashMap<subroutine::Id, Vec<casl2::Statement>>,
353
354    // Continueで参照する継続ラベル対応を保持 (exit_id, 継続ラベル)
355    loop_labels: HashMap<usize, String>,
356
357    // Exitステートメントで参照する脱出ラベル対応を保持 (exit_id, 脱出ラベル)
358    exit_labels: HashMap<usize, String>,
359
360    // 式展開でレジスタの使用状況把握
361    //  最下位ビットがGR0, 最上位ビットがGR7
362    //    (1 << GR0),  (1 << GR7)
363    //    (ただし、実際にはGR0の使用状況は管理しないでGR1~7のみ管理)
364    //  ビットが立っている場合は使用中(register_dequeにある)
365    //  ビットが立っていない場合はアイドル中、番号の大きいレジスタから使用していく
366    registers_used: u8,
367
368    // 式展開でレジスタの使用状況把握
369    //  使用するレジスタを後尾に追加し、使用し終わったら後尾から取り出す
370    //  アイドルレジスタが1つもない場合、
371    //     先頭のレジスタを取り出して使用する(後尾に追加する)
372    //     このレジスタの内容はコールスタックに積んでおき、必要のタイミングでスタックから取り出す
373    //  先頭: 現在の式展開中の箇所から"遠い"箇所で使用してるレジスタ
374    //  後尾: 現在の式展開中の箇所から"近い"箇所で使用してるレジスタ
375    used_registers_order: Vec<casl2::Register>,
376    stacked_registers: Vec<casl2::Register>,
377
378    // 生成するCASL2コード本体
379    statements: Vec<casl2::Statement>,
380
381    // Input命令またはEOF関数があるときに設定される領域を持つかどうか
382    has_eof: bool,
383
384    // 変数領域の総サイズ
385    var_total_size: usize,
386
387    // プログラム実行前のレジスタを保持するかどうか
388    option_restore_registers: bool,
389
390    // プログラム開始時に変数領域を0で初期化するかどうか
391    option_initialize_variables: bool,
392
393    // EOF情報の保持場所が外部プログラムかどうか
394    option_external_eof: bool,
395
396    // アロケータを使うかどうか
397    option_use_allocator: bool,
398
399    // ローカルアロケータの場合の予約領域のサイズ
400    option_local_allocation_size: Option<usize>,
401
402    // アロケートされたメモリ上の各変数の相対位置計算用
403    allocate_memory_relative_position: usize,
404
405    // アロケートされたメモリ上の引数用途の合計サイズ
406    allocate_arguments_size: usize,
407
408    // Callで使用するアロケートメモリの最大サイズ
409    maximum_allocate_temporary_area_size: usize,
410}
411
412// コンパイラの初期化
413impl Compiler {
414    // コンパイラの初期化
415    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
473// デバッガ関連
474impl Compiler {
475    // 現在のデバッグ情報の表示コマンドを取得
476    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    // debugger用のヒント表示のみを追加する
501    fn show_debugger_hint(&mut self) {
502        if let Some(cmd) = self.get_current_debugger_hint() {
503            self.code(cmd);
504        }
505    }
506
507    // 次のヒント情報のみを追加する
508    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    // debugger用のヒントを追加する
520    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
535// subroutine::Genの実装
536impl 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
546// 細かい関心の分離処理?
547impl Compiler {
548    // 組み込みサブルーチンのローカル変数の新規ラベル生成
549    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    // ループや条件分岐に使うジャンプ先ラベル生成
555    fn get_new_jump_label(&mut self) -> String {
556        self.jump_id += 1;
557        format!("J{:03}", self.jump_id)
558    }
559
560    // Continueなど繰り返しの先頭で使うラベルの取得、無い場合は新規登録
561    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    // Exitなどブロック脱出で使うラベルの取得、無い場合は新規登録
572    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    // 式展開時の一時変数(整数/真理値)のラベル取得・生成
583    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    // 式展開時の一時変数(整数/真理値)のラベルの返却
595    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    // 式展開時の一時変数(文字列)のラベル取得・生成
601    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    // 式展開時の一時変数(文字列)のラベルの返却
614    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    // 式展開時の一時変数(配列)のラベルの返却
621    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    // IN/OUTで使用する文字列定数のラベル生成
628    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    // 文字列リテラル取得、もしIN/OUTで使用する文字列定数のラベルがあればそれを返す
643    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    // サブルーチンのソースコードを登録する
663    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    // レジスタのアイドル状態を取得
680    fn is_idle_register(&self, reg: casl2::Register) -> bool {
681        (self.registers_used & (1 << reg as isize)) == 0
682    }
683
684    // アイドル中のレジスタを取得
685    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    // アイドル化している場合にコールスタックに積まれてる値を戻す
702    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    // アイドル中のレスジスタを使用中に変更
713    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    // 使用中のレジスタをアイドル扱いにする
720    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    // subrutine引数のレジスタなどの一時利用のとき
728    // 一時退避するためのソースコードと復帰するためのソースコードを生成
729    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    // 整数変数のラベル取得
744    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    // 整数変数(参照型)のラベル取得
757    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    // 真理値変数のラベル取得
765    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    // 真理値変数(参照型)のラベル取得
778    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    // 文字列変数のラベル取得
786    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    // 文字列変数(参照型)のラベル取得
803    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    // 真理値配列のラベル取得
815    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    // 真理値配列(参照型)のラベル取得
831    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    // 整数配列のラベル取得
842    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    // 整数配列(参照型)のラベル取得
858    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
869// コンパイル最終工程
870impl Compiler {
871    // コンパイル最終工程
872    fn finish(mut self) -> Vec<casl2::Statement> {
873        // 初期化用のサブルーチンのロード
874        if self.var_total_size > 1 && self.option_initialize_variables {
875            self.load_subroutine(subroutine::Id::UtilFill);
876        }
877        // Allocatorのサブルーチンを取得
878        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        // プログラム終了ポイント
921        statements.labeled("EXIT", casl2::Command::Nop);
922
923        // メモリの解放
924        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        // 一時変数の復帰
936        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        // プログラム開始時のレジスタの状態の復帰
948        if option_restore_registers {
949            statements.code(casl2::Command::Rpop);
950        }
951
952        // End Subの表示
953        if let Some(cmd) = dbg_cmd {
954            statements.code(cmd);
955        }
956
957        // プログラムの終了
958        statements.code(casl2::Command::Ret);
959
960        if !option_use_allocator {
961            // 引数の値を保持する領域の設定 ARG*
962            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        // 初期化が必要な変数領域の最初のラベル
997        let mut first_var_label: Option<String> = None;
998
999        if !option_use_allocator {
1000            // 真理値変数 B**
1001            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            // 整数変数 I**
1014            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            // 文字列変数 SL** SB**
1027            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            // 真理値配列(固定長) BA**
1042            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            // 整数配列(固定長) IA**
1060            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        // EOFを扱う場合
1079        if has_eof && !option_external_eof {
1080            statements.labeled("EOF", casl2::Command::Ds { size: 1 });
1081        }
1082
1083        // Allocatorを使用する場合
1084        if option_use_allocator {
1085            statements.labeled("MEM", casl2::Command::Ds { size: 1 });
1086        }
1087
1088        // プログラム冒頭のコードをまとめる用
1089        let mut temp_statements = Vec::<casl2::Statement>::new();
1090
1091        // プログラムの開始点(START)の設定
1092        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        // Subの表示
1116        if for_debug_basic {
1117            temp_statements.code(casl2::Command::DebugBasicStep { id: 0 });
1118        }
1119
1120        // プログラム開始時のレジスタの状態の保存
1121        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            // Forステートメントで使用する一時変数の退避
1127            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            // メモリの確保コード
1150            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        // 引数であるレジスタの値の保存
1195        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        // ByValの配列/文字列の引数の中身コピー処理
1309        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        // 変数領域の初期化処理のコード
1378        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        // プログラム冒頭のコードをマージ
1441        temp_statements.extend(statements);
1442        let mut statements = temp_statements;
1443
1444        // 式展開等で使う一時変数(整数/真理値で共有) T**
1445        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        // 式展開等で使う一時変数(文字列) TL** TB**
1451        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        // IN/OUTで使用する文字列定数 LL** LB**
1459        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        // Allocator埋め込みの場合
1484        if let Some(src) = allocator_code {
1485            statements.code(src);
1486        }
1487
1488        // 組み込みサブルーチンのコード
1489        for (_, code) in subroutine_codes.into_iter().collect::<BTreeMap<_, _>>() {
1490            statements.code(code);
1491        }
1492
1493        // END ステートメントの挿入 (CASL2ソースコード末尾)
1494        statements.code(casl2::Command::End);
1495
1496        statements
1497    }
1498}
1499
1500// ステートメントをコンパイルする
1501impl Compiler {
1502    // ステートメントをコンパイルする
1503    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            // IfやSelectの内側で処理する
1680            ElseIf { .. }
1681            | Else { .. }
1682            | CaseInteger { .. }
1683            | CaseString { .. }
1684            | CaseElse { .. } => unreachable!("BUG"),
1685
1686            // Provisionals unreachable
1687            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}