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