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