|
1 /* |
|
2 * libtu/numparser2.h |
|
3 * |
|
4 * Copyright (c) Tuomo Valkonen 1999-2002. |
|
5 * |
|
6 * You may distribute and modify this library under the terms of either |
|
7 * the Clarified Artistic License or the GNU LGPL, version 2.1 or later. |
|
8 */ |
|
9 |
|
10 #define MAX_MANTISSA 10 /* should be enough for our needs */ |
|
11 #define ULONG_SIZE (sizeof(ulong)*8) |
|
12 |
|
13 enum{ |
|
14 NPNUM_INT, |
|
15 NPNUM_FLOAT |
|
16 }; |
|
17 |
|
18 #ifdef NP_SIMPLE_IMPL |
|
19 |
|
20 typedef struct _NPNum{ |
|
21 int type; |
|
22 int base; |
|
23 bool negative; |
|
24 double fval; |
|
25 ulong ival; |
|
26 } NPNum; |
|
27 |
|
28 #define NUM_INIT {0, 0, 0, 0.0, 0} |
|
29 |
|
30 static int npnum_mulbase_add(NPNum *num, long base, long v) |
|
31 { |
|
32 double iold=num->ival; |
|
33 |
|
34 num->fval=num->fval*base+(double)v; |
|
35 |
|
36 num->ival*=base; |
|
37 |
|
38 if(num->ival<iold) |
|
39 num->type=NPNUM_FLOAT; |
|
40 |
|
41 num->ival+=v; |
|
42 |
|
43 return 0; |
|
44 } |
|
45 |
|
46 #else /* NP_SIMPLE_IMPL */ |
|
47 |
|
48 typedef struct _NPNum{ |
|
49 unsigned char nmantissa; |
|
50 int type; |
|
51 int base; |
|
52 bool negative; |
|
53 ulong mantissa[MAX_MANTISSA]; |
|
54 long exponent; |
|
55 } NPNum; |
|
56 |
|
57 #define NUM_INIT {0, 0, 0, 0, {0,}, 0} |
|
58 |
|
59 #define ADD_EXP(NUM, X) (NUM)->exponent+=(X); |
|
60 |
|
61 #if defined(__GNUG__) && defined(i386) && !defined(NP_NO_I386_ASM) |
|
62 #define NP_I386_ASM |
|
63 #endif |
|
64 |
|
65 static int npnum_mulbase_add(NPNum *num, long base, long v) |
|
66 { |
|
67 long i, j; |
|
68 ulong overflow; |
|
69 #ifndef NP_I386_ASM |
|
70 ulong val; |
|
71 #endif |
|
72 |
|
73 for(i=num->nmantissa;i>=0;i--){ |
|
74 #ifdef NP_I386_ASM |
|
75 __asm__("mul %4\n" |
|
76 : "=a" (num->mantissa[i]), "=d" (overflow) |
|
77 : "0" (num->mantissa[i]), "1" (0), "q" (base) |
|
78 : "eax", "edx"); |
|
79 #else |
|
80 overflow=0; |
|
81 val=num->mantissa[i]; |
|
82 |
|
83 if(val<ULONG_MAX/base){ |
|
84 val*=base; |
|
85 }else if(val){ |
|
86 ulong tmp=val; |
|
87 ulong old=val; |
|
88 for(j=0; j<base; j++){ |
|
89 val+=tmp; |
|
90 if(val<=old) |
|
91 overflow++; |
|
92 old=val; |
|
93 } |
|
94 } |
|
95 num->mantissa[i]=val; |
|
96 #endif |
|
97 if(overflow){ |
|
98 if(i==num->nmantissa){ |
|
99 if(num->nmantissa==MAX_MANTISSA) |
|
100 return E_TOKZ_TOOBIG; |
|
101 num->nmantissa++; |
|
102 } |
|
103 num->mantissa[i+1]+=overflow; |
|
104 } |
|
105 } |
|
106 num->mantissa[0]+=v; |
|
107 |
|
108 return 0; |
|
109 } |
|
110 |
|
111 #undef NP_I386_ASM |
|
112 |
|
113 #endif /* NP_SIMPLE_IMPL */ |
|
114 |
|
115 |
|
116 /* */ |
|
117 |
|
118 |
|
119 static bool is_end(int c) |
|
120 { |
|
121 /* oops... EOF was missing */ |
|
122 return (c==EOF || (c!='.' && ispunct(c)) || isspace(c) || iscntrl(c)); |
|
123 } |
|
124 |
|
125 |
|
126 /* */ |
|
127 |
|
128 |
|
129 static int parse_exponent(NPNum *num, Tokenizer *tokz, int c) |
|
130 { |
|
131 long exp=0; |
|
132 bool neg=FALSE; |
|
133 int err=0; |
|
134 |
|
135 c=GETCH(); |
|
136 |
|
137 if(c=='-' || c=='+'){ |
|
138 if(c=='-') |
|
139 neg=TRUE; |
|
140 c=GETCH(); |
|
141 } |
|
142 |
|
143 for(; 1; c=GETCH()){ |
|
144 if(isdigit(c)){ |
|
145 exp*=10; |
|
146 exp+=c-'0'; |
|
147 }else if(is_end(c)){ |
|
148 UNGETCH(c); |
|
149 break; |
|
150 }else{ |
|
151 err=E_TOKZ_NUMFMT; |
|
152 } |
|
153 } |
|
154 |
|
155 if(neg) |
|
156 exp*=-1; |
|
157 |
|
158 #ifndef NP_SIMPLE_IMPL |
|
159 ADD_EXP(num, exp); |
|
160 #else |
|
161 num->fval*=pow(num->base, exp); |
|
162 #endif |
|
163 return err; |
|
164 } |
|
165 |
|
166 |
|
167 static int parse_number(NPNum *num, Tokenizer *tokz, int c) |
|
168 { |
|
169 int base=10; |
|
170 int dm=1; |
|
171 int err=0; |
|
172 int tmp; |
|
173 #ifdef NP_SIMPLE_IMPL |
|
174 double divisor=base; |
|
175 #endif |
|
176 |
|
177 if(c=='-' || c=='+'){ |
|
178 if(c=='-') |
|
179 num->negative=TRUE; |
|
180 c=GETCH(); |
|
181 if(!isdigit(c)) |
|
182 err=E_TOKZ_NUMFMT; |
|
183 } |
|
184 |
|
185 if(c=='0'){ |
|
186 dm=0; |
|
187 c=GETCH(); |
|
188 if(c=='x' || c=='X'){ |
|
189 base=16; |
|
190 c=GETCH(); |
|
191 }else if(c=='b' || c=='B'){ |
|
192 base=2; |
|
193 c=GETCH(); |
|
194 }else if('0'<=c && c<='7'){ |
|
195 base=8; |
|
196 }else{ |
|
197 dm=2; |
|
198 } |
|
199 } |
|
200 |
|
201 num->base=base; |
|
202 |
|
203 for(; 1; c=GETCH()){ |
|
204 if((c=='e' || c=='E') && dm!=0){ |
|
205 if(dm<2){ |
|
206 err=E_TOKZ_NUMFMT; |
|
207 continue; |
|
208 } |
|
209 tmp=parse_exponent(num, tokz, c); |
|
210 if(err==0) |
|
211 err=tmp; |
|
212 break; |
|
213 } |
|
214 |
|
215 if(isxdigit(c)){ |
|
216 if('0'<=c && c<='9') |
|
217 c-='0'; |
|
218 else if(isupper(c)) |
|
219 c-='A'-10; |
|
220 else |
|
221 c-='a'-10; |
|
222 |
|
223 if(c>=base) |
|
224 err=E_TOKZ_NUMFMT; |
|
225 |
|
226 #ifdef NP_SIMPLE_IMPL |
|
227 if(dm==3){ |
|
228 num->fval+=(double)c/divisor; |
|
229 divisor*=base; |
|
230 }else |
|
231 #endif |
|
232 { |
|
233 tmp=npnum_mulbase_add(num, base, c); |
|
234 if(err==0) |
|
235 err=tmp; |
|
236 } |
|
237 |
|
238 if(dm==1) |
|
239 dm=2; |
|
240 #ifndef NP_SIMPLE_IMPL |
|
241 else if(dm==3) |
|
242 ADD_EXP(num, -1); |
|
243 #endif |
|
244 continue; |
|
245 } |
|
246 |
|
247 if(c=='.'){ |
|
248 if(dm!=2){ |
|
249 err=E_TOKZ_NUMFMT; |
|
250 } |
|
251 dm=3; |
|
252 #ifdef NP_SIMPLE_IMPL |
|
253 num->type=NPNUM_FLOAT; |
|
254 divisor=base; |
|
255 #endif |
|
256 continue; |
|
257 } |
|
258 |
|
259 if(is_end(c)){ |
|
260 UNGETCH(c); |
|
261 break; |
|
262 } |
|
263 |
|
264 err=E_TOKZ_NUMFMT; |
|
265 } |
|
266 |
|
267 #ifndef NP_SIMPLE_IMPL |
|
268 num->type=(num->exponent==0 ? NPNUM_INT : NPNUM_FLOAT); |
|
269 #endif |
|
270 |
|
271 return err; |
|
272 } |