File: numberio.fth

package info (click to toggle)
pforth 21-11
  • links: PTS
  • area: main
  • in suites: lenny, squeeze, wheezy
  • size: 820 kB
  • ctags: 873
  • sloc: ansic: 5,050; makefile: 102
file content (204 lines) | stat: -rw-r--r-- 4,556 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
\ @(#) numberio.fth 98/01/26 1.2
\ numberic_io.fth
\
\ numeric conversion
\ 
\ Author: Phil Burk
\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom
\
\ The pForth software code is dedicated to the public domain,
\ and any third party may reproduce, distribute and modify
\ the pForth software code or any derivative works thereof
\ without any compensation or license.  The pForth software
\ code is provided on an "as is" basis without any warranty
\ of any kind, including, without limitation, the implied
\ warranties of merchantability and fitness for a particular
\ purpose and their equivalents under the laws of any jurisdiction.

anew task-numeric_io.fth
decimal

\ ------------------------ INPUT -------------------------------
\ Convert a single character to a number in the given base.
: DIGIT   ( char base -- n true | char false )
	>r
\ convert lower to upper
	dup ascii a < not
	IF
		ascii a - ascii A +
	THEN
\
	dup dup ascii A 1- >
	IF ascii A - ascii 9 + 1+
	ELSE ( char char )
		dup ascii 9 >
		IF
			( between 9 and A is bad )
			drop 0 ( trigger error below )
		THEN
	THEN
	ascii 0 -
	dup r> <
	IF dup 1+ 0>
		IF nip true
		ELSE drop FALSE
		THEN
	ELSE drop FALSE
	THEN
;

: >NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 , convert till bad char , CORE )
	>r
	BEGIN
		r@ 0>    \ any characters left?
		IF
			dup c@ base @
			digit ( ud1 c-addr , n true | char false )
			IF
				TRUE
			ELSE
				drop FALSE
			THEN
		ELSE
			false
		THEN
	WHILE ( -- ud1 c-addr n  )
		swap >r  ( -- ud1lo ud1hi n  )
		swap  base @ ( -- ud1lo n ud1hi base  )
		um* drop ( -- ud1lo n ud1hi*baselo  )
		rot  base @ ( -- n ud1hi*baselo ud1lo base )
		um* ( -- n ud1hi*baselo ud1lo*basello ud1lo*baselhi )
		d+  ( -- ud2 )
		r> 1+     \ increment char*
		r> 1- >r  \ decrement count
	REPEAT
	r>
;

\ obsolete
: CONVERT  ( ud1 c-addr1 -- ud2 c-addr2 , convert till bad char , CORE EXT )
	256 >NUMBER DROP
;

0 constant NUM_TYPE_BAD
1 constant NUM_TYPE_SINGLE
2 constant NUM_TYPE_DOUBLE

\ This is similar to the F83 NUMBER? except that it returns a number type
\ and then either a single or double precision number.
: ((NUMBER?))   ( c-addr u -- 0 | n 1 | d 2 , convert string to number )
	dup 0= IF drop NUM_TYPE_BAD exit THEN   \ any chars?
	
\ prepare for >number
	0 0 2swap ( 0 0 c-addr cnt )

\ check for '-' at beginning, skip if present
	over c@ ascii - = \ is it a '-'
	dup >r            \ save flag
	IF 1- >r 1+ r>  ( -- 0 0 c-addr+1 cnt-1 , skip past minus sign )
	THEN
\
	>number dup 0=   \ convert as much as we can
	IF
		2drop    \ drop addr cnt
		drop     \ drop hi part of num
		r@       \ check flag to see if '-' sign used
		IF  negate
		THEN
		NUM_TYPE_SINGLE
	ELSE  ( -- d addr cnt )
		1 = swap             \ if final character is '.' then double
		c@ ascii . =  AND
		IF
			r@      \ check flag to see if '-' sign used
			IF  dnegate
			THEN
			NUM_TYPE_DOUBLE
		ELSE
			2drop
			NUM_TYPE_BAD
		THEN
	THEN
	rdrop
;

: (NUMBER?)   ( $addr -- 0 | n 1 | d 2 , convert string to number )
	count ((number?))
;

' (number?) is number?
\ hex
\ 0sp c" xyz" (number?) .s
\ 0sp c" 234" (number?) .s
\ 0sp c" -234" (number?) .s
\ 0sp c" 234." (number?) .s
\ 0sp c" -234." (number?) .s
\ 0sp c" 1234567855554444." (number?) .s


\ ------------------------ OUTPUT ------------------------------
\ Number output based on F83
variable HLD    \ points to last character added 

: hold   ( char -- , add character to text representation)
	-1 hld  +!
	hld @  c!
;
: <#     ( -- , setup conversion )
	pad hld !
;
: #>     ( d -- addr len , finish conversion )
	2drop  hld @  pad  over -
;
: sign   ( n -- , add '-' if negative )
	0<  if  ascii - hold  then
;
: #      ( d -- d , convert one digit )
   base @  mu/mod rot 9 over <
   IF  7 +
   THEN
   ascii 0 + hold
;
: #s     ( d -- d , convert remaining digits )
	BEGIN  #  2dup or 0=
	UNTIL
;


: (UD.) ( ud -- c-addr cnt )
	<# #s #>
;
: UD.   ( ud -- , print unsigned double number )
	(ud.)  type space
;
: UD.R  ( ud n -- )
	>r  (ud.)  r> over - spaces type
;
: (D.)  ( d -- c-addr cnt )
	tuck dabs <# #s rot sign #>
;
: D.    ( d -- )
	(d.)  type space
;
: D.R   ( d n -- , right justified )
	>r  (d.)  r>  over - spaces  type
;

: (U.)  ( u -- c-addr cnt )
	0 (ud.)
;
: U.    ( u -- , print unsigned number )
	0 ud.
;
: U.R   ( u n -- , print right justified )
	>r  (u.)  r> over - spaces  type
;
: (.)   ( n -- c-addr cnt )
	dup abs 0 <# #s rot sign #>
;
: .     ( n -- , print signed number)
   (.)  type space
;
: .R    ( n l -- , print right justified)
	>r  (.)  r> over - spaces type
;