Scala上でアセンブリでFizzBuzz

  • 24
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

自己紹介

  • opengl-8080
  • 主に Qiita で技術メモを書いたり
  • 普段は公私ともに JavaJava
  • Scala 歴 2ヶ月くらい

そんな Scala 初心者な私ですが、
頑張って FizzBuzz を書いてみました


コードをお見せする前に。。。


2つの予備知識

  1. アセンブリ言語とは
  2. CASL とは

2つの予備知識

  1. アセンブリ言語とは
  2. CASL とは

アセンブリ言語とは

  • プログラミング言語の1つ
  • 機械語と1対1で対応する命令(ニーモニック)でプログラムを記述する
  • プロセッサごとに異なる

2つの予備知識

  1. アセンブリ言語とは
  2. CASL とは

CASL とは

  • アセンブリ言語の1つ
  • 情報処理技術者試験で使用される
  • 特定のアセンブリ言語習得者が有利にならないように作られた架空の言語

CASL とは

HelloWorld
MAIN  START
      OUT MSG,LEN         ; メッセージを出力
      RET                 ; 終了
MSG   DC  'Hello World!'  ; 出力メッセージ
LEN   DC  13              ; メッセージの長さ
      END

※セミコロンの後ろはコメント


CASL 初心者が FizzBuzz を書いたらこうなった

※とりあえず1~100まで動くようにしただけなので、きれいな例ではないです

MAIN  START
        LD   GR5,BEGINIDX
        CALL LOOP

LOOP    CPA  GR5,ENDIDX    ; 100 と比較
        JPL  FINISH        ; GR5 > 100 なら終了
        LD   GR1,GR5
        LD   GR2,FIFTEEN
        CALL DIVIDE        ; 15 で割る
        CPA  GR4,ZERO      ; あまりを 0 と比較
        JZE  PUTFZBZ       ; 15 で割り切れたら fizzbuzz 出力
        LD   GR1,GR5
        LD   GR2,FIVE
        CALL DIVIDE        ; 5 で割る
        CPA  GR4,ZERO
        JZE  PUTBUZZ       ; 割り切れたら buzz 出力
        LD   GR1,GR5
        LD   GR2,THREE
        CALL DIVIDE        ; 3 で割る
        CPA  GR4,ZERO
        JZE  PUTFIZZ       ; 割り切れたら fizz 出力
        CALL MSGHUND
        JUMP COUNTUP
PUTFIZZ OUT  FIZZ,LEN4     ; fizz 出力
        JUMP COUNTUP
PUTBUZZ OUT  BUZZ,LEN4     ; buzz 出力
        JUMP COUNTUP
PUTFZBZ OUT  FIZZBUZZ,LEN8 ; fizzbuzz 出力
        JUMP COUNTUP
COUNTUP ADDA GR5,ONE       ; 1加算して次のループへ
        JUMP LOOP
FINISH  RET

; GR5 出力する数値
; GR6 現在のメッセージサイズ
; GR7 文字保存一時領域
MSGHUND LD   GR6,ZERO
        LD   GR1,GR5
        LD   GR2,HUNDRED
        CALL DIVIDE
        CPA  GR3,ZERO
        JMI  MSGTEN
        JZE  MSGTEN
        LD   GR7,NUM,GR3
        ST   GR7,MSG,GR6
        ADDA GR6,ONE
MSGTEN  LD   GR1,GR4
        LD   GR2,TEN
        CALL DIVIDE
        CPA  GR3,ZERO
        JMI  MSGONE
        JZE  MSGONE
        LD   GR7,NUM,GR3
        ST   GR7,MSG,GR6
        ADDA GR6,ONE
MSGONE  LD   GR7,NUM,GR4
        ST   GR7,MSG,GR6
        ADDA GR6,ONE
        ST   GR6,LEN
        OUT  MSG,LEN
        RET

; GR1 割られる数
; GR2 割る数
; GR3 商
; GR4 余り
DIVIDE LD   GR3,ZERO  ; 商を初期化
       JUMP DNEXT     ; 割り算開始
DNEXT  CPA  GR1,GR2   ; 割れるか検証
       JMI  DIVEND    ; 割れないなら終了
       SUBA GR1,GR2   ; GR1 - GR2
       ADDA GR3,ONE   ; 商を加算
       JUMP DNEXT     ; 次のステップ
DIVEND LD  GR4,GR1    ; 余りを GR4 に保存
       RET            ; 割り算終了


BEGINIDX DC 1           ; 開始インデックス
ENDIDX   DC 100         ; 終了インデックス

FIZZ     DC 'fizz'      ; fizzメッセージ
BUZZ     DC 'buzz'      ; buzzメッセージ
FIZZBUZZ DC 'fizzbuzz'  ; fizzbuzzメッセージ
LEN1     DC 1           ; 長さ1
LEN4     DC 4           ; 長さ4
LEN8     DC 8           ; 長さ8

ZERO     DC 0           ; 数値0
ONE      DC 1           ; 数値1
THREE    DC 3           ; 数値3
FIVE     DC 5           ; 数値5
TEN      DC 10          ; 数値10
FIFTEEN  DC 15          ; 数値15
HUNDRED  DC 100         ; 数値100

NUM DC '0123456789'     ; 文字変換テーブル
MSG DS 3                ; 数値出力用メッセージ領域
LEN DS 1                ; 数値文字列の長さ

    END

(´・ω・`) oya?


おわかりいただけただろうか?


Scala はドットとメソッド引数の括弧を省略できる

object MyObject {
  def method(args: String) {}
}

     ↓

MyObject.method("args")

     ↓

MyObject method "args"

アセンブリ言語(CASL)

MSG   DC  'Hello World!'

2つを並べてみると...

Scala

MyObject method "args"

CASL

MSG   DC  'Hello World!'

(`・ω・´)似てる!


ということで
Scala で CASL 風に FizzBuzz を書いてみました


Scala で CASL 風に FizzBuzz

package fizzbuzz

import casl.Implicits._
import casl.Register._
import casl._
import casl.operations._
import fizzbuzz.Comments._
import fizzbuzz.Variables._

object FizzBuzz {

  def main(args: Array[String]): Unit = {
    MAIN START

             LD   GR5 BEGINIDX   ; プインデックスを初期化
             CALL LOOP           ; メインルプ開始}

   {LOOP    {CPA  GR5 ENDIDX     ; プ終了条件確認
             JPL  FINISH         ; GR5がENDIDXより大きければ終了
             LD   GR1 GR5
             LD   GR2 FIFTEEN
             CALL DIVIDE         ; 現在の数を15で割る
             CPA  GR4 ZERO
             JZE  PUTFZBZ        ; 割り切れたらfizzbuzz出力
             LD   GR1 GR5
             LD   GR2 FIVE
             CALL DIVIDE         ; 現在の数を5で割る
             CPA  GR4 ZERO
             JZE  PUTBUZZ        ; 割り切れたらbuzz出力
             LD   GR1 GR5
             LD   GR2 THREE
             CALL DIVIDE         ; 現在の数を3で割る
             CPA  GR4 ZERO
             JZE  PUTFIZZ        ; 割り切れたらfizz出力
             CALL MSGHUND        ; 割り切れなかったら数字をそのまま出力
             JUMP COUNTUP        ; カウントアップへ}
    PUTFIZZ {OUT  FIZZ LEN4      ; fizz出力
             JUMP COUNTUP        ; カウントアップへ}
    PUTBUZZ {OUT  BUZZ LEN4      ; buzz出力
             JUMP COUNTUP        ; カウントアップへ}
    PUTFZBZ {OUT  FIZZBUZZ LEN8  ; fizzbuzz出力
             JUMP COUNTUP        ; カウントアップへ}
    COUNTUP {ADDA GR5 ONE        ; カウントを進めて
             JUMP LOOP           ; 次のルプへ}
    FINISH  {RET                 ; プ終了}

    ; GR5_出力する値
    ; GR6_現在のメッセジサイズ
    ; GR7_文字保存一時領域
    MSGHUND {LD   GR6 ZERO
             LD   GR1 GR5
             LD   GR2 HUNDRED
             CALL DIVIDE         ; 現在の数を100で割る
             CPA  GR3 ZERO
             JMI  MSGTEN         ; 商がない場合は10の位の出力へ
             JZE  MSGTEN         ; 商がない場合は10の位の出力へ
             LD   GR7 NUM GR3    ; 商を一時領域に退避
             ST   GR7 MSG GR6    ; 退避した商を最終出力する文字列に格納
             ADDA GR6 ONE        ; 文字の位置をつ移動
             JUMP MSGTEN         ; 続いて10の位を出力}
    MSGTEN  {LD   GR1 GR4
             LD   GR2 TEN
             CALL DIVIDE         ; 現在の数を10で割る
             CPA  GR3 ZERO
             JMI  MSGONE         ; 商がない場合は1の位の出力へ
             JZE  MSGONE         ; 商がない場合は1の位の出力へ
             LD   GR7 NUM GR3    ; 商を一時領域に退避
             ST   GR7 MSG GR6    ; 退避した商を最終出力する文字列に格納
             ADDA GR6 ONE        ; 文字の位置をつ移動
             JUMP MSGONE         ; 続いて1の位を出力}
    MSGONE  {LD   GR7 NUM GR4    ; 余りを一時領域に退避
             ST   GR7 MSG GR6    ; 退避していた余りを最終出力する文字列に格納
             ADDA GR6 ONE        ; 文字の位置をつ移動
             ST   GR6 LEN
             OUT  MSG LEN
             RET                 ; 数値出力終了}

    ; 割り算処理
    ; GR1_割られる数
    ; GR2_割る数
    ; GR3_
    ; GR4_余り
    DIVIDE  {LD   GR3 ZERO       ; 商を初期化
             JUMP DNEXT          ; 割り算開始}
    DNEXT   {CPA  GR1 GR2        ; 割れるか検証
             JMI  DIVEND         ; 割れないなら終了
             SUBA GR1 GR2        ; GR1からGR2を引く
             ADDA GR3 ONE        ; 商を加算
             JUMP DNEXT          ; 次のステップ}
    DIVEND  {LD   GR4 GR1        ; 余りをGR4に保存
             RET                 ; 割り算終了}

    ; 変数定義
    BEGINIDX DC 1
    ENDIDX   DC 100

    FIZZ     DC "fizz"
    BUZZ     DC "buzz"
    FIZZBUZZ DC "fizzbuzz"
    LEN1     DC 1
    LEN4     DC 4
    LEN8     DC 8

    ZERO     DC 0
    ONE      DC 1
    THREE    DC 3
    FIVE     DC 5
    TEN      DC 10
    FIFTEEN  DC 15
    HUNDRED  DC 100

    NUM      DC "0123456789"
    MSG      DS 3
    LEN      DS 1

    END}
}

え、ソレ動くの?


デモ

1が出力されるまで

fizzbuzz.gif


結論


Scala すごい!


   ∧,,∧ まじめに Scala やってる方
 ( ´・ω・) ごめんなさい
 c(,_U_U

以上


ソースコード

https://github.com/opengl-8080/scala-de-casl-de-fissbuzz


参考