home *** CD-ROM | disk | FTP | other *** search
-
- ;*************************************************************
- ; VAL - Jim Butterfield December 12, 1988 ;
- ; Expression evaluator. Run from CLI only. ;
- ;*************************************************************
-
- ; Exec calls
- _LVOOpenLibrary EQU -$0228
- _LVOCloseLibrary EQU -$019e
- ; DOS calls
- _LVOOutput EQU -$003c
- _LVOWrite EQU -$0030
-
- MOVE.L A0,A5 ; Pointer to text
- LINK A4,#-100 ; Gimme 100 bytes (Purity!)
-
- MOVE.L 4,A6 ; ExecBase
- LEA DosName(pc),A1 ; Where's DOS?
- MOVEQ #0,D0
- JSR _LVOOpenLibrary(A6)
- MOVE.L D0,A6 ; DosBase
- BEQ No_DOS
-
- ;Get Output Handle:
- JSR _LVOOutput(A6)
- MOVE.L D0,-$10(A4) ;OutHandle
- BEQ EXIT
-
- LEA -$18(A4),A3 ;numeric stack pointer
- LEA -$40(A4),A2 ;operator stack pointer
-
- ;Scan Command Tail:
- MOVEQ #0,D0 ;char buffer
- MOVEQ #0,D1 ;numeric analyzer
- MOVEQ #0,D2 ;modulo of input number
- MOVEQ #0,D3 ;value of input number
- MOVE.L D3,-4(A4) ;sign
- MOVE.L D3,-8(A4) ;no parens
- MOVE.L A5,-$C(A4) ;start-of-text pointer
- MOVE.L D3,-$14(A4) ;overflow flag
- MOVE.W D3,-(A2) ;end flag, operator stack
-
-
- ScanLoop:
- MOVE.B (A5)+,D0 ;get character
- CMP.B #$3F,D0 ; '?' anywhere - send prompt
- BEQ Prompt
- MOVE.B D0,D1 ;number slot
- CMP.B #$60,D0
- BCS.S SmallByte
- SUB.B #$20,D1 ;change lower to upper case
- SmallByte:
- CMP.B #$40,D1
- BCS.S SmallerByte
- SUB.B #$37,D1 ;change alpha to hex value
- SmallerByte:
- CMP.B #$3A,D0
- BCC.S BigByte
- SUB.B #$30,D1 ;change num to value
- BigByte:
- CMP.B #$10,D1 ;is it numeric/hex digit?
- BCC.S NotNum ; ... no, skip ahead
- ; We have found a digit! Is it the first?
- TST.B D2 ;Check if number in progress
- BNE.S ModuloSet ; yes, continue
- MOVEQ #$A,D2 ; Set Decimal flag
- ModuloSet:
- CMP.B D1,D2 ; Digit within range (Dec/Hex?)
- BCS Over1 ; .. nope, holler
- CMP.W #$A,D2
- BEQ.s Decimal ; If decimal, skip ahead
- ASL.L #3,D3 ;hex, times 8
- BVS.S Over1
- ASL.L #1,D3 ;hex, times 16
- BRA.S AddDigit
- Decimal:
- ASL.L #1,D3 ; Former value times 2
- BCS.S Over1
- BMI.S Over1
- MOVE.L D3,D7 ; Save times2
- ASL.L #2,D3 ; Times 4, to make times8
- BCS.S Over1
- ADD.L D7,D3 ; times2+times8 gives times10
- BCS.S Over1
- AddDigit:
- ADD.L D1,D3 ; add in new digit
- BCC.S ScanLoop ; On to next character
- Over1:
- BRA.S Oops
- ; If we reach the following code, we have discovered
- ; a non-numeric character
- NotNum:
- TST.B D2 ;number in progress?
- BNE.S SkipTrix ;.. no, skip next tests
- CMP.B #45,D0 ;unary minus?
- BNE.S NotUM
- MOVEQ #-1,D7
- MOVE.L D7,-4(A4) ;set negative flag
- ScanLink:
- BRA.S ScanLoop
- NotUM:
- CMP.B #40,D0 ;left parens?
- BNE.S NotLP ; .. no, keep looking
- ADD.B #$10,-8(A4) ;yes, change hierarchy
- BRA.S ScanLoop
- NotLP:
- CMP.B #36,D0 ;dollars hex?
- BNE.S Oops ; .. no, give up
- HexIt:
- MOVEQ #$10,D2 ; .. yes, change to hex
- BRA.S ScanLink
- ; Any '?' makes us print prompt message
- Prompt:
- LEA Format(pc),A0
- MOVE.L A0,D2 ; Format message pointer
- MOVEQ #FormLen,D3
- BRA.S SayIt
- ; Parentheses not closed
- ParenWarn:
- LEA ParMsg(pc),A0
- MOVE.L A0,D2 ; Bad parens message pointer
- MOVEQ #ParLen,D3
- BRA.S SayIt
- ; Overflow during calculation
- OverWarn:
- LEA OvMsg(pc),A0
- MOVE.L A0,D2 ; Overflow message pointer
- MOVEQ #OvLen,D3
- BRA.S SayIt
- ; Problems. Print input string up to glitch.
- Oops:
- MOVE.B #$3F,(A5)+ ; Add '?',..
- MOVE.B #$0A,(A5)+ ; ..NewLine
- MOVE.L A5,D3 ; Current point
- MOVE.L -$C(A4),D2 ; Start of input
- SUB.L D2,D3 ; Calc length
- SayIt:
- MOVE.L -$10(A4),D1 ; OutHandle
- JSR _LVOWrite(A6)
- BRA EXIT
- ; Here, we have number in progress and
- ; .. non-numeric character
- SkipTrix:
- CMP.B #$21,D1 ; x?
- BNE.S NotX
- TST.L D3 ; Hex if 0x...
- BEQ.S HexIt
- NotX:
- CMP.B #41,D0 ;close parens?
- BNE.S NotRP
- SUB.B #$10,-8(a4) ;drop hierarchy
- BPL.S ScanLink
- OopsLink:
- BRA.S Oops ; too far?
- ; Wrap up number, put on numeric stack
- NotRP:
- TST.B -4(A4) ; negative?
- BEQ.S Positv ; no, skip
- MOVE.L D3,D7
- MOVEQ #0,D3
- SUB.L D7,D3
- Positv:
- ; put D3 to Numeric stack
- MOVE.L D3,-(A3)
- MOVEQ #0,D2 ; clear modulo
- MOVEQ #0,D3 ; clear value
- MOVE.L D2,-4(A4) ; reset sign flag
- ; Look at Operator
- LEA Operators(pc),A0
- MOVEQ #0,D6 ; Operator index
- MOVEQ #1,D7 ; lowest level
- CMP.B #$20,D0 ; end of input string?
- BCS.S PutOper ; .. yes, log it
- CMP.B #$5C,D0 ; Backslash symbol?
- BNE.S OpLoop
- MOVE.B #$25,D0
- OpLoop:
- CMP.B 0(A0,D6.W),D0
- BEQ.S OpFound
- ADDQ.B #4,D6
- CMP.B #EndOps-Operators,D6
- BNE.S OpLoop
- BRA.S OopsLink
- OpFound:
- MOVE.B 1(A0,D6.W),D7
- ADD.B -8(A4),D7
- ; Put the symbol on the stack. But first,
- ; higher/equal level symbols must be squeezed out.
- PutOper:
- CMP.B (A2),D7 ; Check level
- BHI.S LeaveOper
- ; Squeeze out previous operator
- MOVEM.L D0/D1/D2/D6/D7,-(A7)
- MOVE.B (A2)+,D7 ; ignore level indicator
- MOVE.B (A2)+,D0 ; get op index
- MOVE.L (A3)+,D6 ;last numeric from stack
- MOVE.L (A3)+,D7 ; .. and previous
- ; go for the address, off D0
- LEA Subhead(pc),A1
- MOVE.W 2(A0,D0.W),D1 ; here's the address
- JSR 0(A1,D1.W) ; go for it
-
- ; Operation done. Stack result, retest operator.
- PutBack:
- MOVE.L D7,-(A3) ;result to numeric stack
- MOVEM.L (A7)+,D0/D1/D2/D6/D7
- BRA.S PutOper
- ; Everything is pulled off the stack that needs it.
- ; Put new operator on stack, and its level.
- LeaveOper:
- MOVE.B D6,-(A2) ; Op pointer
- MOVE.B D7,-(A2) ; Op level
- MoreLoop:
- CMP.B #$20,D0 ; End of input (NewLine)?
- BCC ScanLoop
- Finish:
- ; -8(A4) Check to see all parens closed
- MOVE.L -8(A4),D7 ; hierarchy
- BNE ParenWarn
- ; -$14(A4) Check if overflow
- TST.B -$14(A4)
- BNE OverWarn
- ; Print value on numeric stack
- MOVE.L (A3)+,D7 ; stack value
- MOVE.B #$20,D2 ; space if positive
- MOVE.L D7,D6
- BPL.S PositR
- MOVEQ #0,D6
- SUB.L D7,D6
- MOVE.B #$2D,D2 ; minus if negative
- PositR:
- LEA -$18(A4),A3
- MOVE.L A3,-4(A4) ; Mark this spot.
- MOVEQ #$20,D0 ; SPACE character..
- MOVE.B D0,-(A3) ; two at end
- MOVE.B D0,-(A3)
- DecLoop:
- MOVEQ #0,D0 ;remainder
- MOVEQ #0,D1 ;shift count
- DivLoop:
- ASL.L #1,D6
- ROXL.B #1,D0
- CMP.B #10,D0
- BCS.s DivCont
- SUBI.B #10,D0
- BSET #0,D6
- DivCont:
- ADDQ.W #1,D1
- CMP.B #32,D1
- BCS.s DivLoop ; 32 times
- ORI.B #$30,d0 ; here's the character
- MOVE.B D0,-(A3) ; stack it
- ; Check if anything left
- TST.L D6 ; more characters?
- BNE.s DecLoop ; .. yes, go get em
- MOVE.B D2,-(A3)
- ; Number is stacked in A3 - print!
- MOVE.L -4(A4),D3 ; end of string
- SUB.L A3,D3 ; buff len
- MOVE.L A3,D2 ; buff add
- MOVE.L -$10(A4),D1 ; file handle
- JSR _LVOWrite(A6)
-
- ; Now for hex...
- MOVE.L -4(A4),A3 ; Restore A3
- MOVEQ #$0A,D6 ; RETURN at end
- MOVE.B D6,-(A3)
- HexDig:
- MOVE.B D7,D6
- LSR.L #4,D7 ; slide those bits
- AND.B #$0F,D6 ; slice four
- ORI.B #$30,D6 ; make it a number
- CMP.B #$3A,D6
- BCS.S NotAlf
- ADD.B #7,D6 ; ... or a letter
- NotAlf:
- MOVE.B D6,-(A3) ; stack it!
- TST.L D7 ; any more?
- BNE.s HexDig ; .. yes, get 'em
- MOVEQ #$24,D6 ; gimme a dollar (sign)
- MOVE.B D6,-(A3) ; stack the buck
- ; Hex number in A3 - print!
- MOVE.L -4(A4),D3 ; end of string
- SUB.L A3,D3 ; buff len
- MOVE.L A3,D2 ; buff add
- MOVE.L -$10(A4),D1 ; file handle
- JSR _LVOWrite(A6)
-
- EXIT:
- ; Close DOS library.
-
- MOVE.L A6,A1 ; DosBase
- MOVE.L 4,A6 ; ExecBase
- JSR _LVOCloseLibrary(A6)
- No_Dos:
- UNLK A4 ; Back to Stack
- RTS
- SubHead:
- OrSub:
- OR.L D6,D7
- RTS
- AndSub:
- AND.L D6,D7
- RTS
- AddSub:
- ADD.L D6,D7
- RTS
- SubSub:
- SUB.L D6,D7
- RTS
- PowSub:
- MOVE.L D6,D1 ; power
- MOVE.L D7,D6 ; base
- MOVEQ #1,D7 ; start value
- PowLoop:
- TST.B D1 ; power?
- BEQ.S PowExit ; zero, done.
- SUB.B #1,D1 ; one less...
- MOVE.L D6,-(A7)
- MOVE.L D1,-(A7)
- BSR.S MultSub
- MOVE.L (A7)+,D1
- MOVE.L (A7)+,D6
- BRA.S PowLoop
- PowExit:
- RTS
- ; Multiply subroutine: 32 bits x 32 bits signed
- ; D7 times D6; uses regs D1 and D2
- ; Result in D7
- MultSub:
- MOVEQ #0,D1 ; sign flag
- TST.L D7 ; is Arg1 Positive?
- BPL.S Arg1Pos
- MOVEQ #0,D2
- SUB.L D7,D2
- MOVE.L D2,D7
- MOVEQ #1,D1
- Arg1Pos:
- TST.L D6
- BPL.S Arg2Pos ; is Arg2 Positive?
- MOVEQ #0,D2
- SUB.L D6,D2
- MOVE.L D2,D6
- EORI.B #1,D1
- Arg2Pos:
- MOVE.L D7,D2 ; biggest val to D2
- CMP.L D6,D7
- BCC.S MultMain
- MOVE.L D6,D2
- MOVE.L D7,D6 ; smallest to D6
- MultMain:
- MOVEQ #0,D7 ; product area
- MultLoop:
- LSR.L #1,D6 ; multiplier to right!
- BCC.S NomAdd
- ADD.L D2,D7
- BCS.S Moverf
- NomAdd:
- TST.L D6
- BEQ.S MultDone
- LSL.L #1,D2 ; multiplicand to left!
- BCC.S MultLoop
- Moverf:
- MOVE.B #1,-$14(A4) ; overflow
- ; How 'bout that sign?
- MultDone:
- TST.L D1 ; product sign flag
- BEQ.S MultExit
- MOVEQ #0,D2
- SUB.L D7,D2
- MOVE.L D2,D7
- MultExit:
- RTS
-
- DivOver:
- MOVE.B #1,-$14(A4)
- RTS
- ModSub:
- MOVEQ #0,D0 ;flags modulo
- MOVE.L D7,D1
- BRA.S DivJob
- DivSub:
- MOVE.L D7,D1
- EOR.L D6,D1
- DivJob:
- TST.L D6
- BEQ.S DivOver
- BPL.S Darg1Pos
- MOVEQ #0,D2
- SUB.L D6,D2
- MOVE.L D2,D6
- Darg1Pos:
- TST.L D7
- BPL.S Darg2Pos
- MOVEQ #0,D2
- SUB.L D7,D2
- MOVE.L D2,D7
- Darg2Pos:
- MOVE.L D1,-(A7) ; Stack the sign
- MOVEQ #0,D2 ; Remainder
- MOVEQ #0,D1 ; Counter
- DivdLoop:
- ASL.L #1,D7
- ROXL.L #1,D2
- CMP.L D6,D2
- BCS.S DivdCont
- SUB.L D6,D2
- BSET #0,D7
- DivdCont:
- ADDQ.W #1,D1
- CMP.B #32,D1
- BCS.S DivdLoop ; 32 times
- MOVE.L (A7)+,D1 ; restore sign flag
- TST.B D0
- BNE.S NotModul
- MOVE.L D2,D7 ; slip remainder in
- NotModul:
- TST.L D1
- BPL.S ModEnd
- MOVEQ #0,D2
- SUB.L D7,D2
- MOVE.L D2,D7
- ModEnd:
- RTS
-
- ; | & + - * % / ^
- Operators: DC.B $7C,2
- DC.W OrSub-SubHead
- DC.B $26,3
- DC.W AndSub-SubHead
- DC.B 43,4
- DC.W AddSub-SubHead
- DC.B 45,4
- DC.W SubSub-SubHead
- DC.B 42,5
- DC.W MultSub-SubHead
- DC.B $25,5
- DC.W ModSub-SubHead
- DC.B 47,5
- DC.W DivSub-SubHead
- DC.B 94,6
- DC.W PowSub-SubHead
- EndOps:
- DosName: DC.B 'dos.library',0
- Format: DC.B 'Format: Val <expression>, e.g., 2+3*4',$a
- EndFormat: DC.B $20,$2A,$20,$4A,$69,$6D,$20,$42,$75,$74
- FormLen = EndFormat-Format
- DC.B $74,$65,$72,$66,$69,$65,$6C,$64,$20
- DC.B $44,$65,$63,$2F,$38,$38,$20,$2A,$20
-
- OvMsg: DC.B 'Overflow',$a
- EndOv:
- OvLen = EndOv-OvMsg
- ParMsg: DC.B 'Too many "("',$a
- EndPar:
- ParLen = EndPar-ParMsg
-
- END
-