Assembler - zamiana małych liter na wielkie

0

Witam,

Mam za zadanie napisać program, który wczytuje litery z klawiatury, po czym małe litery zamienia na wielkie i wypisuje je na ekranie.
Poniżej wkleiłem mój kod, walczę z tym już od kilku godzin. Proszę o pomoc :(

org 100h

start: 
	xor di,di
read:
	mov ah,1 ; odczytuje znak z klawiatury i wypisuje na ekran
	int 21h
	inc di
	cmp al, 97
	jg capital
	cmp al, 122
	jl capital
	mov [tablica+di], al ; przypisanie znaku do wyświetlenia
	cmp al,13
	jne read

	mov cx,di
	mov ah,2
	jmp print
capital:
	sub al, 32
	mov [tablica+di], al
	jmp read
print:
	mov si,di
	sub si,cx
	mov dx, [tablica+si]
	int 21h
	loop print

mov ax, 4c00h
int 21h

tablica TIMES 50 db 0
0
    cmp al, 97
    jg capital
    cmp al, 122
    jl capital

To jest źle i dalej już nie czytałem. W twoim przypadku dla znaku numer 123 też uznasz że jest w zasięgu. Podobnie dla znaków 0-97, bo co prawda pierwszego cmp nie przejdą ale drugie już tak. Musisz sprawdzic oba warunku i dopiero kiedy oba na raz są spełnione to konwertować. BTW w kodzie MOŻNA używać literałów zamiast magicznych liczb. Tak trudno napisać A zamiast numerka z d**y?

0

do tego jg i jl służą do porównywania liczb ze znakiem (+/-), co w przypadku 8-bitowego rejestru oznacza zakres -128..+127.
w przypadku znaków (=literek) potrzebny jest zakres 0..255, czyli instrukcje ja (jump if above) i jb (jump if below)

na działanie powyższego programu to nie będzie jednak miało wpływu - jeśli nie bierzemy pod uwagę polskich liter i innych znaków specjalnych.

    cmp al, 'A'
    jb not_capital
    cmp al, 'Z'
    ja not_capital
capital:
0

Przykład w NASM 32Bit:

global _main
extern _printf
extern _scanf

section .data
prosba    db    "Prosze wpisac lancuch: ", 0
fmt       dd    "%s", 0

section .bss
dane    resd    254

section .text
wypelnij:
    push prosba
    call _printf
    add esp, 4
    
    push dane
    push fmt
    call _scanf
    add esp, 8
    ret
    
kapitaluj:
    mov al, byte[dane+ebx]
    cmp al, 'Z'
    jle dalej
    
    sub dword[dane+ebx], ' '
    dalej:
    inc ebx   
    cmp dword[dane+ebx], 0
    jne kapitaluj
    ret
    
wypisz:
    push dane
    call _printf
    add esp, 4
    ret

_main:
    call wypelnij
    mov ebx, 0
    call kapitaluj
    call wypisz
    
_koniec:
    xor eax, eax
    ret

Wcale nie jest trudniejszy niż szesnastka.

0

@grzesiek51114 boś tego nie napisał w gołym asemblerze tylko korzystasz z zewnętrznych zabawek jak printf ;) A w nauce podstaw warto też wiedzieć co to są przerwania albo np. jak rysować po ekranie poprzez pisanie po pamięci karty graficznej.

0

Na wstępie zaznaczę, że z Assemblera miałem 3 ćwiczenia, a wcześniej 4 wykłady teorii o architekturze von Neumanna, rejestrach czy działaniach na liczbach binarnych. Moja wiedza na ten temat jest strasznie uboga. Na ćwiczeniach robiliśmy proste programy typu Hello World, dodawanie, odejmowanie, mnożenie, dzielenie liczb i echo liter, a teraz prof. kazał zrobić coś takiego samodzielnie...

@Shalom
Jeżeli chodzi o te numerki to w kodzie ASCII numery 97-122 odpowiadają literom a-z. Numery 65-90 odpowiadają literom A-Z. Litery małe na wielkie zamieniam poprzez odjęcie różnicy, która jest stała i wynosi 32. Takie podpowiedzi otrzymałem od profesora, dlatego tak to próbowałem rozwiązać :(

@Azarien
To samo co wyżej. Profesor dał mi taką podpowiedź, dlatego użyłem jg i jl. O ja i jb w ogóle nie miałem pojęcia, że istnieją :(

Poprawiłem kod, ale co do uwagi @Shalom (sprawdzania obydwu warunków i dopiero skok) nie mam pojęcia jak to zapisać.

org 100h

start: 
	xor di,di
read:
	mov ah,1 ; odczytuje znak z klawiatury i wypisuje na ekran
	int 21h
	inc di
	cmp al, 'a'
	ja capital
	cmp al, 'z'
	jb capital
	mov [tablica+di], al ; przypisanie znaku do wyświetlenia
	cmp al,13
	jne read

	mov cx,di
	mov ah,2
capital:
	sub al, 32
	mov [tablica+si], al
	jmp read
print:
	mov si,di
	sub si,cx
	mov dx, [tablica+si]
	int 21h
	loop print

mov ax, 4c00h
int 21h

tablica TIMES 50 db 0

Teraz, gdy odpalam program, trwa on w nieskończoność. Wciśnięcie entera powoduje przejście do nowej linii i pozwala wpisywać kolejne łańcuchy, a powinien wypisać łańcuch z wielkimi literami.

0

Ech no pomyśl chłopie. Logika w szkole była? Chcesz warunek: literka większa od "a" i mniejsza od "z" a zapisujesz DWA OSOBNE warunki więc w efekcie masz literka większa od "a" lub mniejsza od "z". Widzisz różnicę między tymi dwiema rzeczami? Różnica jak między przysłowiowym piciem w szczawnicy a szczaniem w piwnicy. @Azarien ładnie pokazał jak korzystając z praw deMorgana możesz swój problem rozwiązać. Bo jak widać potrafisz zapisać warunek "LUB" a nie potrafisz "I". Zamień więc swój warunek "I" na warunek "LUB".
X i Y = nie (nie X lub nie Y)
Więc musisz zanegować warunki, czyli będzie literka mniejsza od "a", literka większa od "z" i musisz zanegować całe zdanie, czyli skok w takiej sytuacji do nie_capital zmiast do capital. I teraz jeśli przejdziesz za te dwa warunki to znaczy że literka jest pomiędzy a i z.

0

W zasadzie to logika była w szkole, problem w tym, że ja po tym kodzie poruszam się trochę po omacku. Wpisuję coś, sprawdzam czy działa - bardziej metoda prób i błędów niż programowanie.

Chodzi o coś takiego? Nadal mi program chodzi w nieskończoność. Próbowałem też ze skopiowaniem sposobu @Azarien, ale wciąż to samo.

org 100h

start: 
	xor di,di
read:
	mov ah,1 ; odczytuje znak z klawiatury i wypisuje na ekran
	int 21h
	inc di
	cmp al, 'a'
	jb not_capital
	cmp al, 'z'
	ja not_capital
	sub al, 32
	mov [tablica+di], al ; przypisanie znaku do wyświetlenia
	cmp al,13
	jne read

	mov cx,di
	mov ah,2
not_capital:
	mov [tablica+di], al
	jmp read
print:
	mov si,di
	sub si,cx
	mov dx, [tablica+si]
	int 21h
	loop print

mov ax, 4c00h
int 21h

tablica TIMES 50 db 0
0

Chciałym zobaczyć jak ten warunek cmp al,13 miałby być u ciebie spełniony. I dare you, pokaż mi input dla którego tak będzie. Bo jak dla mnie 13+32 = 45, a 45 > 97 więc skoczymy do not_capital, czyż nie? Rada na dziś: zainstaluj program emu8086 i wykonuj to co tu napisałeś krok po kroku patrząc na stan rejestrów...

0

Zainstalowałem EMU8086 i wykrzacza mi się tutaj:

(14) wrong parameters: MOV [tablica+di], al
(14) probably it's an undefined var: [tablica+di]

Ja już nie mam pomysłów, czy ktoś jest w stanie mi pomóc z tym programem? Wpisywałem już wszystkie kombinacje w

    cmp al, 'A'
    jb not_capital
    cmp al, 'Z'
    ja not_capital

i żadna nie działa. Jakbym mógł, to bym sobie darował ten program i już Was nie męczył :(

0
  1. Obstawiam że nie wolno po prostu robić [pamięć+di], tak to tylko z bx wolno ;)
  2. No póki będziesz programował metodą Monte Carlo to nic z tego nie będzie. Musisz zacząć używać głowy do czegoś innego niż tylko do jedzenia. Póki nie zaczniesz myśleć to nic nie poradzimy.
  3. Błąd jest w zupełnie innym miejscu niż to które tak namiętnie zmieniasz. Wersja podana przez @Azarien była poprawna. Błąd masz w tym swoim porównaniu które niby ma wskazać "enter" tylko że porównujesz ten znak w takim miejscu że NIGDY go nie wykryjesz.
0

@Shalom Dzięki za naprowadzenie, ale po co tyle jadu? W prawie każdym poście próbujesz mnie obrazić. Czy ja Ci czymś ubliżyłem?

Pozdrawiam

P.S.
Używam głowy nie tylko do jedzenia. Nie znasz mnie, a oceniasz. Zwyczajnie nie znam zbyt dobrze składni Assemblera, napisałem tylko kilka prostych programów typu dodaj dwie liczby i wyświetl wynik. Dla Ciebie to banał, dla mnie to dość sporo.

0

A może spróbuj tak jak ja to zrobiłem w funkcji kapitaluj. To rozwiązanie działa doskonale tylko zamień rejestry na 16 bitowe.

2

Proszszsz...

org 100h
 
    xor di,di
read:
    mov ah,1
    int 21h

    cmp al, 'a'
    jl store
    cmp al, 'z'
    jg store
    
    and al, 0DFh ; huh...
store:
    mov [tablica+di], al
    inc di
    cmp al,13
    jne read
    
    mov cx,di
    xor si,si
    mov ah,2
    mov dl,10
    int 21h
print:
    mov dl, [tablica+si]
    int 21h
    inc si
    loop print
 
    mov ax, 4c00h
    int 21h
 
tablica TIMES 50 db 0

i, ponieważ tak bardzo niektórzy woleliby widzieć wersję 32-bitową, oto ona, do zlinkowania linkerem LD z pakietu DJGPP
(ruszy pod DOS-em i pod 32-bitowym Windowsem, ale NIE pod 64-bitowym)

; nasm av_dos_dj.asm -fcoff -o av_dos_dj.o
; ld av_dos_dj.o -o av_dos_dj.exe

[bits 32]
[global start]
[section .text]

start:
    xor edi,edi
read:
    mov ah,1
    int 21h

    cmp al, 'a'
    jl store
    cmp al, 'z'
    jg store
    
    and al, 0DFh ; huh...
store:
    mov [tablica+edi], al
    inc edi
    cmp al,13
    jne read
    
    mov ecx,edi
    xor esi,esi
    mov ah,2
    mov dl,10
    int 21h
print:
    mov dl, [tablica+esi]
    int 21h
    inc esi
    loop print
 
    mov ax, 4c00h
    int 21h

[section .bss]
 
    tablica resb 50

wersję 32-bitową pod DOS-extendery z pakietu Open Watcom pozostawiamy do wykonania czytelnikowi ;-)

2

Ahhh. myślałem, że będę pierwszy no ale dobra. Napisałem to wkleję:

org 100h

global _main

section .data:
napis	db	"grzEGorz$"

_main:
	mov di, 0
	
kapitalizuj:
	mov al, byte[napis+di]
	cmp al, 'Z'
	jle dalej

	sub byte[napis+di], ' '
	dalej:
	inc di
	cmp byte[napis+di], '$'
	jne kapitalizuj
	
	mov dx, napis
	mov ah, 9
	int 21h

	mov ax, 4c00h
	int 21h
2

Akurat klepie coś w asm to dorzuce to co pod ręką mam :P

; @param SI - string
; @retrn None
; @descr litery TOUPPER
to_upper:
    pushf
    push si
    .loop:
        cmp BYTE [si], 0
        je .done
        cmp BYTE [si], 'a'
        jb .not_letter
        cmp BYTE [si], 'z'
        ja .not_letter
        sub BYTE [si], 20h
        inc si
        jmp .loop
    .done:
		pop si
        popf
        ret
    .not_letter:
        inc si
        jmp .loop
;=======================================================================
; @param SI - string
; @retrn None
; @descr litery tolower
to_lower:
    pushf
    .loop:
        cmp BYTE [si], 0
        je .done
        cmp BYTE [si], 'A'
        jb .not_letter
        cmp BYTE [si], 'Z'
        ja .not_letter
        add BYTE [si], 20h
        inc si
        jmp .loop
    .done:
        popf
        ret
    .not_letter:
        inc si
        jmp .loop

1 użytkowników online, w tym zalogowanych: 0, gości: 1