2011-11-14 11 views
0

私はそれ以下のプログラムは、ユーザからの入力を取得し、ユーザーがそれを再び入るまで、同じ文字列を繰り返すようにしようとしています。しかし、私はそれが正しく実行するために得ることにいくつかの深刻なdiffucultyを持っていますループ/入力ロジックフロー問題(NASMのx86アセンブリ)

(これは個人的な学習プロジェクトです)。過去のスレッドhereでは、この問題に関して他のユーザーが入力した入力、punが表示されます。

Hello! 
Please enter a word or character: 
INPUT: Nick 
I will now repeat this until you type it back to me. 
Nick 
INPUT: Nick 
N 
INPUT: Nick 

INPUT: Nick 

を死へ^ C、それをするまで、それは永遠に行く:

%include "system.inc" 

section .data 
    greet:  db 'Hello!', 0Ah, 'Please enter a word or character:', 0Ah 
    greetL:  equ $-greet  ;length of string 
    inform:  db 'I will now repeat this until you type it back to me.', 0Ah 
    informL: equ $-inform 
    finish:  db 'Good bye!', 0Ah 
    finishL: equ $-finish 
    newline: db 0Ah 
    newlineL: equ $-newline 


section .bss 

input: resb 40 ;first input buffer 
check: resb 40 ;second input buffer 

section .text 

    global _start 
_start: 


greeting: 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, greet 
    mov edx, greetL 
    sys.write 

getword: 
    mov eax, 3 
    mov ebx, 0 
    mov ecx, input 
    mov edx, 40 
    sys.read 

    sub eax, 1 ;remove the newline 
    push eax ;store length for later 

instruct: 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, inform 
    mov edx, informL 
    sys.write 

    pop edx  ;pop length into edx 
    mov ecx, edx ;copy into ecx 
    push ecx ;store ecx again (needed multiple times) 

    mov eax, 4 
    mov ebx, 1 
    mov ecx, input 
    sys.write 

    mov eax, 4 ;print newline 
    mov ebx, 1 
    mov ecx, newline 
    mov edx, newlineL 
    sys.write 

    mov eax, 3 ;get the user's word 
    mov ebx, 0 
    mov ecx, check 
    mov edx, 40 
    sys.read 

    sub eax, 1 
    push eax 

    xor eax, eax 

checker: 
    pop ecx  ;length of check 
    pop ebx  ;length of input 
    mov edx, ebx ;copy 
    cmp ebx, ecx ;see if input was the same as before 

    jne loop ;if not the same go to input again 

    mov ebx, check 
    mov ecx, input 
secondcheck: 

    mov dl, [ebx] 
    cmp dl, [ecx] 
    jne loop  
    inc ebx 
    inc ecx 
    dec eax 
    jnz secondcheck 

    jmp done 

loop: 

    pop edx 
    mov ecx, edx 
    push ecx 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, check 
    sys.write ;repeat the word 

    mov eax, 4 
    mov ebx, 1 
    mov ecx, newline 
    mov edx, newlineL 
    sys.write 
    mov eax, 3 ;replace new input with old 
    mov ebx, 0 
    mov ecx, check 
    mov edx, 40 
    sys.read 

    jmp checker 

done: 

    mov eax, 1 
    mov ebx, 0 
    sys.exit 

例の出力が得られるでしょう。問題のアイデアは?

ありがとうございました。

答えて

1

instructcheckerによってループラウンド最初に消費されるスタック上の2つのアイテムを残します。しかし、あなたは再びループを回る場合には置き換えられません。これはあなたのコードの中で最も根本的な問題です(他にもあるかもしれません)。

あなたは、デバッガで実行し、スタックポインタespを見て、これを見つけることができます。スタック操作と分岐を除いてすべてをとった場合、checker - >loop - >checkerに戻ると、3つのアイテムがポップされますが、1つのみがプッシュされることがわかります。

greeting: 
    ... 
getword: 
    ... 
    push eax ;store length for later 
instruct: 
    ... 
    pop edx  ;pop length into edx 
    ... 
    push ecx ;store ecx again (needed multiple times) 
    ... 
    push eax 
checker: 
    pop ecx  ;length of check 
    pop ebx  ;length of input 
    ... 
    jne loop ;if not the same go to input again 
    ... 
secondcheck: 
    ... 
    jne loop  
    ... 
    jnz secondcheck 
    jmp done 
loop: 
    pop edx 
    ... 
    push ecx 
    ... 
    jmp checker 
done: 
    ... 

pushpopで、このようなスタック上にそれらを周りシャッフルしようとするよりも長寿命の変数を維持するためのより良い方法があります。

  1. データセクション(すでに適切である必要があり.bss)ではなく、スタック上に保管してください。

  2. はスタック上にいくつかの領域を割り当て、およびロード/直接そこに保管してください。例えばsub esp, 8を使用して2つの32ビットワードを予約した後、[esp]および[esp+4]にアクセスしてください。 (スタックは32ビット境界に合わせる必要がありますので、常に4バイトの倍数を予約してください)。使用を終了したらadd esp, 8を覚えておいてください。

(これらは基本的にCコンパイラは、それぞれ、)グローバル(またはstatic変数、およびローカル変数のために何をするのかに相当します。)

+0

ありがとうございました!私は仕事に着くとすぐに結果を知らせる! – nmagerko

関連する問題