; FLTINPUT.ASM
; ------------
;
; See FALCONER.WS4 for doc.
;
; (Retyped by Emmanuel ROCHE.)
;
;--------------------------------
; External routines required
;
	extrn	fdivt,flotd,fmult	; in FLTARITH.ASM
	extrn	mul10			; in INTARITH.ASM
;
;--------------------------------
; Entry points allowed
; --------------------
;
; Utility routines
;
	entry	deblk,jbc,qmax,qnum
;
; Numeric input
;
	entry	ival,ivalc
;
;--------------------------------
; Macro definitions
;--------------------------------
;
; Execute routine at (BC) [normally get next character]
;
getch	macro
	call	jbc
	endm
;
; Change sign of real operand B or D
;
fsign	macro	reg
	if	reg*(reg-d)
	error	"R"
	endif
	mov	a,reg
	xri	80H
	mov	reg,a
	endm
;
; Reload (BC.L), stored by PUSH B, PUSH H sequence
;
reload	macro	reg
bc.l	equ	b
	if	reg-b
	error	"R"
	db	0,0,0
	endif
	if	reg-b=0		; Was IFZ
	pop	b
	mov	l,c
	pop	b
	endif
	endm
;
; "Return" and check stacl level zero
;
rtn	macro
	if	.lvl
	error	'0'+.lvl
.lvl	set	0
	endif
	ret
	endm
;
; Save (BC.L), to be restored by RELOAD BC.L later
;
save	macro	reg
	bc.l	equ	b
	if	reg-b
	error	'R'
	db	0,0
	endif
	if	reg-b=0		; Was IFZ
	push	b
	push	h
	endif
	endm
;
;--------------------------------
; Start the code
;--------------------------------
;
; Check (A) to be in range 0-9 (ASCII)
; Return Carry for non-numeric character
; F
;
qnum:	cpi	'9'+1		; This first to speed exit
	cmc			;   for alpha.
	rc			; < 0, non-numeric
	cpi	'0'		; 
	rtn			; 
;
; Check (HL) for value < 6554
; Set Carry if greater
; F
;
qmax:	push	b		; 
	mov	b,a		; 
	mov	a,l		; 
	sui	6554 MOD 256	; 
	mov	a,h		; 
	sbi	6554/256	; 
	cmc			; 
	mov	a,b		; 
	pop	b		; 
	rtn			; 
;
; Transfer control to (BC)
;
jbc:	push	b		; Set address on stack
.lvl	set	.lvl-1		; Compensate for stacked addr
	rtn			; Go excute
;
; Input a character, ignoring blanks
; A,F
;
deblk:	getch			; 
	cpi	' '		; 
	rnz			; 
	jmp	deblk		; Bypass a blank
;
; Input a floating point value from a char string
; At entry:
;  (BC) => character input routine
; At exit:
;  (A)=(L) = character following numerical string
;  (DE.H)  = value
; If error, (A) = error code, (L) = exit char, Carry set
; Carry for overflow or illegal first char
; A,F,D,E,H,L
;
ival:	call	deblk		; Bypass leading blanks
;
; Alternate entry with first char in (A)
;
ivalc:	cpi	' '		; 
	jz	ival		; Ignore leading spaces
	cpi	'+'		; 
	jz	ival		; Ignore unary +
	call	qnum		; 
	lxi	h,0		; Clear acc
	mvi	d,40H		;   and exponent.
	jnc	ival6		; Initial numeric entry
	cpi	'.'		; 
	jz	ival1		; Initial decimal point
	cpi	'-'		; 
	stc			; 
	mov	l,a		;   (A) is illegal char.
	rnz			; Error, return 0 and Carry,
	call	ival		; Recursive unary -
	push	psw		; Save exit char
	fsign	d		; 
	pop	psw		; 
	rtn			; 
ival1:	getch			; After initial decimal point
	call	qnum		; 
	jnc	ival4		; Got the required digit
	mov	l,a		; Exit char to (L)
	stc			; 
	rtn			; Illegal initial char
ival2:	inr	d		; Incorporate digit
	getch			; Get next digit
	call	qnum		; 
	jnc	ival2		; Still digit string
	cpi	'.'		; Will be ignored
	jnz	ival8		; Check for exponent
ival3:	getch			; Digits after decimal point
	call	qnum		; 
	jc	ival8		; Non-digit
	call	qmax		; 
	jc	ival3		; No room, ignore
	call	mul10		; 
ival4:	ani	0FH		; Mask off digit
	dcr	d		; Modify exponent digits after
	add	l		;   decimal point.
	mov	l,a		; 
	mov	a,h		; 
	aci	00H		; 
	mov	h,a		; 
	jnc	ival3		; No overflow
	lxi	h,6554		; Set max
	inr	d		; 
	jmp	ival3		; 
ival5:	call	qmax		; Digits to left of decimal point
	jc	ival2		; No more digit room
	call	mul10		; 
ival6:	ani	0FH		; Mask off digit
	add	l		; 
	mov	l,a		; 
	mov	a,h		; 
	aci	00H		; 
	mov	h,a		; Incorporate digit
	jnc	ival7		; No overflow
	lxi	h,65535		; Max
ival7:	getch			; Get next digit/char
	call	qnum		; 
	jnc	ival5		; Digit
	cpi	'.'		; 
	jz	ival3		; Decimal point
ival8:	cpi	'E'		; 
	jz	ival9		; 
	cpi	'e'		; Lower case allowed
ival9:	xchg			; 
	stc			; 
	cmc			; Clear any Carry
	cz	rexp		; "E", read exponent
	mov	l,a		; Exit char
	cnc	unfix		; Convert format if no overflow yet
	rnc			; No overflow
	mvi	a,80H		; Overflow code
	rtn			; 
;
; "Fixed" point representation consists of a 16 bit positive
; integer (in the range 0 to 65535), and a 7 bit offset (by
; 40H) integer exponent, which represents a power of ten
; multiplier. The eighth exponent bit represents the sign
; of the mantissa. This representation is used for input/
; output only.
;
; Convert "fixed" format to "real"
; Carry for input out of range
; F,D,E,H
;
unfix:	save	bc.l		; 
	push	psw		; 
	mov	a,h		; 
	ani	80H		; 
	mov	b,a		; Sign of result
	mov	a,h		; 
	ani	7FH		; 
	sui	40H		; 
	mov	c,a		; Decimal point
	call	flotd		; 
	mov	a,h		; 
	ora	a		; 
	jz	unfix4		; Zero value
	mov	a,d		; 
	ora	b		; 
	mov	d,a		; Incorporate sign
	mov	a,c		; 
	ora	a		; 
@01	set	.lvl		; 
unfix1:	jz	unfix4		; Reduced to real
	jm	unfix3		; Negative exponent
	call	fmult		; Positive exponent
	dcr	c		; 
	jnc	unfix1		; In range
unfix2:	pop	psw		; 
	stc			; 
	jmp	unfix5		; 
.lvl	set	@01		; 
unfix3:	call	fdivt		; Negative exponent
	inr	c		; 
	jnc	unfix1		; Continue
	jmp	unfix2		; Underflow
unfix4:	pop	psw		; 
	ora	a		; Reset Carry, no overflow
unfix5:	reload	bc.l		; 
	rtn			; 
;
; Read 2 digit signed decimal exponent
;   to (A). Return exit character in (D).
; A,F,D,E
;
r2dc:	getch			; Get char
	call	qnum		; 
	jc	r2dc3		; Not digit
r2dc1:	lxi	d,0		; 
r2dc2:	dcr	d		; 
	inr	d		; 
	stc			; 
	rnz			; Overflow, 3 digits entered,
	mov	d,e		;   first non-zero.
	ani	0FH		; 
	mov	e,a		; 
	getch			; 
	call	qnum		; 
	jnc	r2dc2		; 
	push	psw		; 
	mov	a,d		; 
	add	a		; 
	add	a		; 4*
	add	d		; 
	add	a		; 10*
	add	e		; Value MOD 100
	pop	d		; 
	rtn			; 
r2dc3:	cpi	'+'		; 
	jz	r2dc		; Ignore unary +
	cpi	'-'		; 
	jnz	r2dc4		; Not unary -
	call	r2dc		; 
	cma			; 
	inr	a		; 
	rtn			; 
r2dc4:	mov	d,a		; 
	mvi	a,0		; Return 0, none came
	rtn			; 
;
; Read exponent and combine with "fixed" value
; Return exit char in (A)
; A,F,D
;
rexp:	push	d		; 
	call	r2dc		; Get exponent
	jc	rexp1		; Overflow
	push	d		; Save exit char
	mov	d,a		; Exponent
	mov	a,h		; 
	ani	80H		; 
	mov	e,a		; Sign
	mov	a,h		; 
	ani	7FH		; Exponent alone
	add	d		; 
	jp	rexp2		; No overflow
@01	set	.lvl		; 
	pop	psw		; Exit char
rexp1:	pop	d		; 
	stc			; Signal overflow
	rtn			; 
.lvl	set	@01		; 
rexp2:	ora	e		; Original sign
	mov	h,a		; Resultant exponent
	pop	psw		; Restore exit char
	pop	d		; Restore mantissa
	ora	a		; Clear Carry, no overflow
	rtn			; 
;
;--------------------------------
;
	end			; of FLTINPUT.ASM
