Tue, 15 Feb 2005 18:57:52 +0100
Tailorization of trunk
Import of the upstream sources from the repository
http://tao.uab.es/ion/svn/libtu/trunk
as of revision 2
/* * libtu/numparser2.h * * Copyright (c) Tuomo Valkonen 1999-2000. * * This file is distributed under the terms of the "Artistic License". * See the included file LICENSE for details. */ #define MAX_MANTISSA 10 /* should be enough for our needs */ #define ULONG_SIZE (sizeof(ulong)*8) /* * Can handle quite big numbers (depends on MAX_MANTISSA). This is really * a crappy little hack (especially the generic (non-i386asm) mulby10 * algorithm... hopefully it works...) but this'll do for now. */ enum{ NPNUM_INT, NPNUM_FLOAT }; 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(LIBTU_NP_NO_I386_ASM) #define LIBTU_NP_I386_ASM #endif static int npnum_mulbase_add(NPNum *num, long base, long v) { long i, j; ulong overflow; #ifndef LIBTU_NP_I386_ASM ulong val; #endif for(i=num->nmantissa;i>=0;i--){ #ifdef LIBTU_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 LIBTU_NP_I386_ASM /* */ static bool is_end(int c) { return ((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; ADD_EXP(num, exp); return err; } static int parse_number(NPNum *num, Tokenizer *tokz, int c) { int base=10; int dm=1; int err=0; int tmp; if(c=='-' || c=='+'){ if(c=='-') num->negative=TRUE; c=GETCH(); if(!isdigit(c)) err=E_TOKZ_NUMFMT; }else 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=7; }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; npnum_mulbase_add(num, base, c); if(dm==1) dm=2; else if(dm==3) ADD_EXP(num, -1); continue; } if(c=='.'){ if(dm!=2) err=E_TOKZ_NUMFMT; else dm=3; continue; } if(is_end(c)){ UNGETCH(c); break; } err=E_TOKZ_NUMFMT; } num->type=(num->exponent==0 ? NPNUM_INT : NPNUM_FLOAT); return err; }