comparison src/number.s @ 84:f959c92bc329

New first pass implementation of number parsing, untested Rewrite number parsing using recently constructed infrastructure. The result is untested.
author William Astle <lost@l-w.ca>
date Sun, 08 Oct 2023 00:17:20 -0600
parents bb50ac9fdf37
children 663d8e77b579
comparison
equal deleted inserted replaced
83:a492441bfc56 84:f959c92bc329
98 lbeq int32_mod ; do integer modulus 98 lbeq int32_mod ; do integer modulus
99 cmpb #valtype_float ; floating point? 99 cmpb #valtype_float ; floating point?
100 lbeq fps_mod ; floating point modulus 100 lbeq fps_mod ; floating point modulus
101 jmp TMERROR ; unsupported type 101 jmp TMERROR ; unsupported type
102 endc 102 endc
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 ; Parse a number to either an integer or a floating point value
105 ;
106 ; First, identify any sign present. Then parse the remainder as an integer until either a decimal point, an exponential
107 ; indicator, or the value gets larger than 32 bits. If any of those eventualities happens, convert to floating point
108 ; and then continue parsing the number as floating point. The result will be stored to (Y).
109 val_parsenum lbeq SNERROR ; brif no numberr to parse
110 ldd zero ; zero out integer value accumulator
111 std fpa0extra
112 std fpa0extra+2
113 std fpa0extra+4
114 std fpa0extra+6
115 sta fpa0extra12 ; zero out result sign to default positive
116 jsr curchar ; get current input character
117 bra val_parsenum1 ; parse flags
118 val_parsenum0 jsr nextchar ; get next input character
119 val_parsenum1 bcs val_parsenum5 ; brif digit
120 beq val_parsenum ; brif end of input
121 cmpa #'. ; decimal?
122 lbeq val_parsefloat ; switch to parsing floating point
123 cmpa #'- ; minus?
124 beq val_parsenum2 ; brif so
125 cmpa #tok_minus ; unary minus operator?
126 bne val_parsenum3 ; brif not
127 val_parsenum2 com fpa0extra12 ; invert current sign
128 bra val_parsenum0 ; go handle more stuff at the start of the number
129 val_parsenum3 cmpa #'+ ; unary +?
130 beq val_parsenum0 ; brif so - skip it
131 cmpa #tok_plus ; unary + operator?
132 beq val_parsenum0 ; brif so - skip it
133 val_parsenum4 lda fpa0extra4 ; is bit 7 of high byte set?
134 bpl val_parsenum4a ; brif not - no overflow
135 ldb fpa0extra12 ; do we want negative?
136 lbpl val_parsefloat ; brif not - we overflowed so convert to floating point
137 anda #0x7f ; lose sign bit then see if any other bits are set
138 ora fpa0extra5
139 ora fpa0extra6
140 ora fpa0extra7
141 lbne val_parsefloat ; brif nonzero bits - too big for max negative 2's complement
142 val_parsenum4a lda fpa0extra12 ; do we want negative?
143 bpl val_parsenum4b ; brif not
144 ldd zero ; negate it
145 subd fpa0extra6
146 std fpa0extra6
147 ldd zero
148 sbcb fpa0extra5
149 sbca fpa0extra4
150 std fpa0extra4
151 val_parsenum4b ldd fpa0extra6 ; copy value to result location
152 std val.int+2,y
153 ldd fpa0extra4
154 std val.int,y
155 lda #valtype_int ; set value type to integer
156 sta val.type,y
157 rts
158 val_parsenum4c jsr nextchar ; fetch next character (after a digit)
159 bcs val_parsenum5 ; it's a digit
160 cmpa #'. ; decimal?
161 beq val_parsefloat ; brif so - handle floating point
162 cmpa #'E ; exponent?
163 beq val_parsefloat ; brif so - handle floating point
164 cmpa #'e ; exponent but lower case?
165 beq val_parsefloat ; brif so - handle floating point
166 bra val_parsenum4 ; unrecognized character - treat as end of number
167 val_parsenum5 suba #'0 ; offset digit to binary
168 pshs a ; save it for later addition
169 ldx fpa0extra4 ; save original value
170 stx fpa0extra8
171 ldx fpa0extra6
172 stx fpa0extra10
173 lsl fpa0extra7 ; shift partial result left (times 2)
174 rol fpa0extra6
175 rol fpa0extra5
176 rol fpa0extra4
177 rol fpa0extra3
178 lsl fpa0extra7 ; shift partial result left (times 4)
179 rol fpa0extra6
180 rol fpa0extra5
181 rol fpa0extra4
182 rol fpa0extra3
183 ldd fpa0extra6 ; add in original value (time 5)
184 addd fpa0extra10
185 std fpa0extra6
186 ldd fpa0extra8
187 adcb fpa0extra5
188 adca fpa0extra4
189 std fpa0extra4
190 ldb fpa0extra3
191 adcb #0
192 stb fpa0extra3
193 lsl fpa0extra7 ; shift partial result left (times 10)
194 rol fpa0extra6
195 rol fpa0extra5
196 rol fpa0extra4
197 rol fpa0extra3
198 ldd fpa0extra6 ; add in new digit
199 addb ,s+
200 adca #0
201 std fpa0extra6
202 ldd fpa0extra4 ; and propagate carry
203 adcb #0
204 adca #0
205 std fpa0extra4
206 ldb fpa0extra3
207 adcb #0
208 stb fpa0extra3
209 beq val_parsenum4c ; go handle next digit if we didn't overflow past 32 bits
210 jsr nextchar ; eat the digit we just handled
211 val_parsefloat pshs y ; save destination pointer
212 lda #valtype_float ; set return type to floating point
213 sta val.type,y
214 ldx #fpa0extra ; point to integer accumulator
215 jsr fps_fromuint64 ; convert to floating point
216 clr fpa0extra11 ; zero out decimal counter
217 clr fpa0extra10 ; zero out decimal exponent counter
218 clr fpa0extra9 ; flag for decimal seen
219 jsr curchar ; fetch current character
220 bra val_parsefloat1 ; go handle character
221 val_parsefloat0 jsr nextchar ; fetch next character
222 val_parsefloat1 bcc val_parsefloat2 ; brif not digit
223 suba #'0 ; adjust digit to binary
224 sta fpa0extra3 ; save it for later (upper 3 bytes of 32 bit value already 0)
225 ldx ,s ; get destination value
226 jsr fps_mul10 ; do a quick multiply by 10
227 ldx #fpa0extra ; convert digit to floating point
228 ldy #fpa1
229 jsr fps_fromuint32
230 ldu #fpa1 ; add digit to accumulated value
231 ldx ,s
232 leay ,x
233 jsr fps_add
234 lda fpa0extra11 ; update decimal counter
235 suba fpa0extra9
236 sta fpa0extra11
237 bra val_parsefloat0 ; go handle another digit
238 val_parsefloat2 cmpa #'. ; decimal?
239 bne val_parsefloat7 ; brif not
240 com fpa0extra9 ; flag for decimal
241 bne val_parsefloat0 ; brif not two decimals - keep parsing
242 val_parsefloat3 ldb fpa0extra10 ; fetch decimal exponent counter
243 subb fpa0extra11 ; subtract out decimal places provided
244 beq val_parsefloat6 ; brif no adjustment needed
245 stb fpa0extra9 ; save counter
246 bmi val_parsefloat5 ; brif negative exponent - need to do divisions
247 val_parsefloat4 ldx ,s ; point to destination value
248 jsr fps_mul10 ; multiply by 10
249 dec fpa0extra9 ; done all of them?
250 bne val_parsefloat4 ; brif not
251 bra val_parsefloat6
252 val_parsefloat5 ldx ,s ; point to destination value
253 jsr fps_div10 ; divide by 10
254 inc fpa0extra9 ; done all of them?
255 bne val_parsefloat5 ; brif not
256 val_parsefloat6 puls y ; get back destination pointer
257 lda fpa0extra12 ; get desired sign
258 sta val.fpssign,y ; set in result
259 rts
260 val_parsefloat7 cmpa #'E ; decimal exponent?
261 beq val_parsefloat8 ; brif so
262 cmpa #'e ; decimal exponent, lower case edition?
263 bne val_parsefloat3 ; brif not - must be end of number
264 val_parsefloat8 clr fpa0extra9 ; set sign of exponent to positive
265 jsr nextchar ; fetch exponent character
266 bcs val_parsefloat11 ; brif digit
267 cmpa #'+ ; positive exponent?
268 beq val_parsefloat10 ; brif so - skip it
269 cmpa #tok_plus ; positive exponent, operator style?
270 beq val_parsefloat10 ; brif so - skip it
271 cmpa #'- ; negative exponent?
272 beq val_parsefloat9 ; brif so
273 cmpa #tok_minus ; negative exponent, operator style?
274 bne val_parsefloat3 ; brif not - must be end of exponent
275 val_parsefloat9 com fpa0extra9 ; set exponent to negative
276 val_parsefloat10
277 jsr nextchar ; eat exponent sign
278 bcc val_parsefloat12 ; brif end of exponent - apply sign
279 val_parsefloat11
280 suba #'0 ; binary-ize digit
281 sta fpa0extra8 ; save digit for later
282 lda #10 ; mutiply current decimal exponent by 10
283 ldb fpa0extra10 ; get current exponent
284 mul
285 adca #0 ; set A if we overflowed *or* bit 7 of B is set
286 lbne OVERROR ; brif exponent overflow
287 addb fpa0extra8 ; add in digit
288 lbvs OVERROR ; brif exponent overflow
289 stb fpa0extra10 ; save new exponent
290 bra val_parsefloat10 ; go handle next exponent digit
291 val_parsefloat12
292 ldb fpa0extra9 ; do we have a negative exponent?
293 beq val_parsefloat3 ; brif not, go adjust value by exponent and return
294 neg fpa0extra10 ; set base 10 exponent negative
295 bra val_parsefloat3 ; go adjust value by exponent and return
103 *pragmapop list 296 *pragmapop list