numparser2.h

changeset 0
86b7f6f9c5c0
child 1
6e704fc09528
equal deleted inserted replaced
-1:000000000000 0:86b7f6f9c5c0
1 /*
2 * libtu/numparser2.h
3 *
4 * Copyright (c) Tuomo Valkonen 1999-2000.
5 *
6 * This file is distributed under the terms of the "Artistic License".
7 * See the included file LICENSE for details.
8 */
9
10 #define MAX_MANTISSA 10 /* should be enough for our needs */
11 #define ULONG_SIZE (sizeof(ulong)*8)
12
13 /*
14 * Can handle quite big numbers (depends on MAX_MANTISSA). This is really
15 * a crappy little hack (especially the generic (non-i386asm) mulby10
16 * algorithm... hopefully it works...) but this'll do for now.
17 */
18
19 enum{
20 NPNUM_INT,
21 NPNUM_FLOAT
22 };
23
24 typedef struct _NPNum{
25 unsigned char nmantissa;
26 int type;
27 int base;
28 bool negative;
29 ulong mantissa[MAX_MANTISSA];
30 long exponent;
31 } NPNum;
32
33 #define NUM_INIT {0, 0, 0, 0, {0,}, 0}
34
35 #define ADD_EXP(NUM, X) (NUM)->exponent+=(X);
36
37 #if defined(__GNUG__) && defined(i386) && !defined(LIBTU_NP_NO_I386_ASM)
38 #define LIBTU_NP_I386_ASM
39 #endif
40
41 static int npnum_mulbase_add(NPNum *num, long base, long v)
42 {
43 long i, j;
44 ulong overflow;
45 #ifndef LIBTU_NP_I386_ASM
46 ulong val;
47 #endif
48
49 for(i=num->nmantissa;i>=0;i--){
50 #ifdef LIBTU_NP_I386_ASM
51 __asm__("mul %4\n"
52 : "=a" (num->mantissa[i]), "=d" (overflow)
53 : "0" (num->mantissa[i]), "1" (0), "q" (base)
54 : "eax", "edx");
55 #else
56 overflow=0;
57 val=num->mantissa[i];
58
59 if(val<ULONG_MAX/base){
60 val*=base;
61 }else if(val){
62 ulong tmp=val;
63 ulong old=val;
64 for(j=0; j<base; j++){
65 val+=tmp;
66 if(val<=old)
67 overflow++;
68 old=val;
69 }
70 }
71 num->mantissa[i]=val;
72 #endif
73 if(overflow){
74 if(i==num->nmantissa){
75 if(num->nmantissa==MAX_MANTISSA)
76 return E_TOKZ_TOOBIG;
77 num->nmantissa++;
78 }
79 num->mantissa[i+1]+=overflow;
80 }
81 }
82 num->mantissa[0]+=v;
83
84 return 0;
85 }
86
87 #undef LIBTU_NP_I386_ASM
88
89
90 /* */
91
92
93 static bool is_end(int c)
94 {
95 return ((c!='.' && ispunct(c)) || isspace(c) || iscntrl(c));
96 }
97
98
99 /* */
100
101
102 static int parse_exponent(NPNum *num, Tokenizer *tokz, int c)
103 {
104 long exp=0;
105 bool neg=FALSE;
106 int err=0;
107
108 c=GETCH();
109
110 if(c=='-' || c=='+'){
111 if(c=='-')
112 neg=TRUE;
113 c=GETCH();
114 }
115
116 for(; 1; c=GETCH()){
117 if(isdigit(c)){
118 exp*=10;
119 exp+=c-'0';
120 }else if(is_end(c)){
121 UNGETCH(c);
122 break;
123 }else{
124 err=E_TOKZ_NUMFMT;
125 }
126 }
127
128 if(neg)
129 exp*=-1;
130
131 ADD_EXP(num, exp);
132
133 return err;
134 }
135
136
137 static int parse_number(NPNum *num, Tokenizer *tokz, int c)
138 {
139 int base=10;
140 int dm=1;
141 int err=0;
142 int tmp;
143
144 if(c=='-' || c=='+'){
145 if(c=='-')
146 num->negative=TRUE;
147 c=GETCH();
148 if(!isdigit(c))
149 err=E_TOKZ_NUMFMT;
150 }else if(c=='0'){
151 dm=0;
152 c=GETCH();
153 if(c=='x' || c=='X'){
154 base=16;
155 c=GETCH();
156 }else if(c=='b' || c=='B'){
157 base=2;
158 c=GETCH();
159 }else if('0'<=c && c<='7'){
160 base=7;
161 }else{
162 dm=2;
163 }
164 }
165
166 num->base=base;
167
168 for(; 1; c=GETCH()){
169 if((c=='e' || c=='E') && dm!=0){
170 if(dm<2){
171 err=E_TOKZ_NUMFMT;
172 continue;
173 }
174 tmp=parse_exponent(num, tokz, c);
175 if(err==0)
176 err=tmp;
177 break;
178 }
179
180 if(isxdigit(c)){
181 if('0'<=c && c<='9')
182 c-='0';
183 else if(isupper(c))
184 c-='A'-10;
185 else
186 c-='a'-10;
187
188 if(c>=base)
189 err=E_TOKZ_NUMFMT;
190
191 npnum_mulbase_add(num, base, c);
192
193 if(dm==1)
194 dm=2;
195 else if(dm==3)
196 ADD_EXP(num, -1);
197
198 continue;
199 }
200
201 if(c=='.'){
202 if(dm!=2)
203 err=E_TOKZ_NUMFMT;
204 else
205 dm=3;
206 continue;
207 }
208
209 if(is_end(c)){
210 UNGETCH(c);
211 break;
212 }
213
214 err=E_TOKZ_NUMFMT;
215 }
216
217 num->type=(num->exponent==0 ? NPNUM_INT : NPNUM_FLOAT);
218
219 return err;
220 }

mercurial