--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/np/numparser2.h Mon Feb 16 18:04:44 2004 +0100 @@ -0,0 +1,272 @@ +/* + * libtu/numparser2.h + * + * Copyright (c) Tuomo Valkonen 1999-2002. + * + * You may distribute and modify this library under the terms of either + * the Clarified Artistic License or the GNU LGPL, version 2.1 or later. + */ + +#define MAX_MANTISSA 10 /* should be enough for our needs */ +#define ULONG_SIZE (sizeof(ulong)*8) + +enum{ + NPNUM_INT, + NPNUM_FLOAT +}; + +#ifdef NP_SIMPLE_IMPL + +typedef struct _NPNum{ + int type; + int base; + bool negative; + double fval; + ulong ival; +} NPNum; + +#define NUM_INIT {0, 0, 0, 0.0, 0} + +static int npnum_mulbase_add(NPNum *num, long base, long v) +{ + double iold=num->ival; + + num->fval=num->fval*base+(double)v; + + num->ival*=base; + + if(num->ival<iold) + num->type=NPNUM_FLOAT; + + num->ival+=v; + + return 0; +} + +#else /* NP_SIMPLE_IMPL */ + +typedef struct _NPNum{ + unsigned char nmantissa; + int type; + int base; + bool negative; + ulong mantissa[MAX_MANTISSA]; + long exponent; +} NPNum; + +#define NUM_INIT {0, 0, 0, 0, {0,}, 0} + +#define ADD_EXP(NUM, X) (NUM)->exponent+=(X); + +#if defined(__GNUG__) && defined(i386) && !defined(NP_NO_I386_ASM) + #define NP_I386_ASM +#endif + +static int npnum_mulbase_add(NPNum *num, long base, long v) +{ + long i, j; + ulong overflow; +#ifndef NP_I386_ASM + ulong val; +#endif + + for(i=num->nmantissa;i>=0;i--){ +#ifdef NP_I386_ASM + __asm__("mul %4\n" + : "=a" (num->mantissa[i]), "=d" (overflow) + : "0" (num->mantissa[i]), "1" (0), "q" (base) + : "eax", "edx"); +#else + overflow=0; + val=num->mantissa[i]; + + if(val<ULONG_MAX/base){ + val*=base; + }else if(val){ + ulong tmp=val; + ulong old=val; + for(j=0; j<base; j++){ + val+=tmp; + if(val<=old) + overflow++; + old=val; + } + } + num->mantissa[i]=val; +#endif + if(overflow){ + if(i==num->nmantissa){ + if(num->nmantissa==MAX_MANTISSA) + return E_TOKZ_TOOBIG; + num->nmantissa++; + } + num->mantissa[i+1]+=overflow; + } + } + num->mantissa[0]+=v; + + return 0; +} + +#undef NP_I386_ASM + +#endif /* NP_SIMPLE_IMPL */ + + +/* */ + + +static bool is_end(int c) +{ + /* oops... EOF was missing */ + return (c==EOF || (c!='.' && ispunct(c)) || isspace(c) || iscntrl(c)); +} + + +/* */ + + +static int parse_exponent(NPNum *num, Tokenizer *tokz, int c) +{ + long exp=0; + bool neg=FALSE; + int err=0; + + c=GETCH(); + + if(c=='-' || c=='+'){ + if(c=='-') + neg=TRUE; + c=GETCH(); + } + + for(; 1; c=GETCH()){ + if(isdigit(c)){ + exp*=10; + exp+=c-'0'; + }else if(is_end(c)){ + UNGETCH(c); + break; + }else{ + err=E_TOKZ_NUMFMT; + } + } + + if(neg) + exp*=-1; + +#ifndef NP_SIMPLE_IMPL + ADD_EXP(num, exp); +#else + num->fval*=pow(num->base, exp); +#endif + return err; +} + + +static int parse_number(NPNum *num, Tokenizer *tokz, int c) +{ + int base=10; + int dm=1; + int err=0; + int tmp; +#ifdef NP_SIMPLE_IMPL + double divisor=base; +#endif + + if(c=='-' || c=='+'){ + if(c=='-') + num->negative=TRUE; + c=GETCH(); + if(!isdigit(c)) + err=E_TOKZ_NUMFMT; + } + + if(c=='0'){ + dm=0; + c=GETCH(); + if(c=='x' || c=='X'){ + base=16; + c=GETCH(); + }else if(c=='b' || c=='B'){ + base=2; + c=GETCH(); + }else if('0'<=c && c<='7'){ + base=8; + }else{ + dm=2; + } + } + + num->base=base; + + for(; 1; c=GETCH()){ + if((c=='e' || c=='E') && dm!=0){ + if(dm<2){ + err=E_TOKZ_NUMFMT; + continue; + } + tmp=parse_exponent(num, tokz, c); + if(err==0) + err=tmp; + break; + } + + if(isxdigit(c)){ + if('0'<=c && c<='9') + c-='0'; + else if(isupper(c)) + c-='A'-10; + else + c-='a'-10; + + if(c>=base) + err=E_TOKZ_NUMFMT; + +#ifdef NP_SIMPLE_IMPL + if(dm==3){ + num->fval+=(double)c/divisor; + divisor*=base; + }else +#endif + { + tmp=npnum_mulbase_add(num, base, c); + if(err==0) + err=tmp; + } + + if(dm==1) + dm=2; +#ifndef NP_SIMPLE_IMPL + else if(dm==3) + ADD_EXP(num, -1); +#endif + continue; + } + + if(c=='.'){ + if(dm!=2){ + err=E_TOKZ_NUMFMT; + } + dm=3; +#ifdef NP_SIMPLE_IMPL + num->type=NPNUM_FLOAT; + divisor=base; +#endif + continue; + } + + if(is_end(c)){ + UNGETCH(c); + break; + } + + err=E_TOKZ_NUMFMT; + } + +#ifndef NP_SIMPLE_IMPL + num->type=(num->exponent==0 ? NPNUM_INT : NPNUM_FLOAT); +#endif + + return err; +}