//----------------------------------------------------------------
//	alphanum.s 
//
//	This program is for testing an assembly language function 
//	which is intended to recognize 'alphanumeric' characters.
//	We think this function will help us to solve the in-class
//	exercise that was proposed at the conclusion of lesson 3. 
//
//	     assemble using:  $ as alphanum.s -o alphanum.o
//	     and link using:  $ ld alphanum.o -o alphanum
//
//	programmer: ALLAN CRUSE
//	written on: 02 FEB 2009
//----------------------------------------------------------------


	# manifest constants
	.equ	stdin_ID, 0		# input-device (keyboard)
	.equ	stdout_ID, 1		# output-device (screen)
	.equ	sys_read, 0		# ID-number for 'read'
	.equ	sys_write, 1		# ID-number for 'write'
	.equ	sys_exit, 60		# ID-number for 'exit'



	.section	.data
msg1:	.ascii	"\nPlease type a sentence on the line below: \n"
len1:	.quad	. - msg1
msg2:	.ascii	"\nYour letters and digits are marked by '+' \n"
len2:	.quad	. - msg2
msg3:	.ascii	"\n"
len3:	.quad	. - msg3
inbuf:	.space	80
maxin:	.quad	. - inbuf



	.section	.text
#------------------------------------------------------------------
_start:	
	# request user input

	mov 	$sys_write, %rax	# service ID-number
	mov 	$stdout_ID, %rdi	# device ID-number
	lea 	msg1, %rsi		# message address
	mov 	len1, %rdx		# message length
	syscall				# enter the kernel

	# receive user input

	mov 	$sys_read, %rax		# service ID-number
	mov 	$stdin_ID, %rdi		# device ID-number
	lea 	inbuf, %esi		# buffer address
	mov 	maxin, %rdx		# buffer length
	syscall				# enter the kernel
	mov 	%eax, maxin		# save input count

	# replace alphanumeric character with '+' signs, and
	# non-alphanumeric characters with blank spaces ' '

	lea	inbuf, %rbx		# point to buffer start
	mov	maxin, %rcx		# setup character count
	dec	%rcx			# exclude final newline
nxchr:
	mov	$' ', %al		# setup a blank in AL
	xchg	(%rbx), %al		# swap with next char
	call	isalphanum		# is it alphanumeric?
	jnc	nochg			# no, leave the blank
	mov	$'+', %al		# else change to plus
	mov	%al, (%rbx)		# and overwrite blank
nochg:
	inc	%rbx			# advance the pointer
	loop	nxchr			# again if chars left


	# display program output

	mov 	$sys_write, %rax	# service ID-number
	mov 	$stdout_ID, %rdi	# device ID-number
	lea 	inbuf, %rsi		# message address
	mov 	maxin, %rdx		# message length
	syscall				# enter the kernel


	# explain program output		

	mov 	$sys_write, %rax	# service ID-number
	mov 	$stdout_ID, %rdi	# device ID-number
	lea 	msg2, %rsi		# message address
	mov 	len2, %rdx		# message length
	syscall				# enter the kernel

	
	# finish with one blank line 

	mov 	$sys_write, %rax	# service ID-number
	mov 	$stdout_ID, %rdi	# device ID-number
	lea 	msg3, %rsi		# message address
	mov 	len3, %rdx		# message length
	syscall				# enter the kernel


	# terminate this program

	mov 	$sys_exit, %rax		# service ID-number
	mov 	$0, %rdi		# setup exit-code
	syscall				# enter the kernel

#------------------------------------------------------------------




#------------------------------------------------------------------
isalphanum:
#
# This procedure examines the character it finds in the AL register;
# it returns with the CF-flag set in case that character is either a 
# letter or a digit; otherwise, it returns with the CF-flag clear.  
#
	# is the character a digit?

	cmp	$'0', %al		# is AL below '0'?
	jb	not_digit		# yes, not a digit
	cmp	$'9', %al		# is AL above '9'?
	ja	not_digit		# yes, not a digit
	jmp	yes_alpha		# else alphanumeric 
not_digit:


	# is it an uppercase letter?
	
	cmp	$'A', %al		# is AL below 'A'? 
	jb	not_upper		# yes, not uppercase
	cmp	$'Z', %al		# is AL above 'Z'?
	ja	not_upper		# yes, not uppercase
	jmp	yes_alpha		# else alphanumeric
not_upper:


	# is it a lowercase letter?	

	cmp	$'a', %al		# is AL below 'a'?
	jb	not_lower		# yes, not lowercase
	cmp	$'z', %al		# is AL above 'z'?
	ja	not_lower		# yes, not lowercase
	jmp	yes_alpha		# else alphanumeric
not_lower:


	# setup the CF-flag for returning 
	clc				# Clear the CF-flag
	jmp	now_return		# and go to return

yes_alpha:
	stc				# Set the CF-flag
	jmp	now_return		# and go to return

now_return:	
	ret				# return to caller

#------------------------------------------------------------------
	.global	_start			# visible entry-point 
	.end				# no more to assemble