Scala上でアセンブリでFizzBuzz

More than 1 year has passed since last update.


自己紹介


  • 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



参考