Machine Problem 2 Solved

22C:18, Spring 1996

Douglas W. Jones
; MP2, by Douglas Jones, 22C:18, Spring 1996.
;
; an M68000 program that repeatedly evaluates expressions written in
; an RPN calculator notation

; constants
LINELN: EQU	80	; maximum length of an input line

	XREF	STROUT,STRIN,NEWLINE,STOP
START:  			; boilerplate
	LEA	START,A4	; boilerplate (so A4 points to code seg)

MAINLP: LEA	MSGPRT,A0
	MOVE.W	#MSGPRL,D0
	JSR	STROUT		; prompt for input.
        LEA	LINE,A0
	MOVE.W	#LINELN,D0
	JSR	STRIN		; get the line
	TST.W	D0		;   see how long it is
	BLE.S	QUIT		;   quit if empty
	JSR	PROCES		; go do computation
	BRA.S	MAINLP

QUIT:	JSR	STOP		; boilerplate end of program

PROCES:
;	procedure to process 1 line of input
;	expects A0 = pointer to line
;               D0 = length of line
;       uses    A1 = calculator SP
;               D1 = calculator top element on stack
;	does not use
;		A4,A5,A6
	LEA	CALSTK,A1	; initialize calculator stack
	CLR.W	D0		; and put 0 on calc stack top
PROCLP: SUBQ.W	#1,D0		; count one character
	BLE.S	PROCQT		;   quit if less than 1 left
	CLR.L	D2		; setup so character will be long
	MOVE.B	(A0)+,D2	;   get the character
	JSR	PROCCH		;   and process it
	BRA.S	PROCLP
PROCQT: RTS

;	constants needed above
MSGPRT: DC.B	'input: '
MSGPRL: EQU	*-MSGPNT

PROCCH:
;	procedure to process 1 character of input
;	expects D2 = character
;		A1 = calculator SP
;		D1 = calculator top element of stack
;	uses	A2 = jump table computation
;	    	D3 = jump table computation
;	does not touch
;		A0,D0,A4,A5,A6
	LEA	PROTAB,A2
	MOV.L	D2,D3
	LSL.L	#2,D2		; make longword offset
	ADDA.L	D2,A2		; make address of table entry
	MOVE.L	(A2),A2		; get table entry
	ADDA.L	A4,A2		; relocate relative to code seg!
	JMP	(A2)		; go there!

PROTAB: ; this table is organized with one entry per ASCII character
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;control
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;control
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;control
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;control
	DC.L PRONOP,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ; !"#$%&'
	DC.L PROER ,PROER ,PROMUL,PROPLS,PROER ,PROMIN,PROER ,PRODIV ;()*+,-./
	DC.L PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG ;01234567
	DC.L PRODIG,PRODIG,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;89:;<=>?
	DC.L PROER ,PROER ,PROODD,PROER ,PROER ,PROENT,PROER ,PROER  ;@ABCDEFG
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;HIJKLMNO
	DC.L PROPRI,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;PQRSTUVW
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;XYZ[\]^_
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;`abcdefg
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;hijklmno
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;pqrstuvw
	DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER  ;xyz{|}~ 

; code for the end of the procedure in each case follows.  On entry, the
;	expects D2 = character
;		A1 = calculator SP
;		D1 = calculator top element of stack
;       cannot touch
;		A0,D0

PROER:  MOVE.L	A0,-(SP)	; save
	MOVE.L	D0,-(SP)
	LEA	MSGERT,A0
	MOVE.W	#MSGERL,D0
	JSR	STROUT		; error message
	JSR	NEWLINE
	MOVE.L	(SP)+,D0	; restore
	MOVE.L	(SP)+,A0
	RTS

MSGERT: DC.B	"Error"
MSGERL: EQU	*-MSGERT

;			D2 is a digit
PRODIG: MULS.W	#10,D1
	SUB.W	#'0',D2		; convert D2 to integer
	ADD.W	D2,D1		; add to 10 times stack top
	RTS

;			Plus
PROPLS:	ADD.W	-(A1),D1	; add top elements on stack
	RTS

;			Minus
PROMIN:	MOVE.W	-(A1),D2	; pop item under top
	SUB.W	D1,D2		; subtract top from item under it
	MOVE.W	D2,D1		; put result on top
	RTS

;			Mul
PROMUL:	MULS.W	-(A1),D1	; multiply
	RTS

;			Divide
PRODIV: MOVE.W	-(A1),D2	; pop item under top
	EXT.L	D2		; sign extend
	DIVS.W	D1,D2		; divide top into item under it
	MOVE.W	D2,D1		; put result on top
	RTS

;			Enter
PROENT: MOVE.W	D1,+(A1)	; push
	CLR.W	D1		; and clear
	RTS

;			Print
PROPRI: MOVE.L	A0,-(SP)	; save prior to print
	MOVE.L	D0,-(SP)
	MOVE.W	D1,D0		; put number in place
	MOVE.W	#10,D1		; put base in place
	JSR	PRINTO		;   print number
	MOVE.L	(SP)+,D0	; restore
	MOVE.L	(SP)+,A0
	MOVE.W	-(A1),D1	; pop stack
	RTS

;			odd Base print
PROODD: MOVE.L	A0,-(SP)	; save prior to print
	MOVE.L	D0,-(SP)
	MOVE.W	-(A1),D0	; put number in place
				; note that base is in D1
	JSR	PRINTO		;   print number
	MOVE.L	(SP)+,D0	; restore
	MOVE.L	(SP)+,A0
	MOVE.W	-(A1),D1	; pop stack
	RTS

;			space
PRONOP: RTS

PRINTO:
;	procedure to print a number in any odd base
;	given	D0 = number
;		D1 = base
;	recursively handles negative and multidigit numbers

	TST.W	D0
	BGE.S	PRINNG		; skip if not neg
	MOVE.L  A0,-(SP)        ; save prior to print
	MOVE.L  D0,-(SP)
        LEA	MSGNEG,A0
	MOVE.W	#1,D0
	JSR	STROUT		; print sign
	MOVE.L	(SP)+,D0	; restore
	MOVE.L	(SP)+,A0
	NEG.W	D0		; make number positive
PRINNG:				; print nonnegative number
	EXT.L	D0		; setup for divide
	DIVS.W	D0,D1		; divide by base
	MOVE.L  A0,-(SP)        ; save everything
	MOVE.L  D0,-(SP)
	SWAP	D0
	TST.W	D0		; if remainder is zero
	BEQ.S	PRINDN		;   skip ahead
	SWAP	D0		; else get quotient ready
	JSR	PRINTO		;   and print other digits
PRINDN:	MOVE.L	(SP)+,D0	; restore remainder
	SWAP	D0		; get into low half
	CMP.W	#10,D0		; test the digit
	BGE.S	PRINLT		; branch if D3-10 >= 0 or (D3 >= 10)
	ADD.B	#'0',D0		; convert to a digit in 0..9
	BRA.S	PRINPT
PRINLT	ADD.B   #'A'-10,D3	; convert to a digit in 'A'..'Z'
PRINPT	MOVE.B	D0,PRINBF	; put letter in print buffer
	LEA	PRINBF,A0
	MOVE.W	#1,D0
	JSR	STROUT		; output the digit
       	MOVE.L	(SP)+,A0	; restore saved A0
	RTS

MSGNEG: DC.B	'-'

	DATA			; boilerplate start of data section

CALSTK: DS.W	LINELN		; calculator stack (allows lots of E instrs)
LINE:	DS.B	LINELN		; space for a line of text
PRINBF: DS.B	1

	END			; boilerplate end of program