平成26春の過去問問12 アセンブラ のプログラミング(コメント、トレースのノート付き)

この記事では、過去問のアセンブラの問題に載っているプログラムを実際に自分の環境で作成して動かすのに使ったコードと、トレースのノートを掲載しています。
この記事を通してアセンブラだけでなくアルゴリズムのトレース力向上にもお役立て下さい。

アセンブラ過去問プログラミング
アセンブラ自作サンプルへ
基本情報技術者試験トップへ
令和2年度(令和3年1月合格報告)

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
この問題は平成30年春のアセンブラの問題と似ています。

文字列の中から単語を切り出して、「その文字列の先頭アドレス、文字数、全部数字か英文字も含まれているかの種別」を単語管理テーブルに収めるプログラムです。

文字列の領域をMOJI、先頭アドレスをMOJI+0として、この問題の環境ではMOJI+0が100番地になるようです。
種別は全部数字の時は0、英字を含む時は1です。

単語管理テーブル領域はKANRI、先頭アドレスをKANRI+0とします。
問題文のプログラム1、GETTKNは主プログラムはGR1にMOJI+0、GR2にKANRI+0を設定してから呼びます。

トレースは、時間短縮の為、設問1、設問2が一気に解けるように、設問2の具体例を使います。スペースを△と表すので、「△1A2B△C3.」をMOJI領域に入れて、KANRIは「101,4,1,106,2,1,-1」となります。
最初の文字列「1A2B」は101番地から始まって4文字、英字を含むから種別が1で「101,4,1」次の文字列「C3」は106番地から始まって2文字で英字を含むから種別が1で「106,2,1」、最後が終端マークで「-1」が入ります。

では、主プログラムとプログラム1のGETTKNをプログラミングしてトレースをします。単語管理テーブルKANRIは、とりあえず10個ぐらいの領域を用意します。

では、主プログラムとプログラム1のプログラミングが終わりましたので、シミュレーターを動かしながらトレースをして設問1、2を解きます。
文字列の領域MOJIに、「△1A2B△C3.」が入りました。文字コードが入っています。この問題のアドレス100番地が、私のお家の環境ですと、MOJIの左を見ていくと「101C」に当たります。

次に、単語管理テーブルの領域を10個用意しました。

GR1に100番地に当たるアドレス101Cが入りました。

GR2にKANRI+0番地が入りました。

GR3に種別の初期化の「-1」が入りました。

ループLPに入る前にアドレスが調整されました。
99番地に当たる101Bが入りました。

ループLPに入り、アドレスが+1され、100番地に当たる101Cが入りました。

GR4に文字列「△1A2B△C3.」から、最初の「△」が取り出されました。

文字コード0020

GR3が0かどうかみます。
-1なので何もしないです。

文字列のアドレスが1つ先に進み、101番地にあたる101Dを指しました。

GR4に文字列「△1A2B△C3.」から「1」が取り出されました。

文字コード0031

文字列の取り出し処理が開始になるので、GR3に0が読み込まれました。
種別が0で数字だけからなるになりました。

処理開始の文字列のアドレス101番(101D)がGR6に退避されました。
これは後でアドレスの差から文字数を求めるのに使います。

文字列のアドレスが1つ先に進み、102番地にあたる101Eを指しました。

GR4に文字列「△1A2B△C3.」から「A」が取り出されました。

文字コード0041

英文字を含むのでGR3に1が設定されました。

文字列のアドレスが1つ先に進み、103番地にあたる101Fを指しました。

GR4に文字列「△1A2B△C3.」から「2」が取り出されました。

文字コード0032

文字列のアドレスが1つ先に進み、104番地にあたる1020を指しました。

GR4に文字列「△1A2B△C3.」から「B」が取り出されました。

文字コード0042

文字列のアドレスが1つ先に進み、105番地にあたる1021を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「△」が取り出されました。

文字コード0020

△なので、格納処理に進みます。
文字列「△1A2B△C3.」の先頭の「1」、101番地に当たる101Dが管理テーブルの先頭に格納されました。

現在の文字列を指すアドレス105番に当たる1021がGR5に退避されました。

105番地から(1021)101番地(101D)を引いた4が文字数としてGR5に求まりました。

文字数の4と、英数字混合の文字種1が単語管理テーブルに格納されました。

次の文字切り出し用にGR3を-1で初期化しました。

単語管理テーブルのアドレスが3つ進んで、次の単語切り出し用の準備になりました。

文字列のアドレスが1つ先に進み、106番地にあたる1022を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「C」が取り出されました。

文字コード0043・・・設問2

フラグが-1から0になりました。
処理中として、暫定的に全て数字を表す0が入りました。

GR6に今指しているアドレス、106番地に当たる1022が入りました。

「C」は9より大きいので英文字が含まれるため、GR3のフラグが1になりました。

文字列のアドレスが1つ先に進み、107番地にある1023を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「3」が取り出されました。

文字コード0033

文字列のアドレスが1つ先に進み、108番地にある1024を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「.」が取り出されました。

文字コード002E

「.」なので終了処理に入ります。

単語管理テーブルに文字列「C3」の先頭のアドレスが入りました。

GR5に文字列の現在指しているアドレス108番地に当たる1024が入りました。

アドレス108番地に当たる1024から、アドレス106番地に当たる1022を引いて2が文字数として求まりました。

「C3」のアドレス、文字数、種別が入りました。

終端マークの-1が入りました。

以上でプログラム1、設問1、2のトレースを終わります。

プログラミングのコードとトレースに使ったノートの写真です。

;平成26春主プログラムとプログラム1
;設問1、2
;主プログラム
MAIN START
RPUSH
LAD GR1,MOJI ;設問2の具体例の文字列を用意
LAD GR2,KANRI ;単語管理テーブルの領域をとりあえず10個確保
CALL GETTKN ;プログラム1を呼ぶ
RPOP
RET
MOJI DC ‘ 1A2B C3.’ ;文字列
KANRI DS 10 ;単語管理テーブル
;プログラム1
GETTKN
RPUSH
LD GR3,=-1 ;単語種別の初期化
LAD GR1,-1,GR1 ;文字列の位置調整
LP LAD GR1,1,GR1 ;MOJIの位置を順番に指す
LD GR4,0,GR1 ;1文字取り出す(↑で指した位置の中身を入れる)
CPL GR4,=’.’ ;比較
JZE FIN ;[.]なら終わり
CPL GR4,=’ ‘ ;比較
JNZ ALNUM ;[△]なら格納処理へ
CALL SETTKN ;単語管理テーブルへの格納処理へ
JUMP LP ;文字の取り出し処理へ「空欄a」
ALNUM LD GR3,GR3 ;0ですか?(単語の処理中?)
JPL LP ;処理中の単語が英字を含む場合はLPへ
JZE ACHK ;処理中の単語が数字だけからなる場合はACHKへ
LD GR3,=0 ;次の単語の処理開始
;単語種別を”数字だけからなる”に設定
LD GR6,GR1 ;先頭アドレスを退避(後で文字数の計算に使う)
ACHK CPL GR4,=’9′ ;9よりデカかったら文字決定!
JPL NEXT ;英字を含む処理へ
CPL GR4,=’0′ ;0より小さかったら文字決定!
JMI NEXT ;文字記号を含む処理へ
JUMP LP ;取り出した文字が数字の場合はLPへ
NEXT LD GR3,=1 ;単語種別を”英字を含む”に設定
JUMP LP
FIN CALL SETTKN ;単語管理テーブルへの格納処理へ
LD GR5,=-1
ST GR5,0,GR2 ;終端マークを格納
RPOP
RET
SETTKN LD GR3,GR3 ;0ですか?
JMI FIN2 ;単語処理中でなければ何もしない
ST GR6,0,GR2 ;単語の先頭アドレスを単語管理テーブルに格納
LD GR5,GR1 ;文字列の今のアドレスを入れる
SUBL GR5,GR6 ;今のアドレス-先頭アドレス=文字数が求まる「空欄b」
ST GR5,1,GR2 ;単語の長さを格納
ST GR3,2,GR2 ;単語の種別を格納
LD GR3,=-1 ;単語種別を初期化(処理中状態を解除)
LAD GR2,3,GR2 ;次の語のために単語管理テーブルを進める
FIN2 RET
END

設問3では具体例「12×3」を計算します。
文字列で表すとMOJIに「12△*△3△.」が入ります。
プログラム2のCALCでは、12と3はそれぞれGETTKNを使って数字列を切り出して、
その数字列を2進数の数値に変換して計算するので、DTOBという副プログラムを使って2進数にしてから計算します。
GETTKNを呼ぶ時、単語管理テーブルとして使う領域はCTBLという風呂敷を使って主記憶の場所取りをします。
単語管理テーブルのCTBLは「MOJI+0、2、0、MOJI+3、1、1、MOJI+5、1、0、-1」となります。「MOJI+0、2、0」で、「12×3」の「12」の先頭アドレスと文字数の2、数字だけなので文字種別が0、「MOJI+3、1、1」は、「12×3」の「×」の先頭アドレスと文字数の1、英数字含むので種別が1、「MOJI+5、1、0」は、「12×3」の「3」の先頭アドレスと文字数の1、数字だけの0、最後が終端マークの-1です。

計算するのに使うDTOBでは、数字列の12でしたら2進数で1100に、3でしたら、0011に変換します。×はで表します。演算子は「、+、ダミー、-」の順で領域LTBLに入っています。「MULT、PLUS、ダミー、MINUS」
この順番は文字コードを使って対応させています。
先頭である「*」は、アドレスLTBLの0番値目で0番地という位置は文字コードの差を使っています。*の文字コードは2Aで2A-2Aは0だから0番地、「+」は文字コード2Bで2B-2Aは1だから1番地、ダミーは2Cは、演算とは関係のない文字(,)で2C。2C-2Aは2だから2番地はダミー、「-」は文字コード2Dで2D-2Aは3だから3番地、とそれぞれ対応付けています。

参考 文字コード

設問3の流れをノートに書きました。

では、プログラム2を含めたプログラミングが終わったのでトレースをします。
実行すると主記憶のMOJIに「12△*△3△.」が入りました。

主プログラムでGR1に文字列アドレスMOJI+0が入ってCALCを呼び出します。

GR2に単語管理テーブルのアドレスCTBL+0が入ってGETTKNプログラム1のを呼び出します。「12」と「*」と「3」を切り出し、GR2で指す単語管理テーブルに切り出した単語それぞれの、「先頭アドレス、文字数、種別」が入ります。
CALCに戻って最初の文字「12」のGR2に入っている先頭アドレスをGR1に移して、
DTOBを呼びます。

数字列「12」を数値にして後ろから2×1、1×10を計算して足して数値12にします。
12を表すCが入ってCALCに戻りました。

演算子「*」の文字コードが読まれました。

文字コードから「」の2Aが引かれました。 この場合、なので2A-2Aで0が求まり、演算子テーブルの1番目のMULTを指すのに使います。

2番目の数字列を指す先頭アドレスがGR1に読み込まれて再びDTOBを呼びます。

「3」を数値に変換しました。

CALCに戻って、「12」がGR4、「3」がGR5に入りました。

MULTに分岐しました。
GR4×GR5で、「12×3」を求めます。


36(16進数表記で24)が求まりました。

プログラム2を含むコードと、トレースに使ったノートです。


プログラム1は同じなので画像は省略します。

;平成26春主プログラムとプログラム1、2
;設問3;主プログラム
MAIN START
RPUSH
LAD GR1,MOJI ;計算に使う数字列を含む文字列
CALL CALC ;プログラム2を呼ぶ
RPOP
RET
MOJI DC ’12 * 3 .’ ;文字列「12×3」を求める
;プログラム2
CALC
RPUSH
LAD GR2,CTBL ;管理テーブルの先頭アドレス
CALL GETTKN ;プログラム1を呼んで2つの数字列を切り出す
LD GR1,GR2 ;「空欄c」2進数変換につかうDTOBを呼ぶ準備
CALL DTOB ;数字文字列1を2進数に変換して
LD GR4,GR0 ;GR4に設定する。
LD GR1,3,GR2 ;演算子を取り出す
LD GR3,0,GR1 ;GR3←演算子の文字コード
SUBL GR3,=’*’ ;文字コードの差から分岐による演算処理を調べる
LAD GR1,6,GR2
CALL DTOB ;数字文字列2を2進数に変換して
LD GR5,GR0 ;GR5に設定する。
LD GR3,LTBL,GR3 ;「空欄d」どの演算をするのかLTBLの位置から求めて分岐
JUMP 0,GR3 ;演算して指定された処理にジャンプ
MULT LD GR0,=0 ;乗算MULTに分岐
LD GR5,GR5 ;乗数は0ですか?
LPM JZE FINC
LD GR3,GR5
AND GR3,=#0001 ;乗数の最下位ビットのチェック
JZE NEXTC
ADDL GR0,GR4 ;最下位ビットが0では無かったら加算
NEXTC SLL GR4,1 ;被乗数を1ビット左論理シフト
SRL GR5,1 ;乗数を1ビット右論理シフト
JUMP LPM
PLUS ADDL GR4,GR5 ;加算PLUSに分岐
LD GR0,GR4
JUMP FINC
MINUS SUBL GR4,GR5 ;減算MINUSに分岐
LD GR0,GR4
FINC RPOP
RET
CTBL DS 10 ;GETTKN用単語管理テーブル
LTBL DC MULT ;演算の分岐先アドレステーブル
DC PLUS
DS 1 ;ダミー
DC MINUS
;二進数変換プログラムDTOBでは1の桁(後ろから)から変換していく
DTOB RPUSH
LD GR5,=0
LD GR4,1,GR1 ;文字数を入れる
LAD GR6,KETA ;2進数に直す時の桁が入っているテーブル
LP2
SUBL GR4,=1 ;文字数マイナス1
JMI FINK2 ;これがマイナスになったら終了
LD GR3,0,GR1 ;切り出した文字のアドレスが入る
ADDL GR3,GR4 ;アドレスに文字数マイナス1を加える
LD GR3,0,GR3 ;↑の中身
SUBL GR3,=’0′ ;数値に変換
KAKERU LD GR0,=0 ;乗算処理の初期化
LD GR2,0,GR6 ;乗数になる桁が入っているテーブルの桁を読み込む
JZE FINK
LPK LD GR7,GR2 ;最下位ビットチェックの為に退避
AND GR7,=#0001 ;乗数の最下位ビットのチェック
JZE NEXTD
ADDL GR0,GR3 ;最下位ビットが0では無かったら加算
NEXTD
SLL GR3,1 ;被乗数を1ビット左論理シフト
SRL GR2,1 ;乗数を1ビット右論理シフト
JZE FINK
JUMP LPK
FINK
ADDL GR5,GR0 ;前の桁に今回の桁での演算結果を加える
LAD GR6,1,GR6 ;桁テーブルを1つ進める
JUMP LP2
FINK2 LD GR0,GR5 ;2進数に変換した値を退避
RPOP
RET
KETA DC 1,10,100 ;桁テーブル
;プログラム1
GETTKN
RPUSH
LD GR3,=-1 ;単語種別の初期化
LAD GR1,-1,GR1 ;文字列の位置調整
LP LAD GR1,1,GR1 ;MOJIの位置を順番に指す
LD GR4,0,GR1 ;1文字取り出す(↑で指した位置の中身を入れる)
CPL GR4,=’.’ ;比較
JZE FIN ;[.]なら終わり
CPL GR4,=’ ‘ ;比較
JNZ ALNUM ;[△]なら格納処理へ
CALL SETTKN ;単語管理テーブルへの格納処理へ
JUMP LP ;文字の取り出し処理へ「空欄a」
ALNUM LD GR3,GR3 ;0ですか?(単語の処理中?)
JPL LP ;処理中の単語が英字を含む場合はLPへ
JZE ACHK ;処理中の単語が数字だけからなる場合はACHKへ
LD GR3,=0 ;次の単語の処理開始
;単語種別を”数字だけからなる”に設定
LD GR6,GR1 ;先頭アドレスを退避(後で文字数の計算に使う)
ACHK CPL GR4,=’9′ ;9よりデカかったら文字決定!
JPL NEXT ;英字を含む処理へ
CPL GR4,=’0′ ;0より小さかったら文字決定!
JMI NEXT ;文字記号を含む処理へ
JUMP LP ;取り出した文字が数字の場合はLPへ
NEXT LD GR3,=1 ;単語種別を”英字を含む”に設定
JUMP LP
FIN CALL SETTKN ;単語管理テーブルへの格納処理へ
LD GR5,=-1
ST GR5,0,GR2 ;終端マークを格納
RPOP
RET
SETTKN LD GR3,GR3 ;0ですか?
JMI FIN2 ;単語処理中でなければ何もしない
ST GR6,0,GR2 ;単語の先頭アドレスを単語管理テーブルに格納
LD GR5,GR1 ;文字列の今のアドレスを入れる
SUBL GR5,GR6 ;今のアドレス-先頭アドレス=文字数が求まる「空欄b」
ST GR5,1,GR2 ;単語の長さを格納
ST GR3,2,GR2 ;単語の種別を格納
LD GR3,=-1 ;単語種別を初期化(処理中状態を解除)
LAD GR2,3,GR2 ;次の語のために単語管理テーブルを進める
FIN2 RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに丸二日もかかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
この問題は平成30年春のアセンブラの問題と似ています。

アセンブラ過去問プログラミング
アセンブラ自作サンプルへ
基本情報技術者試験トップへ
息抜きに、写真で癒し(=^・^=)