アプリ版:「スタンプのみでお礼する」機能のリリースについて

アセンブリ言語の質問です。8086アセンブラで「筆算的加減算」のプログラムを組むことになりました。
2個の整数(3桁)を入力し、入力エラーも処理する様にしなければなりません。また、


  123     234         1        100
+456    -123     +999       -200
ーーーー   ----    ----     ----
 579      111      1000       -100


のように表示する事が条件になっています。

プログラムを組む上で、何かアドバイスやヒント等、教えていただけないでしょうか・・?

A 回答 (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バイト分しかない。

※ラベルと擬似命令、命令とオペランドの間に空白が
ありません。
    • good
    • 0

#3です。


いきなり間違ってた。
最後のMOVが間違い
誤:MOV DI,DX
正:MOV DX,DI

この回答への補足

一応、途中まで組んでみました。
;-----------------------------
;筆算的加減算
;-----------------------------
Codesegment
Codeends
Datasegment
Dataends
Stacksegment stack
Stackends
;-----------------------------
;Data Segment
;-----------------------------
Datasegment
IN_BUFdb4
db0
db3 dup(0)
db0

VALUE_0dw0;入力した値1
VALUE_1dw0;入力した値2
RESULTdw0;結果

EXPRESSIONdb'';式
TENdw10

OUT_BUFdb0Ah,0Dh;改行
OUT_DATA_0db'';入力した値1を出力
db0Ah,0Dh;改行
OUT_EXPRESSIONdb'';式
OUT_DATA_1db'';入力した値2を出力
db0Ah,0Dh;改行
db'------',0Ah,0Dh;筆算の線と改行
OUT_CODEdb'';符号
OUT_RESULTdb'';計算結果
db0Ah,0Dh,'$';改行と終了

MSG_0db'アセンブリ 筆算的出力プログラム',0Ah,0Dh,'$'
MSG_1db'1つめの値を入力してください==>','$'
MSG_2db0Ah,0Dh
db'+か-を入力してください','$'
0Ah,0Dh
MSG_3db'2つめの値を入力してください==>','$'

MSG_Edb0Ah,0Dh,'エラー発生!もう一度やり直してください。'

Dataends

;-----------------------------
;Stack Segment
;-----------------------------
Stacksegment stack
dw100hdup(?)
Stackends

;-----------------------------
;Code Segment
;-----------------------------
Codesegment
assumecs:Code,ds:Data,ss:Stack
;-----------------------------
;Program MAIN start
;-----------------------------
Mainprocnear
movax,Data;set DATA segment
movds,ax
;-----------------------------メッセージ出力
movah,09h
movdx,offset MSG_0
int21h

movah,09h
movdx,offset MSG_3;2つめの値
int21h
;-----------------------------値1の入力
movah,09h
movdx,offset MSG_1
int21h

こんな感じなんですけど、続きをどうすればよいか、教えてもらえませんか・・?

補足日時:2010/07/29 23:13
    • good
    • 0

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

途中、レジスタの使い方とか、突っ込まれても
大丈夫なように、よく噛み砕いて使ってください。
あと、デバッグしてないから間違ってたらゴメン
    • good
    • 0

プログラムを組む上でのアドバイスではなくて恐縮ですが質問をする上でのアドバイスを


質問するときは環境を具体的に書かれたほうがいいです
アセンブラの種類やパソコンのOSなどできるだけ細かいほうがいいですね
プログラムの仕様ももっと詳しい方が回答も得られやすいです
実際の入力と出力の例も書いたほうがいいです
あと一番いいのは自分が書いたコードをコピーしてアドバイスを求めることですね
    • good
    • 0

別に普通に加算命令(ADD,ADC)と減算命令(SUB,SBB)を使えば良いだけじゃないですか?


レジスタは16bitなので3桁の整数など余裕で扱えるし、他に二進化十進数やアンパック十進数で計算する方法もあります、その為の命令もありますしね。
それよりも入力や出力で数値を変換する部分が大変ですね。
普通はBIOSやAPIなどで入出力の仕様が定義されていて、それに合わせて変換するサブルーチンを作って呼び出しますね。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!