# Jeff Morrison - Final MIPS Calc


# value1 --------------> $t1
# value2 --------------> $t2
# operand -------------> $t3
# byte position -------> $t5
# curr byte position --> $t6

# symbol ascii codes
# <space> == 32
# ( == 40
# ) == 41
# * == 42
# + == 43
# - == 45
# / == 46

	.text
	.globl main
main:

#######################
#  PRINT USER PROMPT  #
#######################

	li	$v0, 4			# PRINT STRING
	la	$a0, prompt		# STORE prompt TO $a0 FOR SYSCALL
	syscall

#######################
#  ACCEPT USER INPUT  #
#######################

	li	$v0, 8			# READ STRING
	la	$a0, expr		# STORE expr TO $a0 FOR SYSCALL
	li	$a1, 50			# SET LENGTH LIMIT OF INPUT TO 50
	syscall

####################################
#  INITIALIZE NECESSARY REGISTERS  #
####################################

	la	$t5, expr		# STORE expr TO $t5
	li	$t1, 0			# SET $t1 TO 0
	li	$t2, 0			# SET $t2 TO 0
	li	$t3, 43			# SET $t3 TO '+' (DEFAULT OPERAND)

###########################
#  BEGIN EXPR EVALUATION  #
###########################

InterpretExpression:
	addi	$t6, $t6, 0
	lb	$t6, 0($t5)		# LOAD FIRST CHAR OF $t5 TO $t6

	beq	$t6, 113, quit		# IF CURRENT BYTE IS 'q', JUMP TO QUIT
	beq	$t6, 81, quit		# IF CURRENT BYTE IS 'Q', JUMP TO QUIT
	beq	$t6, 40, IsOpenParen	# IF CURRENT BYTE IS (, JUMP TO IsOpenParen
	beq	$t6, 41, IsCloseParen	# IF CURRENT BYTE IS ), JUMP TO IsCloseParen
	beq	$t6, 42, IsMultiply	# IF CURRENT BYTE IS *, JUMP TO IsMultiply
	beq	$t6, 47, IsDivide	# IF CURRENT BYTE IS /, JUMP TO IsDivide
	beq	$t6, 43, IsAdd		# IF CURRENT BYTE IS +, JUMP TO IsAdd
	beq	$t6, 45, IsSubtract	# IF CURRENT BYTE IS -, JUMP TO IsSubtract
	beq	$t6, 32, IsSpace	# IF CURRENT BYTE IS ' ', JUMP TO IsSpace
	beq	$t6, 10, OutResult	# IF CURRENT BYTE IS NEWLINE, OUTPUT RESULT
	beq	$t6,  0, OutResult	# IF CURRENT BYTE IS NULL/EMPTY, OUTPUT RESULT
	
	addi	$t2, $t6, -48		# STORE THIS NEW NUMBER TO value2

CheckForAnotherDigit:
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION
	addi	$t6, $t6, 0
	lb	$t6, 0($t5)		# STORE FIRST CHAR OF $t5 TO $t6

	beq	$t6, 10, DoOperation	# IF CURRENT CHAR IS A NEWLINE, GOTO DoOperation
	beq	$t6,  0, DoOperation	# IF CURRENT CHAR IS 0/NULL, GOTO DoOperation

	move	$t9, $t6
	addi	$t9, $t9, -48
	bltz	$t9, DoOperation	# IF $t9 IS < 0 AFTER -48, ITS NOT A NUMBER SO GOTO DoOperation
	
	li	$t4, 10			# STORE 10 INTO $t4 FOR USE IN NEXT INSTRUCTION
	mult	$t2, $t4		# MULTIPLY $t2 BY 10
	mflo	$t2			# SAVE ABOVE MULTIPLICATION BACK TO $t2
	addi	$t6, $t6, -48		# CONVERT ASCII VERSION OF $t2 TO NUMBER VERSION
	add	$t2, $t2, $t6		# ADD THE NEXT DIGIT TO THE PREVIOUS NUMBER*10
	j	CheckForAnotherDigit	# CHECK FOR ANOTHER DIGIT AFTER THIS ONE

	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION

DoOperation:
	beq	$t3, 42, DoMultiply	# IF OPERAND IS *, MULTIPLY
	beq	$t3, 47, DoDivide	# IF OPERAND IS /, DIVIDE
	beq	$t3, 43, DoAdd		# IF OPERAND IS +, ADD
	beq	$t3, 45, DoSub		# IF OPERAND IS -, SUBTRACT

IsSpace:
	addi	$t5, $t5, 1		# IGNORE THE SPACE
	j	InterpretExpression	# MOVE ON...

IsOpenParen:
	subu	$sp, $sp, 4		# MOVE STACK POINTER UP ONE POSITION
	sw	$t3, ($sp)		# PUSH OPERAND, '(', ONTO THE STACK
	subu	$sp, $sp, 4		# MOVE STACK POINTER UP ONE POSITION
	sw	$t1, ($sp)		# PUSH value1 ONTO THE STACK
	li	$t1, 0			# LOAD 0 INTO value1
	li	$t3, 43			# SET OPERAND TO ADD
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION

	j 	InterpretExpression	# CONTINUE READING THE EXPRESSION

IsCloseParen:
	lw	$t2, ($sp)		# LOAD ITEM AT TOP OF THE STACK INTO value2
	addu	$sp, $sp, 4		# MOVE STACK POINTER DOWN ONE POSITION
	lw	$t3, ($sp)		# LOAD NEXT ITEM (SHOULD BE AN OPERAND) INTO $t3
	addu	$sp, $sp, 4		# MOVE STACK POINTER DOWN ONE POSITION
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION

	beq	$t3, 42, DoMultiply	# MULTIPLY STUFF INSIDE PARENTHESIS
#	beq	$t3, 47, DoDivBackwards	# DIVIDE STUFF INSIDE PARENTHESIS
	beq	$t3, 43, DoAdd		# ADD STUFF INSIDE PARENTHESIS
	beq	$t3, 45, DoSubBackwards	# SUBTRACT STUFF INSIDE PARENTHESIS

IsMultiply:
	li	$t3, 42			# SET OPERAND TO '*'
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION
	j	InterpretExpression	# MOVE ON...

IsDivide:
	li	$t3, 47			# SET OPERAND TO '/'
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION
	j	InterpretExpression	# MOVE ON...

IsAdd:
	li	$t3, 43			# SET OPERAND TO '+'
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION

	j	InterpretExpression	# MOVE ON...

IsSubtract:
	li	$t3, 45			# SET OPERAND TO '-'
	addi	$t5, $t5, 1		# INCREMENT BYTE POSITION
	j	InterpretExpression	# MOVE ON...

DoMultiply:
	mult	$t2, $t1		# MULTIPLY value1 AND value2
	mflo	$t1			# STORE THIS MULTIPLICATION BACK INTO value1
	j	InterpretExpression	# MOVE ON...

DoDivide:
	div	$t1, $t2		# DIVIDE value1 BY value2
	mflo	$t1			# STORE THIS DIVISION BACK INTO value1
	j	InterpretExpression	# MOVE ON...

DoDivBackwards:
	div	$t2, $t1		# DIVIDE value2 BY value1
	mflo	$t1			# STORE THIS DIVISION BACK INTO value1
	j	InterpretExpression	# MOVE ON...

DoAdd:
	add	$t1, $t1, $t2		# ADD value1 AND value2 THEN STORE BACK INTO value1
	j	InterpretExpression	# MOVE ON...

DoSub:
	sub	$t1, $t1, $t2		# SUBTRACT value2 FROM value1 THEN STORE BACK INTO value1
	j	InterpretExpression	# MOVE ON...

DoSubBackwards:
	sub	$t1, $t2, $t1		# SUBTRACT value1 FROM value2 THEN STORE BACK INTO value1
	j	InterpretExpression	# MOVE ON...

OutResult:
	li	$v0, 1			# PRINT INTEGER
	move	$a0, $t1		# PUT value1 INTO $a0 FOR SYSCALL
	syscall

	li	$v0, 4			# PRINT STRING
	la	$a0, nl			# PUT NEWLINE INTO $a0 FOR SYSCALL
	syscall

quit:
	li	$v0, 10			# QUIT
	syscall

####################
#  DATA VARIABLES  #
####################

	.data
prompt:
	.asciiz "Enter expression (or 'q' to quit): "
expr:
	.space 50
nl:
	.asciiz "\n"
testV:
	.asciiz "test..."
