]> git.decadent.org.uk Git - ion3.git/blob - libtu/numparser2.h
[svn-inject] Installing original source of ion3
[ion3.git] / libtu / numparser2.h
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 }