b2c2_compiler/
subroutine.rs

1// b2c2-compiler crate::subroutine
2// author: Leonardone @ NEETSDKASU
3
4use crate::casl2;
5
6#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
7pub enum Id {
8    FuncCInt,
9    FuncCStrArgBool,
10    FuncCStrArgInt,
11    FuncSpace,
12    UtilCompareStr,
13    UtilConcatStr,
14    UtilCopyFromOffsetStr,
15    UtilCopyStr,
16    UtilCopyToOffsetStr,
17    UtilDivMod,
18    UtilFill,
19    UtilLoadElement,
20    UtilMul,
21    UtilSafeIndex,
22}
23
24impl Id {
25    pub fn label(&self) -> String {
26        format!("C{:03}", *self as isize)
27    }
28}
29
30pub struct Src {
31    pub dependencies: Vec<Id>,
32    pub statements: Vec<casl2::Statement>,
33}
34
35pub trait Gen {
36    fn var_label(&mut self) -> String;
37    fn jump_label(&mut self) -> String;
38}
39
40// サブルーチンのソースコードと依存関係を取得
41pub fn get_src<T: Gen>(gen: &mut T, id: Id) -> Src {
42    match id {
43        Id::FuncCInt => get_func_cint(gen, id),
44        Id::FuncCStrArgBool => get_func_cstr_arg_bool(gen, id),
45        Id::FuncCStrArgInt => get_func_cstr_arg_int(gen, id),
46        Id::FuncSpace => get_func_space(gen, id),
47        Id::UtilCompareStr => get_util_compare_str(gen, id),
48        Id::UtilConcatStr => get_util_concat_str(gen, id),
49        Id::UtilCopyFromOffsetStr => get_util_copy_from_offset_str(gen, id),
50        Id::UtilCopyStr => get_util_copy_str(gen, id),
51        Id::UtilCopyToOffsetStr => get_util_copy_to_offset_str(gen, id),
52        Id::UtilDivMod => get_util_div_mod(gen, id),
53        Id::UtilFill => get_util_fill(gen, id),
54        Id::UtilLoadElement => get_util_load_element(gen, id),
55        Id::UtilMul => get_util_mul(gen, id),
56        Id::UtilSafeIndex => get_util_safe_index(gen, id),
57    }
58}
59
60// Util: EOF Store
61pub fn get_util_eof_store_code() -> Vec<casl2::Statement> {
62    // 外部コードにする前提なのでSTART/ENDが含まれている
63    // 引数も戻り値もGR0
64    // 引数 GR0 == 0 のとき
65    //    EOF未到達(0)を記憶
66    // 引数 GR0 == 1 のとき
67    //    戻り値 GR0 .. EOF到達状態を取得 (EOF未到達なら0、EOF到達なら-1)
68    // 引数 GR0 == -1 のとき
69    //    EOF到達(-1)を記憶
70    casl2::parse(&format!(
71        r#"
72EOF      START
73                                   ; UtilEofStore
74         AND   GR0,GR0
75         JPL   {load}
76         ST    GR0,{value}
77         RET
78{load}   LD    GR0,{value}
79         RET
80{value}  DS    1
81         END
82"#,
83        load = "J1",
84        value = "V1"
85    ))
86    .unwrap()
87}
88
89// Util: Allocator
90pub fn get_util_allocator_code_for_common(size: usize) -> Vec<casl2::Statement> {
91    #[derive(Default)]
92    struct Temp {
93        j: usize,
94        v: usize,
95    }
96    impl Gen for Temp {
97        fn var_label(&mut self) -> String {
98            self.j += 1;
99            format!("J{}", self.j)
100        }
101        fn jump_label(&mut self) -> String {
102            self.v += 1;
103            format!("V{}", self.v)
104        }
105    }
106    let mut temp = Temp::default();
107    super::utils::to_external("ALLOC", get_util_allocator_code(&mut temp, size))
108}
109
110// Util: Allocator
111pub fn get_util_allocator_code<T: Gen>(gen: &mut T, size: usize) -> Vec<casl2::Statement> {
112    // スタック的な呼び出しが想定されてる
113    // 引数 GR0 == 0 のとき
114    //   引数  GR1 .. 確保するメモリ
115    //   戻り値 GR0 .. 確保したメモリの先頭アドレス
116    // 引数 GR0 != 0 のとき
117    //   引数  GR1 .. 解放するメモリの先頭アドレス
118    casl2::parse(&format!(
119        r#"
120                                   ; UtilAllocator
121ALLOC   AND   GR0,GR0
122        JNZ   {free}
123        LAD   GR0,{mem}
124        ADDL  GR0,{cnt}
125        CPL   GR0,{pos}
126        JZE   {next}
127{init}  ST    GR1,{cnt}
128        LAD   GR0,{mem}
129        ADDL  GR1,GR0
130        ST    GR1,{pos}
131        RET
132{next}  ADDL  GR0,GR1
133        CPL   GR0,{end}
134        JPL   {init}
135        ST    GR0,{pos}
136        SUBL  GR0,GR1
137        ADDL  GR1,{cnt}
138        ST    GR1,{cnt}
139        RET
140{free}  ST    GR1,{pos}
141        LAD   GR0,{mem}
142        SUBL  GR1,GR0
143        ST    GR1,{cnt}
144        RET
145{cnt}   DS    1
146{pos}   DS    1
147{mem}   DS    {size}
148{end}   DC    {end}
149"#,
150        init = gen.jump_label(),
151        next = gen.jump_label(),
152        free = gen.jump_label(),
153        cnt = gen.var_label(),
154        pos = gen.var_label(),
155        mem = gen.var_label(),
156        end = gen.var_label(),
157        size = size
158    ))
159    .unwrap()
160}
161
162// Func: CInt
163fn get_func_cint<T: Gen>(gen: &mut T, id: Id) -> Src {
164    // GR1 .. adr of s_buf
165    // GR2 .. s_len
166    // GR0 .. ret
167    Src {
168        dependencies: Vec::new(),
169        statements: casl2::parse(&format!(
170            r#"
171                                   ; {comment}
172{prog} PUSH  0,GR1
173       PUSH  0,GR2
174       PUSH  0,GR3
175       PUSH  0,GR4
176       PUSH  0,GR5
177       ADDL  GR2,GR1
178       XOR   GR0,GR0
179       XOR   GR4,GR4
180       CPL   GR1,GR2
181       JZE   {ret}
182       LD    GR3,0,GR1
183       CPL   GR3,='+'
184       JNZ   {mi}
185       LAD   GR1,1,GR1
186       JUMP  {read}
187{mi}   CPL   GR3,='-'
188       JNZ   {read}
189       LAD   GR4,-1
190       LAD   GR1,1,GR1
191{read} CPL   GR1,GR2
192       JZE   {ret}
193       LD    GR3,0,GR1
194       SUBL  GR3,='0'
195       JMI   {ret}
196       CPL   GR3,=9
197       JPL   {ret}
198       LD    GR5,GR0
199       SLL   GR0,3
200       ADDL  GR0,GR5
201       ADDL  GR0,GR5
202       ADDL  GR0,GR3
203       LAD   GR1,1,GR1
204       JUMP  {read}
205{ret}  XOR   GR0,GR4
206       SUBL  GR0,GR4
207       POP   GR5
208       POP   GR4
209       POP   GR3
210       POP   GR2
211       POP   GR1
212       RET
213"#,
214            comment = format_args!("{:?}", id),
215            prog = id.label(),
216            ret = gen.jump_label(),
217            read = gen.jump_label(),
218            mi = gen.jump_label()
219        ))
220        .unwrap(),
221    }
222}
223
224// Util: Safe Index
225fn get_util_safe_index<T: Gen>(gen: &mut T, id: Id) -> Src {
226    // GR1 index of array
227    // GR2 size of array
228    // GR0 = Max(0, Min(GR1, GR2 - 1))
229    Src {
230        dependencies: Vec::new(),
231        statements: casl2::parse(&format!(
232            r#"
233                                   ; {comment}
234{prog}    AND    GR2,GR2
235          JNZ    {lbound}
236          XOR    GR0,GR0
237          RET
238{lbound}  LD     GR0,GR1
239          JPL    {ubound}
240          XOR    GR0,GR0
241          RET
242{ubound}  CPL    GR0,GR2
243          JMI    {ok}
244          LAD    GR0,-1
245          ADDL   GR0,GR2
246{ok}      RET
247"#,
248            comment = format_args!("{:?}", id),
249            prog = id.label(),
250            lbound = gen.jump_label(),
251            ubound = gen.jump_label(),
252            ok = gen.jump_label()
253        ))
254        .unwrap(),
255    }
256}
257
258// Util: Div Mod
259fn get_util_div_mod<T: Gen>(gen: &mut T, id: Id) -> Src {
260    // GR2 割られる数 (分子)
261    // GR3 割る数 (分母)
262    // GR0 商    = GR2 \ GR3
263    // GR1 余り   = GR2 Mod GR3
264    Src {
265        dependencies: vec![Id::UtilMul],
266        statements: casl2::parse(&format!(
267            r#"
268                                   ; {comment}
269{prog}  AND   GR3,GR3
270        JNZ   {ok}
271        XOR   GR0,GR0
272        LAD   GR1,-1
273        RET
274{ok}    PUSH  0,GR2
275        PUSH  0,GR3
276        PUSH  0,GR4
277        PUSH  0,GR5
278        LD    GR4,GR2
279        LD    GR5,GR2
280        JPL   {x}
281        XOR   GR5,GR5
282        SUBA  GR5,GR2
283{x}     LD    GR1,GR3
284        JPL   {y}
285        XOR   GR1,GR1
286        SUBA  GR1,GR3
287{y}     LAD   GR0,1
288{shift} ADDL  GR1,GR1
289        JOV   {pre}
290        ADDL  GR0,GR0
291        JUMP  {shift}
292{pre}   SRL   GR1,1
293        LAD   GR1,#8000,GR1
294        XOR   GR2,GR2
295{cycle} CPL   GR5,GR1
296        JMI   {next}
297        SUBL  GR5,GR1
298        ADDL  GR2,GR0
299{next}  SRL   GR0,1
300        JZE   {ret}
301        SRL   GR1,1
302        JUMP  {cycle}
303{ret}   LD    GR5,GR4
304        XOR   GR5,GR3
305        SRA   GR5,15
306        XOR   GR2,GR5
307        SUBA  GR2,GR5
308        CALL  {mul}
309        LD    GR1,GR4
310        SUBA  GR1,GR0
311        LD    GR0,GR2
312        POP   GR5
313        POP   GR4
314        POP   GR3
315        POP   GR2
316        RET
317"#,
318            comment = format_args!("{:?}", id),
319            prog = id.label(),
320            mul = Id::UtilMul.label(),
321            x = gen.jump_label(),
322            y = gen.jump_label(),
323            ok = gen.jump_label(),
324            shift = gen.jump_label(),
325            pre = gen.jump_label(),
326            cycle = gen.jump_label(),
327            next = gen.jump_label(),
328            ret = gen.jump_label()
329        ))
330        .unwrap(),
331    }
332}
333
334// Util: Mul
335fn get_util_mul<T: Gen>(gen: &mut T, id: Id) -> Src {
336    // GR2 * GR3
337    // GR0 積の下位16ビット  (GR2 * GR3) & 0x0000FFFF
338    // GR1 積の上位16ビット ((GR2 * GR3) & 0xFFFF0000) >> 16
339    Src {
340        dependencies: vec![Id::UtilMul],
341        statements: casl2::parse(&format!(
342            r#"
343                                   ; {comment}
344{prog}   PUSH  0,GR2
345         PUSH  0,GR3
346         PUSH  0,GR4
347         PUSH  0,GR5
348         XOR   GR0,GR0
349         XOR   GR1,GR1
350         LD    GR4,GR2
351         LD    GR5,GR3
352{cycle1} SRL   GR2,1
353         JOV   {add1}
354         JNZ   {next1}
355         JUMP  {cycle2}
356{add1}   ADDL  GR0,GR3
357         JOV   {raise1}
358         JUMP  {next1}
359{raise1} LAD   GR1,1,GR1
360{next1}  SLL   GR3,1
361         JUMP  {cycle1}
362{cycle2} SRL   GR5,1
363         SLL   GR4,1
364         JOV   {add2}
365         JNZ   {cycle2}
366         JUMP  {ret}
367{add2}   ADDL  GR1,GR5
368         JUMP  {cycle2}
369{ret}    POP   GR5
370         POP   GR4
371         POP   GR3
372         POP   GR2
373         RET
374"#,
375            comment = format_args!("{:?}", id),
376            prog = id.label(),
377            cycle1 = gen.jump_label(),
378            add1 = gen.jump_label(),
379            raise1 = gen.jump_label(),
380            next1 = gen.jump_label(),
381            cycle2 = gen.jump_label(),
382            add2 = gen.jump_label(),
383            ret = gen.jump_label()
384        ))
385        .unwrap(),
386    }
387}
388
389// Func: CStr (bool)
390fn get_func_cstr_arg_bool<T: Gen>(gen: &mut T, id: Id) -> Src {
391    // GR1 .. adr of s_buf
392    // GR2 .. adr of s_len
393    // GR3 .. value (boolean)
394    Src {
395        dependencies: vec![Id::UtilCopyStr],
396        statements: casl2::parse(&format!(
397            r#"
398                                   ; {comment}
399{prog}   PUSH  0,GR3
400         PUSH  0,GR4
401         AND   GR3,GR3
402         LAD   GR3,='FalseTrue'
403         LAD   GR4,5
404         JZE   {ret}
405         ADDL  GR3,GR4
406         LAD   GR4,4
407{ret}    CALL  {copy}
408         POP   GR4
409         POP   GR3
410         RET
411"#,
412            comment = format_args!("{:?}", id),
413            prog = id.label(),
414            copy = Id::UtilCopyStr.label(),
415            ret = gen.jump_label()
416        ))
417        .unwrap(),
418    }
419}
420
421// Func: CStr (int)
422fn get_func_cstr_arg_int<T: Gen>(gen: &mut T, id: Id) -> Src {
423    // GR1 .. adr of s_buf
424    // GR2 .. adr of s_len
425    // GR3 .. value (integer)
426    Src {
427        dependencies: vec![Id::UtilDivMod, Id::UtilCopyStr],
428        statements: casl2::parse(&format!(
429            r#"
430                                   ; {comment}
431{prog}   CPL   GR3,=#8000
432         JNZ   {zero}
433         PUSH  0,GR3
434         PUSH  0,GR4
435         LAD   GR3,='-32768'
436         LAD   GR4,6
437         CALL  {copystr}
438         POP   GR4
439         POP   GR3
440         RET
441{zero}   AND   GR3,GR3
442         JNZ   {init}
443         LAD   GR3,1
444         ST    GR3,0,GR2
445         LD    GR3,='0'
446         ST    GR3,0,GR1
447         XOR   GR3,GR3
448         RET
449{init}   PUSH  0,GR1
450         PUSH  0,GR2
451         PUSH  0,GR3
452         PUSH  0,GR4
453         PUSH  0,GR5
454         JPL   {start}
455         LD    GR4,='-'
456         ST    GR4,0,GR1
457         LAD   GR1,1,GR1
458         XOR   GR3,=#FFFF
459         LAD   GR3,1,GR3
460{start}  LAD   GR4,{temp}
461         LD    GR5,GR1
462         LD    GR2,GR3
463         LAD   GR3,10
464{cycle}  CALL  {rem}
465         ADDL  GR1,='0'
466         ST    GR1,0,GR4
467         LAD   GR4,1,GR4
468         LD    GR2,GR0
469         JPL   {cycle}
470         LAD   GR2,{temp}
471         LAD   GR4,-1,GR4
472{copy}   LD    GR1,0,GR4
473         ST    GR1,0,GR5
474         LAD   GR5,1,GR5
475         LAD   GR4,-1,GR4
476         CPL   GR4,GR2
477         JPL   {copy}
478         JZE   {copy}
479         LD    GR0,GR5
480         POP   GR5
481         POP   GR4
482         POP   GR3
483         POP   GR2
484         POP   GR1
485         SUBL  GR0,GR1
486         ST    GR0,0,GR2
487         RET
488{temp}   DS    6
489"#,
490            comment = format_args!("{:?}", id),
491            prog = id.label(),
492            rem = Id::UtilDivMod.label(),
493            copystr = Id::UtilCopyStr.label(),
494            zero = gen.jump_label(),
495            init = gen.jump_label(),
496            start = gen.jump_label(),
497            cycle = gen.jump_label(),
498            copy = gen.jump_label(),
499            temp = gen.var_label()
500        ))
501        .unwrap(),
502    }
503}
504
505// Util: Compare Str
506fn get_util_compare_str<T: Gen>(gen: &mut T, id: Id) -> Src {
507    // GR1 .. adr of s_buf (lhs)
508    // GR2 .. s_len (lhs)
509    // GR3 .. adr of s_buf (rhs)
510    // GR4 .. s_len (rhs)
511    // GR0 .. -1 if lhs < rhs, 0 if lhs == rhs, 1 if lhs > rhs
512    Src {
513        dependencies: Vec::new(),
514        statements: casl2::parse(&format!(
515            r#"
516                                   ; {comment}
517{prog}   PUSH  0,GR1
518         PUSH  0,GR2
519         PUSH  0,GR3
520         PUSH  0,GR4
521         PUSH  0,GR5
522         XOR   GR0,GR0
523{cycle}  AND   GR2,GR2
524         JPL   {next}
525         CPL   GR2,GR4
526         JNZ   {less}
527         JUMP  {ret}
528{next}   AND   GR4,GR4
529         JZE   {great}
530         LD    GR5,0,GR1
531         CPL   GR5,0,GR3
532         JMI   {less}
533         JPL   {great}
534         LAD   GR1,1,GR1
535         LAD   GR2,-1,GR2
536         LAD   GR3,1,GR3
537         LAD   GR4,-1,GR4
538         JUMP  {cycle}
539{less}   LAD   GR0,-1
540{great}  OR    GR0,=1
541{ret}    POP   GR5
542         POP   GR4
543         POP   GR3
544         POP   GR2
545         POP   GR1
546         RET
547"#,
548            comment = format_args!("{:?}", id),
549            prog = id.label(),
550            cycle = gen.jump_label(),
551            next = gen.jump_label(),
552            less = gen.jump_label(),
553            great = gen.jump_label(),
554            ret = gen.jump_label()
555        ))
556        .unwrap(),
557    }
558}
559
560// Util: Copy Str
561fn get_util_copy_str<T: Gen>(gen: &mut T, id: Id) -> Src {
562    // GR1 .. adr of s_buf (dst)
563    // GR2 .. adr of s_len (dst)
564    // GR3 .. adr of s_buf (src)
565    // GR4 .. s_len (src)
566    //  copy from (GR3,GR4) to (GR1,GR2)
567    Src {
568        dependencies: Vec::new(),
569        statements: casl2::parse(&format!(
570            r#"
571                                   ; {comment}
572{prog}   PUSH  0,GR1
573         PUSH  0,GR2
574         PUSH  0,GR3
575         PUSH  0,GR4
576         ST    GR4,0,GR2
577         AND   GR4,GR4
578         JZE   {ret}
579{cycle}  LD    GR2,0,GR3
580         ST    GR2,0,GR1
581         LAD   GR3,1,GR3
582         LAD   GR1,1,GR1
583         SUBL  GR4,=1
584         JPL   {cycle}
585{ret}    POP   GR4
586         POP   GR3
587         POP   GR2
588         POP   GR1
589         RET
590"#,
591            comment = format_args!("{:?}", id),
592            prog = id.label(),
593            cycle = gen.jump_label(),
594            ret = gen.jump_label()
595        ))
596        .unwrap(),
597    }
598}
599
600// Util: Concat Str
601fn get_util_concat_str<T: Gen>(gen: &mut T, id: Id) -> Src {
602    // GR1 .. adr of s_buf (dst,left)
603    // GR2 .. adr of s_len (dst)
604    // GR3 .. adr of s_buf (src,right)
605    // GR4 .. s_len (src)
606    //   GR1 = GR1 & GR3
607    //   GR2 = Min(GR2 + GR4, 256)
608    Src {
609        dependencies: Vec::new(),
610        statements: casl2::parse(&format!(
611            r#"
612                                   ; {comment}
613{prog}   PUSH  0,GR1
614         PUSH  0,GR2
615         PUSH  0,GR3
616         PUSH  0,GR4
617         LD    GR0,0,GR2
618         LD    GR2,GR1
619         ADDL  GR1,GR0
620         LAD   GR2,256,GR2
621         ADDL  GR4,GR3
622{cycle}  CPL   GR1,GR2
623         JZE   {ret}
624         CPL   GR3,GR4
625         JZE   {ret}
626         LD    GR0,0,GR3
627         ST    GR0,0,GR1
628         LAD   GR1,1,GR1
629         LAD   GR3,1,GR3
630         JUMP  {cycle}
631{ret}    LD    GR0,GR1
632         POP   GR4
633         POP   GR3
634         POP   GR2
635         POP   GR1
636         SUBL  GR0,GR1
637         ST    GR0,0,GR2
638         RET
639"#,
640            comment = format_args!("{:?}", id),
641            prog = id.label(),
642            cycle = gen.jump_label(),
643            ret = gen.jump_label()
644        ))
645        .unwrap(),
646    }
647}
648
649// Util: Fill
650fn get_util_fill<T: Gen>(gen: &mut T, id: Id) -> Src {
651    // GR1 .. adr of start point of s_buf or array
652    // GR2 .. fill value
653    // GR3 .. fill len
654    Src {
655        dependencies: Vec::new(),
656        statements: casl2::parse(&format!(
657            r#"
658                                   ; {comment}
659{prog} PUSH  0,GR1
660       PUSH  0,GR2
661       PUSH  0,GR3
662       ADDL  GR3,GR1
663{next} CPL   GR1,GR3
664       JZE   {ret}
665       ST    GR2,0,GR1
666       LAD   GR1,1,GR1
667       JUMP  {next}
668{ret}  POP   GR3
669       POP   GR2
670       POP   GR1
671       RET
672"#,
673            comment = format_args!("{:?}", id),
674            prog = id.label(),
675            next = gen.jump_label(),
676            ret = gen.jump_label()
677        ))
678        .unwrap(),
679    }
680}
681
682// Func Space
683fn get_func_space<T: Gen>(_gen: &mut T, id: Id) -> Src {
684    // GR1 .. adr of s_buf
685    // GR2 .. adr of s_len
686    // GR3 .. space len
687    Src {
688        dependencies: vec![Id::UtilFill, Id::UtilSafeIndex],
689        statements: casl2::parse(&format!(
690            r#"
691                                   ; {comment}
692{prog} PUSH  0,GR1
693       PUSH  0,GR2
694       PUSH  0,GR3
695       XOR   GR1,GR3
696       XOR   GR3,GR1
697       XOR   GR1,GR3
698       LAD   GR2,257
699       CALL  {fit}
700       LD    GR1,GR3
701       LD    GR3,GR0
702       LD    GR2,=' '
703       CALL  {fill}
704       LD    GR0,GR3
705       POP   GR3
706       POP   GR2
707       POP   GR1
708       ST    GR0,0,GR2
709       RET
710"#,
711            comment = format_args!("{:?}", id),
712            prog = id.label(),
713            fit = Id::UtilSafeIndex.label(),
714            fill = Id::UtilFill.label()
715        ))
716        .unwrap(),
717    }
718}
719
720// Util: Copy To Offset Str
721fn get_util_copy_to_offset_str<T: Gen>(gen: &mut T, id: Id) -> Src {
722    // GR1 .. DST offset
723    // GR2 .. s_len (DST)
724    // GR3 .. adr of s_buf (src)
725    // GR4 .. s_len (src)
726    // GR5 .. adr of s_buf (DST)
727    // GR6 .. copy length
728    // GR0 .. copied length
729    Src {
730        dependencies: vec![Id::UtilSafeIndex],
731        statements: casl2::parse(&format!(
732            r#"
733                                   ; {comment}
734{prog} PUSH  0,GR1
735       PUSH  0,GR2
736       PUSH  0,GR3
737       PUSH  0,GR4
738       PUSH  0,GR5
739       PUSH  0,GR6
740       CALL  {fit}
741       LD    GR1,GR6
742       LD    GR6,GR0
743       CPL   GR1,GR2
744       JMI   {x}
745       LD    GR1,GR2
746{x}    ADDL  GR1,GR6
747       LD    GR0,GR1
748       CPL   GR0,GR2
749       JMI   {y}
750       LD    GR0,GR2
751{y}    SUBL  GR0,GR6
752       CPL   GR0,GR4
753       JMI   {z}
754       LD    GR0,GR4
755{z}    ADDL  GR5,GR6
756       LD    GR6,GR5
757       ADDL  GR5,GR0
758       ADDL  GR3,GR0
759{next} CPL   GR5,GR6
760       JZE   {ret}
761       LAD   GR3,-1,GR3
762       LAD   GR5,-1,GR5
763       LD    GR1,0,GR3
764       ST    GR1,0,GR5
765       JUMP  {next}
766{ret}  POP   GR6
767       POP   GR5
768       POP   GR4
769       POP   GR3
770       POP   GR2
771       POP   GR1
772       RET
773"#,
774            comment = format_args!("{:?}", id),
775            prog = id.label(),
776            fit = Id::UtilSafeIndex.label(),
777            x = gen.jump_label(),
778            y = gen.jump_label(),
779            z = gen.jump_label(),
780            next = gen.jump_label(),
781            ret = gen.jump_label()
782        ))
783        .unwrap(),
784    }
785}
786
787// Util: Copy From Offset Str
788fn get_util_copy_from_offset_str<T: Gen>(gen: &mut T, id: Id) -> Src {
789    // GR1 .. SRC offset
790    // GR2 .. s_len (SRC)
791    // GR3 .. adr of s_buf (SRC)
792    // GR4 .. s_len (dst)
793    // GR5 .. adr of s_buf (dst)
794    // GR6 .. copy length
795    // GR0 .. copied length
796    Src {
797        dependencies: vec![Id::UtilSafeIndex],
798        statements: casl2::parse(&format!(
799            r#"
800                                   ; {comment}
801{prog} PUSH  0,GR1
802       PUSH  0,GR2
803       PUSH  0,GR3
804       PUSH  0,GR4
805       PUSH  0,GR5
806       PUSH  0,GR6
807       CALL  {fit}
808       LD    GR1,GR6
809       LD    GR6,GR0
810       CPL   GR1,GR2
811       JMI   {x}
812       LD    GR1,GR2
813{x}    ADDL  GR1,GR6
814       LD    GR0,GR1
815       CPL   GR0,GR2
816       JMI   {y}
817       LD    GR0,GR2
818{y}    SUBL  GR0,GR6
819       CPL   GR0,GR4
820       JMI   {z}
821       LD    GR0,GR4
822{z}    ADDL  GR3,GR6
823       LD    GR6,GR5
824       ADDL  GR6,GR0
825{next} CPL   GR5,GR6
826       JZE   {ret}
827       LD    GR1,0,GR3
828       ST    GR1,0,GR5
829       LAD   GR3,1,GR3
830       LAD   GR5,1,GR5
831       JUMP  {next}
832{ret}  POP   GR6
833       POP   GR5
834       POP   GR4
835       POP   GR3
836       POP   GR2
837       POP   GR1
838       RET
839"#,
840            comment = format_args!("{:?}", id),
841            prog = id.label(),
842            fit = Id::UtilSafeIndex.label(),
843            x = gen.jump_label(),
844            y = gen.jump_label(),
845            z = gen.jump_label(),
846            next = gen.jump_label(),
847            ret = gen.jump_label()
848        ))
849        .unwrap(),
850    }
851}
852
853// Util: Load Element
854fn get_util_load_element<T: Gen>(gen: &mut T, id: Id) -> Src {
855    // GR1 .. index of arr or str
856    // GR2 .. length of arr or str
857    // GR3 .. adr of arr or str
858    // GR0 .. element value
859    Src {
860        dependencies: vec![Id::UtilSafeIndex],
861        statements: casl2::parse(&format!(
862            r#"
863                                   ; {comment}
864{prog}     AND  GR2,GR2
865           JNZ  {ok}
866           XOR  GR0,GR0
867           RET
868{ok}       CALL {fit}
869           PUSH 0,GR3
870           ADDL GR3,GR0
871           LD   GR0,0,GR3
872           POP  GR3
873           RET
874"#,
875            comment = format_args!("{:?}", id),
876            prog = id.label(),
877            fit = Id::UtilSafeIndex.label(),
878            ok = gen.jump_label()
879        ))
880        .unwrap(),
881    }
882}