Comment detail

整数の漢数字表記 (Nested Flatten)

Mac OS X (PowerPC 32bit) アセンブリで。お題の通り一京未満しか対応してません。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        .machine ppc
        .globl _main

;; Usage: ./kansuuji string
        
;; r3: 数字
;; r4: 桁数
;; r5: 処理中の数字
;; r6: 開始時のスタックの位置
;; r7: 漢数字(零〜九)
;; r8: 漢数字の桁1(十百千)
;; r9: 漢数字の桁2(万〜)
;; r11: 表示文字数
;; r12: フラグ
;;      1: 桁1をスタックに積んだかどうか
;;      2: 桁2をスタックに積んだかどうか
_main:
        lwz     r3, 4(r4)       ; argv[1]
        li      r4, 0
        mr      r6, r1          ; スタックポインタを保存
        
        lis     r7, hi16(digit)
        addi    r7, r7, lo16(digit)

        ;; 文字列の最後にセット
        lis     r8, hi16(subunit_end)
        addi    r8, r8, lo16(subunit_end)
        lis     r9, hi16(unit_end)
        addi    r9, r9, lo16(unit_end)

        ;; 改行をスタックに積んでおく
        li      r11, 1          ; 表示文字数(改行含む)
        li      r0, 10          ; '\n'
        stbu    r0, -1(r1)
        
goto_end:
        ;; 文字列の最後に移動
        addi    r4, r4, 1
        lbz     r5, 0(r3)
        addi    r3, r3, 1
        cmpli   cr7, r5, 0
        bne     cr7, goto_end
        subi    r3, r3, 2       ; 文字列の終端から戻す
        subi    r4, r4, 1
        mr      r13, r4

scan:
        li      r12, 0          ; フラグをクリア
        
        ;; 桁1
        lbz     r0, 0(r8)
        cmpli   cr7, r0, 0
        bne     cr7, push_subunit

        ;; 桁1のポインタを先頭に戻し、桁2へ
        lis     r8, hi16(subunit)
        addi    r8, r8, lo16(subunit)
        b       push_unit

;; 桁1
push_subunit:
        lbz     r0, 1(r8)
        stbu    r0, -1(r1)
        lbz     r0, 0(r8)
        stbu    r0, -1(r1)
        addi    r8, r8, 2
        addi    r11, r11, 2     ; 表示文字数+2
        li      r12, 1          ; フラグ
        b       push_digit

;; 桁2
push_unit:
        lbz     r0, 0(r9)
        cmpli   cr7, r0, 0
        beq     cr7, ignore_unit

        ;; 桁2をスタックに追加
        lbz     r0, 1(r9)
        stbu    r0, -1(r1)
        lbz     r0, 0(r9)
        stbu    r0, -1(r1)
        addi    r9, r9, 2
        addi    r11, r11, 2     ; 表示文字数+2
        li      r12, 2          ; フラグ
        b       push_digit
        
ignore_unit:
        lis     r9, hi16(unit)
        addi    r9, r9, lo16(unit)      
        
push_digit:
        ;; 整数に変換してスタックに追加
        lbz     r5, 0(r3)
        subi    r5, r5, 48      ; ASCIIコード

        ;; 数字が1で、かつ桁1がある場合は1を省略
        cmpli   cr7, r5, 1
        cmpli   cr6, r12, 1
        crand   2, 30, 26       ; cr0[eq] = cr7[eq] & cr6[eq]
        beq     cr0, next_scan

        ;; 数字が0で、かつ一の位であれば省略
        cmpli   cr7, r5, 0
        cmpl    cr6, r13, r4
        crand   2, 30, 26       ; cr0[eq] = cr7[eq] & cr6[eq]
        beq     cr0, next_scan

        ;; 数字が0で、かつ桁2がある場合は数字だけ省略
        cmpli   cr7, r5, 0
        cmpli   cr6, r12, 2
        crand   2, 30, 26       ; cr0[eq] = cr7[eq] & cr6[eq]
        beq     cr0, next_scan

        ;; 数字が0で、かつ桁1がある場合は両方省略
        cmpli   cr7, r5, 0
        cmpli   cr6, r12, 1
        crand   2, 30, 26       ; cr0[eq] = cr7[eq] & cr6[eq]
        bne     cr0, push_digit_exec
        addi    r1, r1, 2       ; 先に積んである桁を戻す
        subi    r11, r11, 2
        b       next_scan
        
push_digit_exec:
        ;; 数字
        add     r10, r7, r5
        add     r10, r10, r5    ; 2バイト分
        lbz     r0, 1(r10)
        stbu    r0, -1(r1)
        lbz     r0, 0(r10)
        stbu    r0, -1(r1)
        addi    r11, r11, 2

next_scan:
        subi    r3, r3, 1
        subi    r4, r4, 1
        cmpli   cr7, r4, 0
        bgt     cr7, scan

        ;; 表示
        stwu    r6, -4(r1)      ; スタックに退避
        li      r3, 1
        addi    r4, r1, 4
        mr      r5, r11
        li      r0, 4           ; sys_write()
        sc
        lwz     r6, 0(r1)       ; スタックから復帰
        addi    r1, r1, 4

exit:
        ;; 終了
        mr      r1, r6          ; スタックポインタを戻す
        li      r3, 0
        li      r0, 1
        sc


        .data
        .align  4

digit:
        .asciz  "零一二三四五六七八九"
        .align  4

subunit:
        .asciz  "十百千"
        subunit_end = . - 1
        .align  4

unit:
        .asciz  "万億兆"
        unit_end = . - 1
        .align  4

Index

Feed

Other

Link

Pathtraq

loading...