; CIS-261 ; M08.ASM ; Demo program of IO.H and IO.ASM usage ; @topic W080093 IO.H and IO.ASM usage demo ; @brief Console Input/Output OUTPUT, INPUT, SZLEN, DTOA, ITOA, ATOI usage .386 ; Tells MASM to use Intel 80386 instruction set. .MODEL FLAT ; Flat memory model option casemap:none ; Treat labels as case-sensitive INCLUDE IO.H ; header file for input/output .CONST ; Constant data segment intro1 BYTE "Jeramy Brian", 0 intro2 BYTE "Assignment M08", 0 intro3 BYTE "1. Inputs two 8-bit unsigned integers from the user, calculates the sum of the two numbers, and prints the result on the screen.", 0 addPrompt1 BYTE "Please enter two numbers in the range [0, 255], in the format '1 + 2': ", 0 addPrompt2 BYTE "Would you like to add more numbers (y/N): ", 0 addError1 BYTE "ERROR :: OVERFLOW :: (BYTE, DWORD) :: (", 0 addError2 BYTE "ERROR :: This number is too big. ::", 0 intro4 BYTE "2. Inputs two 32-bit signed integers from the user, calculates their difference, and prints the result.", 0 subPrompt1 BYTE "Please enter two numbers in the range [-2147483648, 2147483647], in the format '1 - 2': ", 0 subPrompt2 BYTE "Would you like to subtract more numbers (y/N): ", 0 subError1 BYTE "ERROR :: OVERFLOW :: (SDWORD) :: (", 0 exitPrompt BYTE "Press enter to exit...", 0 ENDL BYTE 13, 10, 0 equals BYTE " = ", 0 subtract BYTE "-", 0 addition BYTE "+", 0 genError BYTE "ERROR :: That entry could not be understood. :: ", 0 contPrompt BYTE "Press 'Enter' to continue...", 0 errorFrm1 BYTE ", ", 0 errorFrm2 BYTE ")", 0 numbers BYTE "0123456789", 0 ;Second 0 is a place holder space BYTE " ", 0 .STACK 100h ; (default is 1-kilobyte stack) .DATA ; Begin initialized data segment dtoa_buffer BYTE 11 DUP (?), 0 atoa_buffer BYTE 6 DUP (?), 0 addBuffer BYTE 12 DUP (?) add1Str BYTE 3 DUP (?), 0 add1 BYTE ? add2Str BYTE 3 DUP (?), 0 add2 BYTE ? addAns BYTE ? addAnsStr BYTE 3 DUP (?), 0 addOFAnsStr BYTE 6 DUP (?), 0 addErrAns DWORD ? ;BOOL Value for code reuse isSub BYTE 0 subBuffer BYTE 26 DUP (?) sub1Str BYTE 11 DUP (?) sub1 SDWORD ? sub2Str BYTE 11 DUP (?) sub2 SDWORD ? subAns SDWORD ? subAnsStr BYTE 26 DUP (?) tmpAddr DWORD ? numCounter DWORD 0 strCounter DWORD 0 strLength DWORD 0 numCounter1 DWORD 0 numCounter2 DWORD 0 ansCounter DWORD 0 tmpCounter DWORD 0 tmpStr BYTE ? doItAgainCntr DWORD 0 doItAgainBuffer BYTE 6 DUP (?) .CODE ; Begin code segment _main PROC ; Beginning of code output intro1 ; My name output ENDL ; Start New Line output intro2 ; The assignment output ENDL ; Start New Line output intro3 ; First part of assignment output ENDL ; Start New Line output ENDL ; Start New Line ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; addFunc: output addPrompt1 ; Give user instructions input addBuffer, 12 ; ...read zero to 10 ASCII characters output ENDL ; Start New Line szlen addBuffer ; get the length of the input mov strLength, eax ; put the length in a variable mov tmpCounter, eax ; set the length to a variable that is going to be decrimented mov tmpAddr, OFFSET add1Str ; set the address of add1Str to a temp value that can be incremented lea edx, ds:[addBuffer] ; load the address of the addBuffer into edx jmp compAdd ; jump to the comp add 'function' this is to compare the entries on the buffer string to values we are looking for ;make sure we have a '+' symbol compAdd: mov al, addition ; load the addition value into eax mov bl, [edx] ; move the value stored in the eax register to bl cmp al, bl ; compare al and bl to look for '+' jne compSpace ; if there is no '+' character look for ' ' mov tmpAddr, OFFSET add2Str ; if the '+' symbol is found then we are ready to work on the second integer jmp nextChar ; look for the next character in the string ;skip the spaces compSpace: mov al, space ; load the space value into al cmp al, bl ; compare the al and bl registers jne compNumbers ; if the value in bl is not a space, then make sure it is a number jmp nextChar ; if it is a space then go to the next character ;make sure the entry was a number compNumbers: lea eax, ds:[numbers - 1] ; load the address just before the numbers string into eax, it will immediately be bumped up to where we want to be @@: inc eax ; move the pointer to where we want to start looking inc numCounter ; keep track of the number of times we have iterated over the string push eax ; move the value out of eax for a minute so we can see how many numbers we have szlen numbers ; count the length of the numbers variable cmp eax, numCounter ; see if we have gone through all of the numbers and not found a match pop eax ; get the value that was in eax back off the stack. there is a matching pop in the errorCharMsg 'function' in case a jump was made je errorCharMsg ; if there are no more numbers to check and there is no match, then there is a problem. notify the user cmp [eax], bl ; we have more numbers to iterate over, does the value in bl match the number in the eax register? jne @B ; no match, go back and look at the next number in line jmp concatStr ; it matches put it in the string ;we have a number, prepare it for use concatStr: mov numCounter, 0 ; reset the numCounter for compNumbers so that it is ready to go for the next char from the input buffer push edx ; move the value in the edx register out of the way for a minute mov edx, tmpAddr ; move the tmpAddr into edx mov [edx], bl ; push the number from bl into the place that edx is pointing at inc tmpAddr ; move the tmpAddr to the next address so that it is ready for the next number pop edx ; get the edx value back from the stack jmp nextChar ; go find the next character in the input buffer ;get the next char in the buffer nextChar: inc edx ; point edx to the next character in the input buffer inc strCounter ; make sure we are not continuously searching through a nonsensical string mov bl, [edx] ; move the value from the address into the bl register push eax ; move eax out of the way mov eax, strLength ; get the original buffer string length cmp eax, strCounter ; compare the buffer string length to where we are currently at pop eax ; get eax back off the stack je addOrSubtractShowOut ; we reached the end, but are we adding or subtracting dec tmpCounter ; count our temp counter down jnz addOrSubtractComp ; if the temp counter is not zero then go start the process over for the next character in line, are we adding or subtracting? jmp errorCharMsg ; we reached the end of the string addOrSubtractShowOut: push eax ; move eax back out of the way mov al, isSub ; is isSub set cmp al, 0 ; compare with 0 pop eax ; get eax back je showOutput ; we are adding, show proper output jmp showSubOutput ; we are subtracting, show proper output addOrSubtractComp: push eax ; move eax out of the way mov al, isSub ; is isSub set cmp al, 0 ; compare with 0 pop eax ; get eax back je compAdd ; we are adding, look for the + symbol ******NOTE****** this program does not check if there is a leading + symbol. This will cause an error jmp compSub ; we are subtracting, look for the - symbol ; Malformed addition problem errorCharMsg: output genError ; Let the user know that the input was not appropriate for the function mov tmpStr, bl ; Move the inappropriate character into the tmpStr variable output tmpStr ; Show the user the problem character output ENDL ; print a new line addOrSubtractCharError: push eax ; move eax out of the way mov al, isSub ; is isSub set cmp al, 0 ; compare with 0 pop eax ; get eax back je doItAgain ; we are adding, Let the user try again jmp subItAgain ; we are subtracting, let the user try again ; the problem seems good, show the user what we got showOutput: output add1Str ; print the first number found output space ; print a space (formatting) output addition ; print '+' (formatting) output space ; print a space (formatting) output add2Str ; print the second number found xor eax, eax ; zero the eax register so that there is no junk in it atoi add1Str ; convert the first number to an integer mov add1, al ; move the number into the add1 variable push ebx ; move anything in ebx out of the way mov ebx, 255 ; put 255 in the ebx register cmp eax, ebx ; compare the entered value with ebx pop ebx ; get the value for ebx back jg errorTooBig ; if the user entered a value greater than 255, let the user know that this is not allowed xor eax, eax ;first number is ok. clear the eax register again for the second number atoi add2Str ; convert the second number to an integer mov add2, al ; move the number into the add2 variable (this isn't necessary, but may want to save it for future use) push ebx ; move ebx out of the way mov ebx, 255 ; put 255 into the register cmp eax, ebx ; compare the entered value with ebx pop ebx ; get ebx back jg errorTooBig ; if the number was too big, let the user know add al, add1 ; the numbers are ok. add first number to second number jc errorOFMsg ; if the carry flag is set then let the user know. (jump if overflow does not work here, because the problem still makes sense in the wierd x86 way) mov addAns, al ; move the result to the addAns variable itoa addAnsStr, ax ; convert the answer to ascii and move it to the addAnsStr variable output equals ; print ' = ' (formatting) output addAnsStr ; show the user the result output ENDL ; print a new line jmp doItAgain ; ask the user if they want to do it again ; there was an overflow errorOFMsg: output ENDL ; print a new line mov addAns, al ; move the overflow answer to the addAns variable itoa addAnsStr, ax ; convert the answer to ascii output addError1 ; let the user know that there was an overflow output addAnsStr ; show the user the overflow answer output errorFrm1 ; print ', ' (formatting) movzx ax, add1 ; move the first number into a bigger register movzx bx, add2 ; move the second number into a bigger register add ax, bx ; add the first and second numbers itoa addOFAnsStr, ax ; convert the non overflow answer to ascii output addOFAnsStr ; show the user the correct answer output errorFrm2 ; print ')' (formatting) output ENDL ; print a new line jmp doItAgain ; ask the user if they want to do it again errorTooBig: output ENDL ; print a new line output addError2 ; let the user know that the value they entered was too big itoa addOFAnsStr, ax ; move the value that is too big into the addOFAnStr variable (just used this variable instead of assigning one specifically for this situation) output addOFAnsStr ; show the user the value that was too large output ENDL ; print a new line jmp doItAgain ; let the user try again doItAgain: ;some of this is a mess because I was having trouble clearing out all of the variables in order to start again szlen add1Str ; I have no idea why I did this. the following few lines make no sense, but the program is working and I don't want to change it right now mov eax, numCounter1 ; overwrote the value just placed in eax szlen add2Str ; overwrote the value just placed in eax mov eax, numCounter2 ; overwrote the value just placed in eax szlen addAnsStr ; overwrote the value just placed in eax mov numCounter, 0 ; set numCounter to 0 ;I think that this is probably overly complicated for the number variables movzx eax, add1 ; move the add1 variable to eax, and zero pad the beginning in order to fill the entire register xor eax, eax ; zero the register mov add1, al ; zero out the add1 variable movzx eax, add2 ; move the add2 variable to the eax register xor eax, eax ; zero the register mov add2, al ; zero out the add2 variable movzx eax, addAns ; move the addAns variable to the eax register xor eax, eax ; zero the register mov addAns, al ; zero out the addAns variable ;clear the addBuffer mov eax, OFFSET addBuffer ; move the address of addBuffer into eax @@: mov dl, [eax] ; move the value that is at the address stored in eax to the dl register xor dl, dl ; zero out the dl register mov [eax], dl ; move the zero's back into the location pointed to by eax inc eax ; have eax point to the next location in memory dec strLength ; count down the strLength so we know when we are done jnz @B ; if there are more characters in the string, repeat the process ;clear the add1Str mov eax, OFFSET add1Str ; same process as above @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec numCounter1 jnz @B ;clear the add2Str mov eax, OFFSET add2Str ; same process as above @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec numCounter2 jnz @B ; clear the addAnsStr mov eax, OFFSET addAnsStr ; same process as above @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec ansCounter jnz @B ;this is necessary if the user overflowed the buffer with spaces when entering the previous addition problem output ENDL ; print a new line output contPrompt ; print 'press enter to cont.' output ENDL ; print a new line input doItAgainBuffer, 6 ; bring in previously entered values if there are any szlen doItAgainBuffer ; see how many characters are in the buffer mov doItAgainCntr, eax ; keep track of how many characters there are cmp eax, 0 ; make sure that there are not 0 characters in the buffer jz addOrSubtractFinish ; if there are no characters in the buffer, then finish up clearExtraSpaces: mov eax, OFFSET doItAgainBuffer ; there are still characters in the buffer @@: ;******NOTE****** mov dl, [eax] ; this is the same process used to clear the previous buffer, but because the doItAgainBuffer is small, we have to keep pulling values in to make sure that we get them all xor dl, dl ; if all characters on the prompt are not handled, then the program will automatically jump to the subtraction part mov [eax], dl ; and there is no way of knowing how much junk was entered into the command prompt inc eax dec doItAgainCntr jnz @B push eax input doItAgainBuffer, 6 szlen doItAgainBuffer mov doItAgainCntr, eax cmp eax, 0 pop eax jnz clearExtraSpaces jmp addOrSubtractFinish addOrSubtractFinish: push eax ; move eax out of the way mov al, isSub ; is isSub set cmp al, 0 ; compare with 0 pop eax ; get eax back je finishUp ; we are adding, finish up jmp subFinishUp ; we are subtracting, finish up finishUp: xor ebx, ebx ; zero out the ebx register xor edx, edx ; zero out the edx register output addPrompt2 ; ask if the user wants to add more numbers input doItAgainBuffer, 6 ; get the users input mov al, 79h ; hex value for 'y' cmp al, doItAgainBuffer ; if the user entered 'y' do the addition thing again jne subFunc ; otherwise move on to the subtraction part jmp addFunc ; user selected the addition function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; subFunc: mov isSub, 1 ; my BOOL value, let the program know we are now perfoming subtraction so that we can reuse some of the previous code segments output ENDL ; print a new line output intro4 ; let the user know how to use this part of the program output ENDL ; print a new line output ENDL ; print a new line output subPrompt1 ; print instructions input subBuffer, 26 ; get user input szlen subBuffer ; find out how long the input string is mov strLength, eax ; move the length value into the strLength variable mov tmpCounter, eax ; move the length value into the tmpCounter so that we can decriment it mov tmpAddr, OFFSET sub1Str ; move the addres of sub1Str in to our tmpAddr so that we can incriment the value lea edx, ds:[subBuffer] ; load the address of the subBuffer into edx jmp compSub ; go to compSub (this would have happened anyway, but I felt it was cleaner to explicitely state it) ;make sure we have a '-' symbol compSub: mov al, subtract ; load the subtract value into eax mov bl, [edx] ; move the string char into the bl register cmp al, bl ; check if the string char is a '-' symbol jne compSpace ; it's not so check to see if it is a space symbol push eax ; it is a '-' symbol, so move eax out of the way szlen sub1Str ; get the length of the first number cmp al, 0 ; make sure that we have not started forming the first number yet pop eax ; if the flag is going to be set it has already happened, get eax back je concatStr ; The first number is negative push eax ; there are already characters stored for the first number (first number is positive), move eax back out of the way mov eax, tmpAddr ; move the value of tmpAddr into the eax register cmp eax, OFFSET sub2Str ; check to see if we are working on the second number pop eax ; get eax back je checkSubNum2 ; so, the second number address has been loaded into the tmpAddr variable, We are subtracting a negative number (addition) mov tmpAddr, OFFSET sub2Str ; the first nuber address is still loaded, This is the subtraction symbol seperating the two numbers jmp nextChar ; get the next char in the string checkSubNum2: push eax ; it is a '-' symbol, so move eax out of the way szlen sub2Str ; get the length of the first number cmp al, 0 ; make sure that we have not started forming the first number yet pop eax ; if the flag is going to be set it has already happened, get eax back je concatStr jmp errorCharMsg showSubOutput: pop eax ; move eax out of the way output sub1Str ; print the first number output space ; print space (formatting) output subtract ; print subtract (fromatting) output space ; print space (formatting) output sub2Str ; print second number atod sub1Str ; convert ascii to integer mov sub1, eax ; move int to sub1 variable atod sub2Str ; convert ascii to integer jo errorSubOFMsg mov sub2, eax ; move int to sub2 variable cmp eax, 0 ; compare the value of sub2 with 0 jnl switchSign ; if sub2 is not less than 0 then we need to switch the sign jmp getResult ; otherwise it is fine getResult: mov eax, sub1 ; make sure we are subtracting the right way, move sub1 back into eax sub eax, sub2 ; subtract sub2 from sub1 jo errorSubOFMsg ; if there is an overflow, let the user know mov subAns, eax ; move the result to subAns variable dtoa subAnsStr, eax ; convert the answer to ascii output equals ; print ' = ' (formatting) output subAnsStr ; print the answer output ENDL ; print a new line jmp subItAgain ; let the user do it again switchSign: imul eax, -1 ; switch the sign on the number mov sub2, eax ; copy the new result to the sub2 variable mov eax, sub1 ; move sub1 back into eax add eax, sub2 ; here we are 'adding' negative numbers jo errorSubOFMsg ; if there is an overflow, let the user know mov subAns, eax ; move the result into subAns variable dtoa subAnsStr, eax ; convert the answer to ascii output equals ; print ' = ' (formatting) output subAnsStr ; print the answer output ENDL ; print a new line jmp subItAgain ; let the user do it again errorSubOFMsg: output ENDL ; print a new line mov subAns, eax ; copy the result in eax to subAns dtoa subAnsStr, eax ; convert the answer to ascii output subError1 ; let the user know there was an error output subAnsStr ; show the user the incorrect result output errorFrm2 ; print ')' (formatting) output ENDL ; print a new line jmp subItAgain ; let the user do it again ; this is nearly identical to 'doItAgain', just the variables that need to be cleared, and the output strings have changed subItAgain: szlen sub1Str mov eax, numCounter1 szlen sub2Str mov eax, numCounter2 szlen subAnsStr mov numCounter, 0 mov eax, sub1 xor eax, eax mov sub1, eax mov eax, sub2 xor eax, eax mov sub2, eax mov eax, subAns xor eax, eax mov subAns, eax mov eax, OFFSET subBuffer @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec strLength jnz @B mov eax, OFFSET sub1Str @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec numCounter1 jnz @B mov eax, OFFSET sub2Str @@: mov dl, [eax] xor dl, dl mov [eax], dl inc eax dec numCounter2 jnz @B output ENDL output contPrompt output ENDL input doItAgainBuffer, 6 szlen doItAgainBuffer mov doItAgainCntr, eax cmp eax, 0 jz subFinishUp jmp clearExtraSpaces subFinishUp: xor ebx, ebx xor edx, edx output subPrompt2 input doItAgainBuffer, 6 ; get the users input mov al, 79h ; hex value for 'y' cmp al, doItAgainBuffer ; if the user entered 'y' do the addition thing again jne endProgram ; otherwise end the program jmp subFunc ; user selected the addition function ;all done time to exit endProgram: ret _main ENDP END _main ; Marks the end of the module and sets the program entry point label
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.