-
IO.h
11/29/2015 at 17:50 • 0 comments;#pragma once ; CIS - 261 ; IO.H -- header file for I / O macros ; 32 - bit version for flat memory model .NOLIST; turn off listing .386 EXTRN itoaproc : near32, atoiproc : near32 EXTRN dtoaproc : near32, atodproc : near32 EXTRN inproc : near32, outproc : near32 EXTRN szlenproc : near32 itoa MACRO dest, source, xtra;; convert integer to ASCII string IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF push ebx;; save EBX mov bx, source push bx;; source parameter lea ebx, dest;; destination address push ebx;; destination parameter call itoaproc;; call itoaproc(source, dest) pop ebx;; restore EBX ENDM atoi MACRO source, xtra;; convert ASCII string to integer in AX ;; offset of terminating character in ESI IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF push ebx;; save EBX lea ebx, source;; source address to EBX push ebx;; source parameter on stack call atoiproc;; call atoiproc(source) pop ebx;; parameter removed by ret ENDM dtoa MACRO dest, source, xtra;; convert double to ASCII string IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF push ebx;; save EBX mov ebx, source push ebx;; source parameter lea ebx, dest;; destination address push ebx;; destination parameter call dtoaproc;; call dtoaproc(source, dest) pop ebx;; restore EBX ENDM atod MACRO source, xtra;; convert ASCII string to integer in EAX ;; offset of terminating character in ESI IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF lea eax, source;; source address to EAX push eax;; source parameter on stack call atodproc;; call atodproc(source) ;; parameter removed by ret ENDM output MACRO string, xtra;; display string IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF push eax;; save EAX lea eax, string;; string address push eax;; string parameter on stack call outproc;; call outproc(string) pop eax;; restore EAX ENDM input MACRO dest, length, xtra;; read string from keyboard IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF push ebx;; save EBX lea ebx, dest;; destination address push ebx;; dest parameter on stack mov ebx, length;; length of buffer push ebx;; length parameter on stack call inproc;; call inproc(dest, length) pop ebx;; restore EBX ENDM szlen MACRO string, xtra;; get string length IFB .ERR EXITM ENDIF IFNB .ERR EXITM ENDIF lea eax, string;; string address push eax;; string parameter on stack call szlenproc;; call szlenproc(string) ENDM .NOLISTMACRO; suppress macro expansion listings .LIST; begin listing
This is not my code! this is from http://www.c-jump.com/bcc/c261c/CIS261syllabus.html
-
IO.asm
11/29/2015 at 17:49 • 0 comments; CIS-261 ; implementation of I/O procedures called by macros in io.obj ; flat memory model version .386 .MODEL FLAT PUBLIC itoaproc, atoiproc, dtoaproc, atodproc, outproc, inproc, szlenproc .CODE ; itoaproc(source, dest) ; convert integer (source) to string of 6 characters at given destination address itoaproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame push eax ; Save registers push ebx ; used by push ecx ; procedure push edx push edi pushf ; save flags mov ax, [ebp+12] ; first parameter (source integer) mov edi, [ebp+8] ; second parameter (dest offset) ifSpecial: cmp ax,8000h ; special case -32,768? jne EndIfSpecial ; if not, then normal case mov BYTE PTR [edi],'-' ; manually put in ASCII codes mov BYTE PTR [edi+1],'3' ; for -32,768 mov BYTE PTR [edi+2],'2' mov BYTE PTR [edi+3],'7' mov BYTE PTR [edi+4],'6' mov BYTE PTR [edi+5],'8' jmp ExitIToA ; done with special case EndIfSpecial: mov dx, ax ; save source number mov al,' ' ; put blanks in mov ecx,5 ; first five cld ; bytes of rep stosb ; destination field mov ax, dx ; copy source number mov cl,' ' ; default sign (blank for +) IfNeg: cmp ax,0 ; check sign of number jge EndIfNeg ; skip if not negative mov cl,'-' ; sign for negative number neg ax ; number in AX now >= 0 EndIfNeg: mov bx,10 ; divisor WhileMore: mov dx,0 ; extend number to doubleword div bx ; divide by 10 add dl,30h ; convert remainder to character mov [edi],dl ; put character in string dec edi ; move forward to next position cmp ax,0 ; check quotient jnz WhileMore ; continue if quotient not zero mov [edi],cl ; insert blank or "-" for sign ExitIToA: popf ; restore flags and registers pop edi pop edx pop ecx pop ebx pop eax pop ebp ret 6 ;exit, discarding parameters itoaproc ENDP ; dtoaproc(source, dest) ; convert double (source) to string of 11 characters at given offset in DS (dest) dtoaproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame push eax ; Save registers push ebx ; used by push ecx ; procedure push edx push edi pushf ; save flags mov eax, [ebp+12] ; first parameter (source double) mov edi, [ebp+8] ; second parameter (dest addr) ifSpecialD: cmp eax,80000000h ; special case -2,147,483,648? jne EndIfSpecialD ; if not, then normal case mov BYTE PTR [edi],'-' ; manually put in ASCII codes mov BYTE PTR [edi+1],'2' ; for -2,147,483,648 mov BYTE PTR [edi+2],'1' mov BYTE PTR [edi+3],'4' mov BYTE PTR [edi+4],'7' mov BYTE PTR [edi+5],'4' mov BYTE PTR [edi+6],'8' mov BYTE PTR [edi+7],'3' mov BYTE PTR [edi+8],'6' mov BYTE PTR [edi+9],'4' mov BYTE PTR [edi+10],'8' jmp ExitDToA ; done with special case EndIfSpecialD: mov edx, eax ; save source number mov al,' ' ; put blanks in mov ecx,10 ; first ten cld ; bytes of rep stosb ; destination field mov eax, edx ; copy source number mov cl,' ' ; default sign (blank for +) IfNegD: cmp eax,0 ; check sign of number jge EndIfNegD ; skip if not negative mov cl,'-' ; sign for negative number neg eax ; number in EAX now >= 0 EndIfNegD: mov ebx,10 ; divisor WhileMoreD: mov edx,0 ; extend number to doubleword div ebx ; divide by 10 add dl,30h ; convert remainder to character mov [edi],dl ; put character in string dec edi ; move forward to next position cmp eax,0 ; check quotient jnz WhileMoreD ; continue if quotient not zero mov [edi],cl ; insert blank or "-" for sign ExitDToA: popf ; restore flags and registers pop edi pop edx pop ecx pop ebx pop eax pop ebp ret 8 ;exit, discarding parameters dtoaproc ENDP ; atoiproc(source) ; Procedure to scan data segment starting at source address, interpreting ; ASCII characters as an integer value which is returned in AX. ; Leading blanks are skipped. A leading - or + sign is acceptable. ; Digit(s) must immediately follow the sign (if any). ; Memory scan is terminated by any non-digit, and the address of ; the terminating character is in ESI. ; The following flags are affected: ; AC is undefined ; PF, SF and ZF reflect sign of number returned in AX. ; CF reset to 0 ; OF set to indicate error. Possible error conditions are: ; - no digits in input ; - value outside range -32,768 to 32,767 ; (AX) will be 0 if OF is set. atoiproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame sub esp, 2 ; local space for sign push ebx ; Save registers push ecx push edx pushf ; save flags mov esi,[ebp+8] ; get parameter (source addr) WhileBlank: cmp BYTE PTR [esi],' ' ; space? jne EndWhileBlank ; exit if not inc esi ; increment character pointer jmp WhileBlank ; and try again EndWhileBlank: mov ax,1 ; default sign multiplier IfPlus: cmp BYTE PTR [esi],'+' ; leading + ? je SkipSign ; if so, skip over IfMinus: cmp BYTE PTR [esi],'-' ; leading - ? jne EndIfSign ; if not, save default + mov ax,-1 ; -1 for minus sign SkipSign: inc esi ; move past sign EndIfSign: mov [ebp-2],ax ; save sign multiplier mov ax,0 ; number being accumulated mov cx,0 ; count of digits so far WhileDigit: cmp BYTE PTR [esi],'0' ; compare next character to '0' jl EndWhileDigit ; not a digit if smaller than '0' cmp BYTE PTR [esi],'9' ; compare to '9' jg EndWhileDigit ; not a digit if bigger than '9' imul ax,10 ; multiply old number by 10 jo overflow ; exit if product too large mov bl,[esi] ; ASCII character to BL and bx,000Fh ; convert to single-digit integer add ax,bx ; add to sum jc overflow ; exit if sum too large inc cx ; increment digit count inc esi ; increment character pointer jmp WhileDigit ; go try next character EndWhileDigit: cmp cx,0 ; no digits? jz overflow ; if so, set overflow error flag ; if value is 8000h and sign is '-', want to return 8000h (-32,768) cmp ax,8000h ; 8000h ? jne TooBig? cmp WORD PTR [ebp-2],-1 ; multiplier -1 ? je ok1 ; if so, return 8000h TooBig?: test ax,ax ; check sign flag jns ok ; will be set if number > 32,767 overflow: pop ax ; get flags or ax,0000100001000100B ; set overflow, zero & parity flags and ax,1111111101111110B ; reset sign and carry flags push ax ; push new flag values mov ax,0 ; return value of zero jmp AToIExit ; quit ok: imul WORD PTR [ebp-2] ; make signed number ok1: popf ; get original flags test ax,ax ; set flags for new number pushf ; save flags AToIExit: popf ; get flags pop edx ; restore registers pop ecx pop ebx mov esp, ebp ; delete local variable space pop ebp ret 4 ; exit, removing parameter atoiproc ENDP ; atodproc(source) ; Procedure to scan data segment starting at source address, interpreting ; ASCII characters as an integer value which is returned in EAX. ; Leading blanks are skipped. A leading - or + sign is acceptable. ; Digit(s) must immediately follow the sign (if any). ; Memory scan is terminated by any non-digit, and the address of ; the terminating character is in ESI. ; The following flags are affected: ; AC is undefined ; PF, SF and ZF reflect sign of number returned in EAX. ; CF reset to 0 ; OF set to indicate error. Possible error conditions are: ; - no digits in input ; - value outside range -2,147,483,648 to 2,147,483,647 ; (EAX) will be 0 if OF is set. atodproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame sub esp, 4 ; local space for sign push ebx ; Save registers push ecx push edx pushf ; save flags mov esi,[ebp+8] ; get parameter (source addr) WhileBlankD:cmp BYTE PTR [esi],' ' ; space? jne EndWhileBlankD ; exit if not inc esi ; increment character pointer jmp WhileBlankD ; and try again EndWhileBlankD: mov eax,1 ; default sign multiplier IfPlusD: cmp BYTE PTR [esi],'+' ; leading + ? je SkipSignD ; if so, skip over IfMinusD: cmp BYTE PTR [esi],'-' ; leading - ? jne EndIfSignD ; if not, save default + mov eax,-1 ; -1 for minus sign SkipSignD: inc esi ; move past sign EndIfSignD: mov [ebp-4],eax ; save sign multiplier mov eax,0 ; number being accumulated mov cx,0 ; count of digits so far WhileDigitD:cmp BYTE PTR [esi],'0' ; compare next character to '0' jl EndWhileDigitD ; not a digit if smaller than '0' cmp BYTE PTR [esi],'9' ; compare to '9' jg EndWhileDigitD ; not a digit if bigger than '9' imul eax,10 ; multiply old number by 10 jo overflowD ; exit if product too large mov bl,[esi] ; ASCII character to BL and ebx,0000000Fh ; convert to single-digit integer add eax,ebx ; add to sum jc overflowD ; exit if sum too large inc cx ; increment digit count inc esi ; increment character pointer jmp WhileDigitD ; go try next character EndWhileDigitD: cmp cx,0 ; no digits? jz overflowD ; if so, set overflow error flag ; if value is 80000000h and sign is '-', want to return 80000000h (-2^32) cmp eax,80000000h ; 80000000h ? jne TooBigD? cmp DWORD PTR [ebp-4],-1 ; multiplier -1 ? je ok1D ; if so, return 8000h TooBigD?: test eax,eax ; check sign flag jns okD ; will be set if number > 2^32 - 1 overflowD: pop ax ; get flags or ax,0000100001000100B ; set overflow, zero & parity flags and ax,1111111101111110B ; reset sign and carry flags push ax ; push new flag values mov eax,0 ; return value of zero jmp AToDExit ; quit okD: imul DWORD PTR [ebp-4] ; make signed number ok1D: popf ; get original flags test eax,eax ; set flags for new number pushf ; save flags AToDExit: popf ; get flags pop edx ; restore registers pop ecx pop ebx mov esp, ebp ; delete local variable space pop ebp ret 4 ; exit, removing parameter atodproc ENDP ; *************** setup for Win32 I/O **************** STD_OUTPUT EQU -11 STD_INPUT EQU -10 GetStdHandle PROTO NEAR32 stdcall, nStdHandle:DWORD ReadFile PROTO NEAR32 stdcall, hFile:DWORD, lpBuffer:NEAR32, nNumberOfCharsToRead:DWORD, lpNumberOfBytesRead:NEAR32, lpOverlapped:NEAR32 WriteFile PROTO NEAR32 stdcall, hFile:DWORD, lpBuffer:NEAR32, nNumberOfCharsToWrite:DWORD, lpNumberOfBytesWritten:NEAR32, lpOverlapped:NEAR32 .DATA written DWORD ? read DWORD ? strAddr DWORD ? strLength DWORD ? hStdOut DWORD ? hStdIn DWORD ? .CODE ; outproc(source) ; Procedure to display null-terminated string ; No registers are changed; flags are not affected. outproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame pushad pushfd ; save flags mov esi,[ebp+8] ; source address mov strAddr, esi ; find string length mov strLength, 0 ; initialize string length WhileChar: cmp BYTE PTR [esi], 0 ; character = null? jz EndWhileChar ; exit if so inc strLength ; increment character count inc esi ; point at next character jmp WhileChar EndWhileChar: INVOKE GetStdHandle, ; get handle for console output STD_OUTPUT mov hStdOut, eax INVOKE WriteFile, hStdOut, ; file handle for screen strAddr, ; address of string strLength, ; length of string NEAR32 PTR written, ; bytes written 0 ; overlapped mode popfd ; restore flags popad ; restore registers pop ebp ret 4 ;exit, discarding parameter outproc ENDP ; inproc(dest,length) ; Procedure to input a string from keyboard. ; The string will be stored at the address given by dest. ; The length parameter gives the size of the user's buffer. It is assumed ; that there will be room for the string and a null byte. ; The string will be terminated by a null character (00h). ; Flags are unchanged. inproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame pushad ; save all registers pushfd ; save flags INVOKE GetStdHandle, ; get handle for console STD_INPUT mov hStdIn, eax mov ecx, [ebp+8] ; string length mov strLength, ecx mov esi, [ebp+12] ; source address mov strAddr, esi INVOKE ReadFile, hStdIn, ; file handle for keyboard strAddr, ; address of string strLength, ; length of string NEAR32 PTR read, ; bytes read 0 ; overlapped mode mov ecx, read ; number of bytes read mov BYTE PTR [esi+ecx-2],0 ; replace CR/LF by trailing null popfd ; restore flags popad ; restore registers pop ebp ret 8 ; exit, discarding parameters inproc ENDP ;ik-10/4/2008 ; szlenproc(source) ; Procedure to calculate length of a null-terminated string ; No registers are changed; flags are not affected. szlenproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame pushad pushfd ; save flags mov esi,[ebp+8] ; source address mov strAddr, esi ; find string length mov strLength, 0 ; initialize string length WhileChar: cmp BYTE PTR [esi], 0 ; character = null? jz EndWhileChar ; exit if so inc strLength ; increment character count inc esi ; point at next character jmp WhileChar EndWhileChar: popfd ; restore flags popad ; restore registers pop ebp mov eax, strLength ; rerun string length in EAX ret 4 ;exit, discarding parameter szlenproc ENDP END
This is not my code! This is from http://www.c-jump.com/bcc/c261c/CIS261syllabus.html
-
I/O
11/29/2015 at 17:47 • 0 comments; 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