Close

I/O

A project log for Assembly

This will be useless except for reference.

jlbrian7jlbrian7 11/29/2015 at 17:470 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

Discussions