Tue, 17 Oct 2006 00:32:05 +0200
Path fix
| 60 | 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{ | |
| 62 | 14 | NPNUM_INT, |
| 15 | NPNUM_FLOAT | |
| 60 | 16 | }; |
| 17 | ||
| 18 | #ifdef NP_SIMPLE_IMPL | |
| 19 | ||
| 20 | typedef struct _NPNum{ | |
| 62 | 21 | int type; |
| 22 | int base; | |
| 23 | bool negative; | |
| 24 | double fval; | |
| 25 | ulong ival; | |
| 60 | 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 | { | |
| 62 | 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; | |
| 60 | 44 | } |
| 45 | ||
| 46 | #else /* NP_SIMPLE_IMPL */ | |
| 47 | ||
| 48 | typedef struct _NPNum{ | |
| 62 | 49 | unsigned char nmantissa; |
| 50 | int type; | |
| 51 | int base; | |
| 52 | bool negative; | |
| 53 | ulong mantissa[MAX_MANTISSA]; | |
| 54 | long exponent; | |
| 60 | 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 | { | |
| 62 | 67 | long i, j; |
| 68 | ulong overflow; | |
| 60 | 69 | #ifndef NP_I386_ASM |
| 62 | 70 | ulong val; |
| 60 | 71 | #endif |
| 62 | 72 | |
| 73 | for(i=num->nmantissa;i>=0;i--){ | |
| 60 | 74 | #ifdef NP_I386_ASM |
| 62 | 75 | __asm__("mul %4\n" |
| 76 | : "=a" (num->mantissa[i]), "=d" (overflow) | |
| 77 | : "0" (num->mantissa[i]), "1" (0), "q" (base) | |
| 78 | : "eax", "edx"); | |
| 60 | 79 | #else |
| 62 | 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; | |
| 60 | 96 | #endif |
| 62 | 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; | |
| 60 | 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 | { | |
| 62 | 121 | /* oops... EOF was missing */ |
| 122 | return (c==EOF || (c!='.' && ispunct(c)) || isspace(c) || iscntrl(c)); | |
| 60 | 123 | } |
| 124 | ||
| 125 | ||
| 126 | /* */ | |
| 127 | ||
| 128 | ||
| 129 | static int parse_exponent(NPNum *num, Tokenizer *tokz, int c) | |
| 130 | { | |
| 62 | 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 | } | |
| 60 | 154 | |
| 62 | 155 | if(neg) |
| 156 | exp*=-1; | |
| 60 | 157 | |
| 158 | #ifndef NP_SIMPLE_IMPL | |
| 62 | 159 | ADD_EXP(num, exp); |
| 60 | 160 | #else |
| 62 | 161 | num->fval*=pow(num->base, exp); |
| 162 | #endif | |
| 163 | return err; | |
| 60 | 164 | } |
| 165 | ||
| 166 | ||
| 167 | static int parse_number(NPNum *num, Tokenizer *tokz, int c) | |
| 168 | { | |
| 62 | 169 | int base=10; |
| 170 | int dm=1; | |
| 171 | int err=0; | |
| 172 | int tmp; | |
| 60 | 173 | #ifdef NP_SIMPLE_IMPL |
| 62 | 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; | |
| 60 | 225 | |
| 226 | #ifdef NP_SIMPLE_IMPL | |
| 62 | 227 | if(dm==3){ |
| 228 | num->fval+=(double)c/divisor; | |
| 229 | divisor*=base; | |
| 230 | }else | |
| 60 | 231 | #endif |
| 62 | 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; | |
| 60 | 252 | #ifdef NP_SIMPLE_IMPL |
| 62 | 253 | num->type=NPNUM_FLOAT; |
| 254 | divisor=base; | |
| 60 | 255 | #endif |
| 62 | 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); | |
| 60 | 269 | #endif |
| 270 | ||
| 62 | 271 | return err; |
| 60 | 272 | } |