- ベストアンサー
アセンブリ言語の質問です。8086アセンブラで「筆算的加減算」のプログ
アセンブリ言語の質問です。8086アセンブラで「筆算的加減算」のプログラムを組むことになりました。 2個の整数(3桁)を入力し、入力エラーも処理する様にしなければなりません。また、 123 234 1 100 +456 -123 +999 -200 ーーーー ---- ---- ---- 579 111 1000 -100 のように表示する事が条件になっています。 プログラムを組む上で、何かアドバイスやヒント等、教えていただけないでしょうか・・?
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
全部面倒見ないとイケナイかな。 字数の関係があるから、答えを全ては書けません。 よって、今回は考え方のみ記述しますね。 (1)初期処理 ・セグメントレジスタの設定(既にやっている) ・初期メッセージの表示 (2)中核処理 これは^Cを入力すれば止まるのだから、 無限ループで良いでしょう。以下のことをします。 (a)数値1の入力を促すメッセージを表示する (b)数値1を入力する (c)入力値をチェックする エラー時はメッセージを表示して(a)に戻る (d)演算子(+か-)を入力する 上記以外はメッセージを表示して(a)に戻る (e)数値2の入力を促すメッセージを表示する (f)数値2を入力する (g)入力値をチェックする エラー時はメッセージを表示して(d)に戻る (h)数値1と数値2を(d)に基づいて加減算する (i)結果を編集し、表示を行う 観念的なコード CALL 初期処理 MUGEN: ;ここから(2) CALL 数値1入力 JC MUGEN ;エラー時は戻る CALL 演算子入力 JC MUGEN ;エラー時は戻る CALL 数値2入力 JC MUGEN ;エラー時は戻る CALL 演算 CALL 結果編集 CALL 表示処理 JMP MUGEN ;戻る 疑問点の指摘 (1)復帰改行 0Ah,0Dh とあるが、普通は0Dh,0Ah 文字通り、 復帰(0Dh)、改行(0Ah)の順に書く。後退法の 心配をしたと思うが、DW擬似命令の場合話で、 DB擬似命令では書いた順にメモリに格納される。 (2)セグメントレジスタの設定 mov ax,Data → mov ax,SEG IN_BUF 20年くらい前にやってたことなんで自信ないが、 こう書くような気がする。それと、COM(TINY) 形式の場合はDSの設定は不要です。 おまじないで入れときましょうか。 (3)OUT_DATA_0など バッファド入出力(機能コード:10)を使えば、 入力値の再表示は不要なので、OUT_DATA_0 等は 不要です。ちょっと工夫が要るけどね。 (4)結果表示領域 結果が何ケタになるのか分からないのに、領域が 1バイト分しかない。 ※ラベルと擬似命令、命令とオペランドの間に空白が ありません。
その他の回答 (4)
- nda23
- ベストアンサー率54% (777/1415)
#3です。 いきなり間違ってた。 最後のMOVが間違い 誤:MOV DI,DX 正:MOV DX,DI
- nda23
- ベストアンサー率54% (777/1415)
DOS上での話と仮定します。 (1)文字列の入力 文字数の上限を指定して、エコーバックやバックスペースも行う 0Ahという機能コードを使います。 X DB 5 ;入力文字数(符号、数字3桁、リターンを含む) N DB ? ;実際に入力されたバイト数が返る領域 D DB 5 DUP (?) ;入力領域 MOV AH,0Ah MOV DX,OFFSET X INT 21h (2)入力チェックと数値変換 AXに変換値が入る。Cy=0:正常/Cy=1:エラー CONV: MOV BX,1 ;BH←0、BL←1 MOV SI,OFFSET N ;実入力バイト数のアドレス CLD ;デクリメントフラグクリア LODSB ;AL←[SI++]=実入力バイト数 CBW ;符号拡張(AH←0) CDW ;符号拡張(DX←0) XCHG AX,CX ;CX←実入力バイト数 JCXZ C4 ;CX=0(未入力)なら出口へ分岐 C1: LODSB ;AL←[SI++] CMP AL,'+' JE C2 ;"+"であればC2へ分岐 CMP AL,'-' JNE C3 ;"-"でなければC3へ分岐 C2: OR BH,BH ;最初かどうか調べる JNZ C4 ;最初でなければ出口へ分岐 C3: SUB AL,'0' ;文字コードを減じて数値化する JB C4 ;0未満なら出口へ分岐 CMP AL,9 ;9と比較 JA C4 ;9より大きければ出口へ分岐 CBW ;符号拡張(AH←0) XCHG AX,DI ;数値をDIに退避 MOV AX,10 ;10倍するための定数 MUL DX ;既存の値を10倍 ADD AX,DI ;先程の数値を加算 MOV DX,AX ;DXに変換値を記録 OR BH,1 ;文字が検査済みであることを記録 LOOP C1 ;--CX !=0 ならC1へ分岐 DEC BX ;BL←0(ここまで来れば正常) CMP BH,'-' ;ハイフンがあったか調べる JNZ C4 ;ハイフンが無ければ出口へ分岐 NEG AX ;マイナスにする C4: SHR BL,1 ;BLを右シフトしてCyへ結果を反映させる RET (3)数値表示 AXに数値があるとする B DB 5 DUP (?) ;文字格納領域 DB 0Dh,0Ah,'$' ;復帰、改行、終端記号 DISP: MOV DI,OFFSET B[5];ポインタを初期化 XOR CX,CX ;CX←0 符号 MOV BL,10 ;定数 OR AX,AX ;マイナスかどうか調べる JGE D1 INC CX ;マイナスを記録 NEG AX D1: CBW ;符号拡張 DIV BL ;AXをBLで除算 XCHG AL,AH ;商と剰余を入れ替える ADD AL,'0' ;文字コード化する DEC DI ;ポインタを更新する MOV [DI],AL ;格納する XCHG AL,AH ;商と剰余を入れ替える OR AL,AL ;0かどうかを調べる JNZ D1 ;ゼロでなければ続ける JCXZ D2;CX=0なら分岐 DEC DI ;ポインタを更新する MOV [DI],BYTE PTR '-' ;符号を格納する D2: MOV AH,09h ;機能コード MOV DI,DX ;データ領域 INT 21h RET 途中、レジスタの使い方とか、突っ込まれても 大丈夫なように、よく噛み砕いて使ってください。 あと、デバッグしてないから間違ってたらゴメン
- php504
- ベストアンサー率42% (926/2160)
プログラムを組む上でのアドバイスではなくて恐縮ですが質問をする上でのアドバイスを 質問するときは環境を具体的に書かれたほうがいいです アセンブラの種類やパソコンのOSなどできるだけ細かいほうがいいですね プログラムの仕様ももっと詳しい方が回答も得られやすいです 実際の入力と出力の例も書いたほうがいいです あと一番いいのは自分が書いたコードをコピーしてアドバイスを求めることですね
- yama1718
- ベストアンサー率41% (670/1618)
別に普通に加算命令(ADD,ADC)と減算命令(SUB,SBB)を使えば良いだけじゃないですか? レジスタは16bitなので3桁の整数など余裕で扱えるし、他に二進化十進数やアンパック十進数で計算する方法もあります、その為の命令もありますしね。 それよりも入力や出力で数値を変換する部分が大変ですね。 普通はBIOSやAPIなどで入出力の仕様が定義されていて、それに合わせて変換するサブルーチンを作って呼び出しますね。
補足
一応、途中まで組んでみました。 ;----------------------------- ; 筆算的加減算 ;----------------------------- Code segment Code ends Data segment Data ends Stack segment stack Stack ends ;----------------------------- ; Data Segment ;----------------------------- Data segment IN_BUF db 4 db 0 db 3 dup(0) db 0 VALUE_0 dw 0 ;入力した値1 VALUE_1 dw 0 ;入力した値2 RESULT dw 0 ;結果 EXPRESSION db ' ' ;式 TEN dw 10 OUT_BUF db 0Ah,0Dh ;改行 OUT_DATA_0 db ' ' ;入力した値1を出力 db 0Ah,0Dh ;改行 OUT_EXPRESSION db ' ' ;式 OUT_DATA_1 db ' ' ;入力した値2を出力 db 0Ah,0Dh ;改行 db '------',0Ah,0Dh ;筆算の線と改行 OUT_CODE db ' ' ;符号 OUT_RESULT db ' ' ;計算結果 db 0Ah,0Dh,'$' ;改行と終了 MSG_0 db 'アセンブリ 筆算的出力プログラム',0Ah,0Dh,'$' MSG_1 db '1つめの値を入力してください==>','$' MSG_2 db 0Ah,0Dh db '+か-を入力してください','$' 0Ah,0Dh MSG_3 db '2つめの値を入力してください==>','$' MSG_E db 0Ah,0Dh,'エラー発生!もう一度やり直してください。' Data ends ;----------------------------- ; Stack Segment ;----------------------------- Stack segment stack dw 100h dup(?) Stack ends ;----------------------------- ; Code Segment ;----------------------------- Code segment assume cs:Code,ds:Data,ss:Stack ;----------------------------- ; Program MAIN start ;----------------------------- Main proc near mov ax,Data ;set DATA segment mov ds,ax ;-----------------------------メッセージ出力 mov ah,09h mov dx,offset MSG_0 int 21h mov ah,09h mov dx,offset MSG_3 ;2つめの値 int 21h ;-----------------------------値1の入力 mov ah,09h mov dx,offset MSG_1 int 21h こんな感じなんですけど、続きをどうすればよいか、教えてもらえませんか・・?