TITLE RPN Calculator by Doug Jones ;------------------------------- ; This calcullator supports the following operators: ; ; Ennn - enter the decimal integer nnn ; P - decimal print ; + - add ; - - subtract ; * - multiply ; / - divide ; B - print in an odd base ; ; All letters may be upper or lower case ;------------------------------- USE "/group/22c018/hawk.macs" ; linkage for external procedures in the monitor EXT DSPCH,DSPST,DSPDEC,TIMES,DIVIDE PDSPCH: W DSPCH PDSPST: W DSPST PDSPDEC:W DSPDEC PTIMES: W TIMES PDIVIDE:W DIVIDE ; linkage for other external procedures EXT ODDPR PODDPR: W ODDPR ;------------------------------- INT CALC CALC: ; procedure to handle one line of calculator input ; expects R3 = pointer to line MOVE R8,R1 ; save return address MOVE R9,R3 ; save pointer to command string MOVE R10,R2 ; save pointer to stack base LOOP: LOADS R3,R9 EXTB R3,R3,R9 ; get a character BZR NONNULL MOVE R2,R10 ; restore stack (clean off unpopped stuff) JUMPS R8 ; return if null NONNULL: LEA R4,JUMPTAB ADDSL R3,R4,2 ; index by char into jumptab LOADS R3,R3 ; get jump table entry JUMPS R3 ; and go process the entry ;------------------------------- ; jump table with one entry for each ASCII code ; because the table is complete, no bounds checking is needed ALIGN 4 JUMPTAB: W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; control W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; chars W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; control W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; chars W SPACE,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; !"#$%&' W ERROR,ERROR,MULT, PLUS, ERROR,MINUS,ERROR,DIV ; ()*+,-./ W DIGIT,DIGIT,DIGIT,DIGIT,DIGIT,DIGIT,DIGIT,DIGIT ; 01234567 W DIGIT,DIGIT,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; 89:;<=>? W ERROR,ERROR,BASE ,ERROR,ERROR,ENTER,ERROR,ERROR ; @ABCDEFG W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; HIJKLMNO W PRINT,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; PQRSTUVW W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; XYZ[\]^_ W ERROR,ERROR,BASE ,ERROR,ERROR,ENTER,ERROR,ERROR ; `abcdefg W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; hijklmno W PRINT,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; pqrstuvw W ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR ; xyz{|}~ ;------------------------------- ; ; Each of the following cases handles one calculator command. ; These cases are not procedures! The code for Each calculator command ; ends by advancing the input pointer and going to the loop top! ; ; Register usage on entry and exit from each case: ; ; R2 -- calculator stack pointer; points to free space just above top item ; R8 -- saved return address for calculator procedure as a whole ; R9 -- input pointer; points to current calculator command ; R10 -- saved pointer to stack base, used to check for stack underflow ; ;------------------------------- SPACE: ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- ERROR: LEA R3,ERMSG1 LOAD R1,PDSPST JSRS R1,R1 ; output error message prefix LOADS R3,R9 EXTB R3,R3,R9 ; get the character LOAD R1,PDSPCH JSRS R1,R1 ; output it LEA R3,ERMSG2 LOAD R1,PDSPST JSRS R1,R1 ; output error message suffix ADDSI R9,1 ; advance pointer into command string JUMP LOOP ERMSG1: ASCII "Error '",0 ERMSG2: ASCII "' ",0 ALIGN 2 ;------------------------------- MULT: ADDSI R2,-4 ; pop the stack CMP R2,R10 ; check for underflow! BLE ERROR ; complain if underflow LOADS R3,R2 ; get old (popped) stack top LOAD R4,R2,-4 ; get item below it (current top item) LOAD R1,PTIMES JSRS R1,R1 ; multiply them STORE R3,R2,-4 ; put the result back on top of the stack ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- PLUS: ADDSI R2,-4 ; pop the stack CMP R2,R10 ; check for underflow! BLE ERROR ; complain if underflow LOADS R3,R2 ; get old (popped) stack top LOAD R4,R2,-4 ; get item below it (current top item) ADD R4,R4,R3 ; add them STORE R4,R2,-4 ; put the result back on top of the stack ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- MINUS: ADDSI R2,-4 ; pop the stack CMP R2,R10 ; check for underflow! BLE ERROR ; complain if underflow LOADS R3,R2 ; get old (popped) stack top LOAD R4,R2,-4 ; get item below it (current top item) SUB R4,R4,R3 ; subtract them STORE R4,R2,-4 ; put the result back on top of the stack ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- DIV: ADDSI R2,-4 ; pop the stack CMP R2,R10 ; check for underflow! BLE ERROR ; complain if underflow LIS R11,1 ; set default sign of result LOADSCC R4,R2 ; get old (popped) stack top BNR DIVP1 NEG R4,R4 ; negate if negative NEG R11,R11 ; and complement sign of result DIVP1: LOADCC R3,R2,-4 ; get item below it (current top item) BNR DIVP2 NEG R3,R3 ; negate if negative NEG R11,R11 ; and complement sign of result DIVP2: LOAD R1,PDIVIDE JSRS R1,R1 ; divide TESTR R11 ; test sign result should have BNR DIVP3 NEG R3,R3 ; negate result if should be negative DIVP3: STORE R3,R2,-4 ; put the result back on top of the stack ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- DIGIT: CMP R2,R10 ; check for empty stack! BLE ERROR ; complain if empty LOAD R4,R2,-4 ; item on stack top LOADS R3,R9 ; the character needs getting again EXTB R3,R3,R9 ; so get it (known to be a digit) ADDI R3,-"0" ; convert it to an integer ADDSL R4,R4,2 ; multiply stack top by 5 ADDSL R4,R3,1 ; multiply by 2 and add digit STORE R4,R2,-4 ; return to stack top ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- BASE: ADDSI R2,-4 ; pop the stack CMP R2,R10 ; check for underflow! BLE ERROR ; complain if underflow LOADS R4,R2 ; get old (popped) stack top CMPI R4,2 ; test for minimum legal radix BLT ERROR CMPI R4,36 ; test for maximum legal radix BGT ERROR LOAD R3,R2,-4 ; get item below it (current top item) LOAD R1,PODDPR JSRS R1,R1 ; print number in odd base ADDSI R2,-4 ; finish popping the stack ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- ENTER: STORES 0,R2 ; push zero ADDSI R2,4 ADDSI R9,1 ; advance pointer into command string JUMP LOOP ;------------------------------- PRINT: CMP R2,R10 ; check for empty stack! BLE ERROR ; complain if empty ADDSI R2,-4 ; pop LOADSCC R3,R2 ; check sign BNR PRINTP LIS R3,"-" ; if negative LOAD R1,PDSPCH JSRS R1,R1 ; print - first LOADS R3,R2 ; then recover the number NEG R3,R3 ; and negate it PRINTP: CLR R4 LOAD R1,PDSPDEC JSRS R1,R1 ; print in field width zero LIS R3," " LOAD R1,PDSPCH JSRS R1,R1 ; print trailing blank ADDSI R9,1 ; advance pointer into command string JUMP LOOP END