📄 deskcalc.s
字号:
! EIGHT BYTE INTEGER POCKET CALCULATOR IN REVERSE POLISH! This program emulates a stack oriented integer machine in polish notation.! The central data structure consists of eight byte signed long ints, which! are pushed onto and popped from a stack which is called "nstack".! The size of this stack is 1024 of those longs. Moreover the emulated! machine has a memory containing 26 of those eight byte variables,! which are indicated by the variable names "A" through "Z".! The machine is supposed to read commands and integers from standard input.! The operators all pop their arguments from the stack and push the result.! The admitted binary operators are: addition, indicated by a "+" character;! subtraction, "-"; multiplication, "*"; integer division discarding! the remainder, indicated by a ":" character; and the remainder operation! indicated by "%". ! There is a unary minus operator "~"; a pop from stack operator "p";! duplicate top of stack "d"; and exchange the two integers on the top of! the stack "x". The operator "^" prints the entire stack, and if an end of! line is encountered the top element of the stack is printed if available.! If the input is numerical, the indicated number is pushed onto the stack.! The command "sA" is a store operation, which pops the top of stack and stores! it into the variable "A"; retrieval is done with the "r" command, so "rZ"! gets the value of variable "Z" and pushes it onto the stack.! The command "q" terminates the program.! As an example program we could try! 35 18-d*dsA\n which pushes first 35, then 18, computes the difference,(17)! duplicates and multiplies it (289) duplicate and stores it in "A".! The end of line prints the top of stack, so the result is 289.! The aim of this exercise is: First to understand the calculation! Secondly to program an extra feature in such a way that the calculator! accepts lines in infix notation. In this infix notation the operators are! put between the numbers, and the order of evaluation can be influenced by! means of parentheses. Those infix notation lines will be recognised! by an equal sign "=" at the end of a line. If such a line is encountered,! then it must be converted into reversed polish notation. After the converted! line is processed the result is on top of the stack, and this value is printed! because of the end of line which is encountered after the "=" sign.! In the section "Stack addressing" this conversion process is discussed.! Note that in infix notation the operators "x" "p" "d" "q" and "s" cannot! be used. Provisions should be made that recalled variable can be used in! stead of numbers, so "rA+rB=\n" is admitted and must give the expected answer.! Central in the program is the integer stack "nstack" which consists! of 1024 8-byte integers. The stack is used from high to low addresses! and register BX is used to indicate the top of stack.! After a line is read from standard input into the buffer "inputb" it is! scanned one character at the time. Two integer buffers "curbuf" and "nxtbuf"! are used to keep the bytes which are to be processed. A copy of "curbuf"! is kept in DX, and "nxtbuf" is used to have a read ahead of one byte.! The routine "getcbuf" copies the "nxtbuf" into DX and "curbuf" and moves! another byte into "nxtbuf". The input line in "inputb" is scanned by means! of a pointer variable "pinbuf"..SECT .TEXT TEN = 0xa ! Use this constant for decimal printoutsstart: MOV BX,stkend ! Puts the register BX at the end of the nstack CLD0: CALL rdline ! Read an input line into the inputb CALL central ! Execute the commands in the inputb CALL snlcr ! Output top of stack JMP 0b ! Start again by the read linecentral: ! The central interpretation loop1: CALL getcbuf MOV AX,DX ! Copy input character into AX CMP AX,0 ! Zero means end of buffer, finish central. JLE 3f SHL AX,1 ! Double the value of the input byte to MOV DI,AX ! use it in the dispatch table DTABLE CALL DTABLE(DI) ! The register DI is used to govern the call. JMP 1b3: RETsquit: PUSH (null) ! Exit system call routine. PUSH (_exit) SYSrdline: MOV DI,inputb ! Use DI register to store characters in inputb XOR CX,CX ! Cleanup CX, which counts the number of bytes PUSH (_getchar) ! Prepare for the read byte from standard in1: SYS ! get next byte CMP AX,0 JL 9f ! finish on AX<0, i.e. end of file. CMPB AL,'\b' JE 8f ! move one character back on a backspace STOSB ! store character in inputb, auto increment DI INC CX ! One more character read CMP AX,'\n' JNE 1b ! If not end of line, get next byte MOVB (DI),'\0' ! Close input string with a zero byte MOV (pinbuf),inputb ! put input pointer at the start of the line CALL getcbuf ! Fill the next character buffer ADD SP,2 ! Stack cleanup RET8: CMP CX,0 ! Correct current line with backspaces. JE 1b ! No correction at the start of the line DEC CX ! Decrement byte count DEC DI ! Decrement buffer pointer JMP 1b9: PUSH eofmes ! Close process on end of input PUSH (_printf) SYS ! Print exit message ADD SP,4 CALL squit ! and terminate programgetcbuf: PUSH AX ! Save AX XOR DX,DX ! Cleanup DX MOVB DL,(nxtbuf) ! Get DL from nxtbuf MOV (curbuf),DX ! Fill curbuf XCHG SI,(pinbuf) ! get pointer from pinbuf LODSB ! Get next character from inputb; increment SI MOVB (nxtbuf),AL ! Fill nxtbuf with new character XCHG (pinbuf),SI ! Restore SI and pot neww value in pinbuf POP AX ! Restore AX RET ! Back! The three registers BX, SI and DI which can be used to point in the data! segment are used to boint to the bottom address of the 8-byte integers which! are used as the basic data units in this exercise. The BX register governs! the nstack, and the DI and SI point to the destination and the source for! the integers used in the computation. So the basic computations used those! registers in every computation, and we need routines to clean the integer! variables indicated, to copy and exchange them, for addition, subtraction,! multiplication, division, and the determination of remainders. Because these! last three computations involve complicated loops in their routines there! are five scratch variables oper1 through oper5, which are used for this ! purpose.clrd: PUSH DX ! Put 8-byte value 0 in the variable under DI XOR DX,DX ! Cleanup DX MOV (DI),DX ! and enter this value 0 into four consecutive MOV 2(DI),DX ! memory words indicated by DI MOV 4(DI),DX MOV 6(DI),DX POP DX RETclrs: XCHG SI,DI ! Put 8-byte value 0 in the variable under SI CALL clrd ! by exchangeing the pointers twice and clrd XCHG DI,SI RETpushd: SUB BX,2 ! Push 8-byte integer under DI onto nstack MOV AX,6(DI) ! using the register BX as its stackpointer MOV (BX),AX SUB BX,2 MOV AX,4(DI) MOV (BX),AX SUB BX,2 MOV AX,2(DI) MOV (BX),AX SUB BX,2 MOV AX,(DI) MOV (BX),AX RETsrshift: SHR 6(SI),1 ! Right shift 8-byte integer under SI RCR 4(SI),1 RCR 2(SI),1 RCR (SI),1 RETslshift:SHL (SI),1 ! Left shift 8-byte integer under SI RCL 2(SI),1 RCL 4(SI),1 RCL 6(SI),1 JC 9f ! Jump on carry set (Unsigned overflow) JO 9f ! Jump on overflow (Signed overflow) CMP 6(SI),0 JL 9f ! Jump on negative (Signed overflow) RET9: PUSH shfterr PUSH (_printf) SYS ADD SP,4 RETdlshift:XCHG SI,DI ! Left shift 8-byte integer under DI CALL slshift ! by exchanging the registers SI and DI XCHG DI,SI RETcpsd: MOV AX,(SI) ! Copy variable under SI to variable under DI MOV (DI),AX MOV AX,2(SI) MOV 2(DI),AX MOV AX,4(SI) MOV 4(DI),AX MOV AX,6(SI) MOV 6(DI),AX RETcpds: MOV AX,(DI) ! Copy variable under DI to variable under SI MOV (SI),AX MOV AX,2(DI) MOV 2(SI),AX MOV AX,4(DI) MOV 4(SI),AX MOV AX,6(DI) MOV 6(SI),AX RETsubsd: MOV AX,(SI) ! Subtract source (SI) from destination (DI) SUB (DI),AX MOV AX,2(SI) SBB 2(DI),AX MOV AX,4(SI) SBB 4(DI),AX MOV AX,6(SI) SBB 6(DI),AX RETaddsd: MOV AX,(SI) ! Add source (SI) to destination (DI) ADD (DI),AX MOV AX,2(SI) ADC 2(DI),AX MOV AX,4(SI) ADC 4(DI),AX MOV AX,6(SI) ADC 6(DI),AX RETmulsd: PUSH CX ! Multiply source (SI) to destination (DI) PUSH BX MOV BX,oper2 ! Use oper2 as a 16 byte shift register. MOV (BX),0 MOV 2(BX),0 MOV 4(BX),0 MOV 6(BX),0 MOV CX,641: SHL (BX),1 ! Multiplication is shift followed by add in case of a 1 RCL 2(BX),1 RCL 4(BX),1 RCL 6(BX),1 RCL 8(BX),1 RCL 10(BX),1 RCL 12(BX),1 RCL 14(BX),1 SHL (SI),1 ! Shift the source RCL 2(SI),1 RCL 4(SI),1 RCL 6(SI),1 JNC 2f ! and look if a carry is shifted out. This would be a 1 INC (SI) ! in that case this inc makes a rotate for the source MOV AX,(DI) ! and the add of the multiplyer is done here ADD (BX),AX MOV AX,2(DI) ADC 2(BX),AX MOV AX,4(DI) ADC 4(BX),AX MOV AX,6(DI) ADC 6(BX),AX ADC 8(DI),0 ! multiplyers are just 8 byte, so only adc from here ADC 10(DI),0 ADC 12(DI),0 ADC 14(DI),02: LOOP 1b MOV AX,(BX) MOV (DI),AX MOV AX,2(BX) MOV 2(DI),AX MOV AX,4(BX) MOV 4(DI),AX MOV AX,6(BX) MOV 6(DI),AX POP BX POP CX RETdivsd: ! Divides the positive number addressed by DI by the number in (SI). ! Keeps the sources unchanged, but copies them into ! oper1, oper2 en oper3 ! stores remainder in oper1, divisor in oper2 en quotient in oper3. PUSH CX PUSH BX MOV BX,oper3 XCHG BX,DI CALL clrd ! Get an 8-byte 0 value CALL cmpds ! Compare with divisor under SI CMP AX,0 JE 9f ! And jump to error is divisor is zero XCHG DI,BX PUSH DI PUSH SI PUSH DI MOV DI,oper2 ! Scratch variable oper2 in DI CALL cpsd ! Copy source value i.e the divisor to oper2 MOV DI,oper1 POP SI ! Old DI is extracted as SI as source for the divident CALL cpsd ! and the divident is copied to oper1 MOV SI,oper2 XOR CX,CX0: CALL cmpds ! Next compare divident and divisor CMP AX,0 JL 2f JE 3f ADD CX,1 CALL slshift ! Shift left divisor left until its larger than divident JMP 0b ! Determines ho often subtraction should be attempted.2: CMP CX,0 JE 8f ! Never shifted, then divident is rest DEC CX CALL srshift3: ADD (BX),1 ! Increment quotient ADC 2(BX),0 ADC 4(BX),0 ADC 6(BX),0 CALL subsd ! Subtract shifted divisor from divident4: CMP CX,0 JE 8f ! Nothing to shift, then ready DEC CX CALL srshift ! right shift divisor (i.e. backwards) XCHG DI,BX CALL dlshift ! left shift quotient XCHG BX,DI CALL cmpds ! Compare again if subtraction is necessary CMP AX,0 JGE 3b ! Yes: Increment quotient again and subtract (Label 3) JMP 4b ! No: Shifts only (Label 4)8: POP SI ! Divisor back at original value in oper2 POP DI ! oper3 contains quotient. JMP 6f ! oper1 contains remainder9: XCHG DI,BX PUSH nulmes ! Print message division by 0 refused PUSH (_printf) SYS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -