Thread: Manually reading an integer literal

  1. #1
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733

    Manually reading an integer literal

    So far this is the test file I have (no other code needed to compile with cc (I presume my system is redirecting to gcc there), aside from obvious lack of backward compatibility with C89 and some left over stuff from when I started by testing on a hardcoded string does anyone see any particular issues in this or even think it's missing something or other? BTW I plan on implementing the LL stuff next, thinking of just croping it with a cast after the value is filled in for the sizing but for the unsigned part I will probably make a seperate similar function to mimic the behavior of pre-processors in that they treat it as signed unless explicitly given notice to treat as unsigned
    Code:
    #include <errno.h>
    #include <ctype.h>
    #include <inttypes.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    typedef signed char schar;
    typedef unsigned char uchar;
    
    typedef int (*int_c_void_t)();
    typedef int (*int_c_pvoid_t)( void *src );
    
    #define BASE_NUM "0123456789"
    #define BASE_a2z "abcdefghijklmnopqrstuvqxyz"
    #define BASE_A2Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    char upper_base62_text[] = BASE_NUM BASE_A2Z BASE_a2z;
    char lower_base62_text[] = BASE_NUM BASE_a2z BASE_A2Z;
    int rdU64_base62( int_c_pvoid_t getchr, void *source, int c,
    	uint base, _Bool lowercase1st, uint_least64_t *num ) {
    	uint i = 0;
    	uint_least64_t n = 0;
    	int rdU64_high() {
    		char *base_text =
    			lowercase1st ? lower_base62_text : upper_base62_text;
    		for ( i = 0; i < base && c != base_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base;
    			n += i;
    			for ( i = 0; i < base && c != base_text[i]; ++i );
    		}
    		if ( num ) *num = n + ((i < base) ? i : 0);
    		return c;
    	}
    	int rdU64_both() {
    		for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base;
    			n += i;
    			for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		}
    		if ( num ) *num = n + ((i < base) ? i : 0);
    		return c;
    	}
    	return (base < 2) ? -1 :
    		((base < 37) ? rdU64_both() : ((base < 63) ? rdU64_high() : -1));
    }
    int rdNum( int_c_pvoid_t getchr, void *source, int c, uint_least64_t *num ) {
    	int rdUint() {
    		c = getchr(source);
    		return (c == 'x' || c == 'X') ?
    			rdU64_base62( getchr, source, getchr(source), 16, 0, num ) :
    			((c == 'b' || c == 'B') ?
    			rdU64_base62( getchr, source, getchr(source), 2, 0, num ) :
    			rdU64_base62( getchr, source, c, 8, 0, num ));
    	}
    	int rdVal() {
    		return (c == '0') ? rdUint() :
    			rdU64_base62( getchr, source, c, 10, 0, num );
    	}
    	int rdInt() {
    		int p = c;
    		c = getchr(source);
    		c = rdVal();
    		if ( num ) *num = ( p == '-' ) ? -(*num) : *num;
    		return c;
    	}
    	return (c == '-' || c == '+') ? rdInt() : rdVal();
    }
    
    typedef struct str {
    	size_t pos;
    	size_t cap;
    	size_t len;
    	char * txt;
    } str_t;
    int rdstr( str_t *str ) {
    	return (str->pos < str->len) ? str->txt[str->pos++] : 0;
    }
    
    int main() {
    	uint_least64_t val123 = 0;
    	uint i = 0;
    	for ( ; i < 5; ++i ) {
    		(void)puts("Please enter a number");
    		rdNum(
    			(int_c_pvoid_t)getc, (void*)stdin, getc(stdin), &val123 );
    		(void)printf("Number entered: %" PRIuLEAST64 "\n", val123);
    	}
    	return 0;
    }
    The results of my last test:
    Code:
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$ make expr
    cc  -D OUT=main.elf -o expr.elf expr.c
    ./expr.elf
    Please enter a number
    +500
    Number entered: 500
    Please enter a number
    600
    Number entered: 600
    Please enter a number
    0456
    Number entered: 302
    Please enter a number
    0x456
    Number entered: 1110
    Please enter a number
    0b100
    Number entered: 4
    rm expr.elf
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$

  2. #2
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    My first impression is that it seems quite complicated for what it does, but letting that slide for a moment I have some comments/suggestions/questions.

    a) Why haven't you got compiler warnings enabled?
    b) Is there a reason that you've typedef'd the function pointers? This is probably a question about style and maybe a personal view but IMO they make the code harder to read
    c) Standard C doesn't allow you to have nested functions
    d) There's barely any error checking. Line 31, for example. (there are other issues I have with this area of the code as well, but the lack of error checking is probably the main one... you've checked the result of line 26, barely, so why not check the result of line 31?) I think lines 26-33 can be rewritten to be a bit clearer

    I guess that's enough to start with

    Edit: I think the "check" for line 26 (on line 27) isn't correct actually. If the character isn't found then you set i to 0 so that the subsequent loop can be entered and just continue on as if nothing went wrong?
    Last edited by Hodor; 09-02-2019 at 06:02 PM.

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Code:
    Please enter a number
    -0xff
    Number entered: 18446744073709551361
    Please enter a number
    -0x7fffffffffffffff
    Number entered: 9223372036854775809
    Neither of these seem right...

    Edit:
    Just wrote a quick and dirty program of my own and I get:
    Code:
    Please enter a number
    -0xff
    Number entered: -255
    Please enter a number
    -0x7fffffffffffffff
    Number entered: -9223372036854775807
    Please enter a number
    Last edited by Hodor; 09-02-2019 at 11:17 PM.

  4. #4
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    Code:
    Please enter a number
    -0xff
    Number entered: 18446744073709551361
    Please enter a number
    -0x7fffffffffffffff
    Number entered: 9223372036854775809
    Neither of these seem right...

    Edit:
    Just wrote a quick and dirty program of my own and I get:
    Code:
    Please enter a number
    -0xff
    Number entered: -255
    Please enter a number
    -0x7fffffffffffffff
    Number entered: -9223372036854775807
    Please enter a number
    I'll reply to this one 1st, I did know about that but that'll be next on my agenda after successfully supporting the accepted standards for string literals (plus a few new ones that I doubt anyone will argue with as they're based on printf identifiers, you'll see in an upcoming post - I just realized I forgot the 'u' && 'U' identifiers when doing them)

  5. #5
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    My first impression is that it seems quite complicated for what it does, but letting that slide for a moment I have some comments/suggestions/questions.
    I you refer back to a previous thread of mine 'Interesting speed test' you'll notice I'm trying to squeeze out those cycles, this is gonna be part of a compiler I'm making myself (in particular I want to be able to do something specific that current compilers are just not built to support) and since it could be doing hundredsto thousands of this call every cycle counts (relax I will do a simpler one also to check the speed of each since a the simple test on previous thread doesn't check based on complex code)

    Quote Originally Posted by Hodor View Post
    a) Why haven't you got compiler warnings enabled?
    That's just a whoopsee on my part, I've now added a '-Wall' switch to my compiling so I'll soon see what you saw
    Quote Originally Posted by Hodor View Post
    b) Is there a reason that you've typedef'd the function pointers? This is probably a question about style and maybe a personal view but IMO they make the code harder to read
    That was for flexibility in what it is used for, as you may have noted above my main function there is ther left overs from the first set of tests I did which used a hard coded string, to that end I had to produce a handler in the same int(*) format that getc/fgetc use in order to pass it the same way and minimise my code (ties in to a feature I want to support directly)
    Quote Originally Posted by Hodor View Post
    c) Standard C doesn't allow you to have nested functions
    Well given that this is for a compiler I'm making (which if I manage to complete the way I want will quickly dwarf vc, gcc & clang by extension)
    Quote Originally Posted by Hodor View Post
    d) There's barely any error checking. Line 31, for example. (there are other issues I have with this area of the code as well, but the lack of error checking is probably the main one... you've checked the result of line 26, barely, so why not check the result of line 31?) I think lines 26-33 can be rewritten to be a bit clearer
    It is checked, note the
    Code:
    while ( i < base
    above it

    Quote Originally Posted by Hodor View Post
    Edit: I think the "check" for line 26 (on line 27) isn't correct actually. If the character isn't found then you set i to 0 so that the subsequent loop can be entered and just continue on as if nothing went wrong?
    That is correct, the point of rdU64 is to ONLY read in a number, the identifiers are treated separately, the point of that first check is to see if still at the identifier or on the 1st digit (e.g. started with 'x' in 0x8F), it's basically insurance in case I slipped up somewhere

  6. #6
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Okay just completed my next revision of my code, slightly major changes so I'll post the whole file after the results:
    Code:
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$ make expr
    cc -Wall  -D OUT=main.elf -o expr.elf expr.c
    ./expr.elf
    Please enter a number
    -255
    Number entered: -255
    Please enter a number
    -0xff
    Number entered: -255
    Please enter a number
    +26
    Number entered: 26
    Please enter a number
    0xffffffffuh
    Number entered: 65535
    Please enter a number
    0xffffffffuhh       
    Number entered: 255
    rm expr.elf
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$
    Code:
    Code:
    #include <errno.h>
    #include <ctype.h>
    #include <inttypes.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    typedef signed char schar;
    typedef unsigned char uchar;
    typedef signed long long sllong;
    typedef unsigned long long ullong;
    
    typedef int (*int_c_void_t)();
    typedef int (*int_c_pvoid_t)( void *src );
    
    #define BASE_NUM "0123456789"
    #define BASE_a2z "abcdefghijklmnopqrstuvqxyz"
    #define BASE_A2Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    char upper_base62_text[] = BASE_NUM BASE_A2Z BASE_a2z;
    char lower_base62_text[] = BASE_NUM BASE_a2z BASE_A2Z;
    int rdU64_base62( int_c_pvoid_t getchr, void *source, int c,
    	uint base, _Bool lowercase1st, uint_least64_t *num ) {
    	uint i = 0;
    	uint_least64_t n = 0;
    	int rdU64_high() {
    		char *base_text =
    			lowercase1st ? lower_base62_text : upper_base62_text;
    		for ( i = 0; i < base && c != base_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base;
    			n += i;
    			for ( i = 0; i < base && c != base_text[i]; ++i );
    		}
    		if ( num ) *num = n + ((i < base) ? i : 0);
    		return c;
    	}
    	int rdU64_both() {
    		for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base;
    			n += i;
    			for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		}
    		if ( num ) *num = n + ((i < base) ? i : 0);
    		return c;
    	}
    	return (base < 2) ? -1 :
    		((base < 37) ? rdU64_both() : ((base < 63) ? rdU64_high() : -1));
    }
    typedef struct num_out {
    	uint unSigned : 1;
    	uint isSigned : 1;
    	uint use_base : 8;
    	uint bitcount : 16;
    	uint_least64_t num;
    } num_out_t;
    int rdNum( int_c_pvoid_t getchr, void *source, int c, num_out_t *out ) {
    	num_out_t o = {0};
    	int rdUint() {
    		int cropH() {
    			int p = c;
    			o.num = ((c = getchr(source) == p)) ?
    				(uchar)(o.num) : (ushort)(o.num);
    			return c;
    		}
    		int cropL() {
    			int p = c;
    			o.num = ((c = getchr(source)) == p) ?
    				(ullong)(o.num) : (ulong)(o.num);
    			return c;
    		}
    		int cropI() {
    			uint_least64_t size = 0;
    			c = ((c == 'i' || c == 'I') && isdigit(c = getchr(source))) ?
    				rdU64_base62( getchr, source, c, 10, 0, &size ) : c;
    			o.num = (size == 64) ? (o.num) :
    				((size == 32) ? (uint_least32_t)(o.num) :
    				((size == 16) ? (uint_least16_t)(o.num) :
    				((size == 8) ? (uint_least8_t)(o.num) : (uint)(o.num))));
    			return c;
    		}
    		c = getchr(source);
    		c = (c == 'x' || c == 'X') ?
    			rdU64_base62( getchr, source, getchr(source), 16, 0, &(o.num) ) :
    			((c == 'b' || c == 'B') ?
    			rdU64_base62( getchr, source, getchr(source), 2, 0, &(o.num) ) :
    			rdU64_base62( getchr, source, c, 8, 0, &(o.num) ));
    		if ( c == 'u' || c == 'U' ) {
    			c = getchr(source);
    			o.unSigned = 1;
    		}
    		return (c == 'l' || c == 'L') ? cropL() :
    			((c == 'h' || c == 'H') ? cropH() : cropI());
    	}
    	int rdVal() {
    		return (c == '0') ? rdUint() :
    			rdU64_base62( getchr, source, c, 10, 0, &(o.num) );
    	}
    	int rdInt() {
    		int p = c;
    		o.isSigned = 1;
    		c = getchr(source);
    		c = rdVal();
    		o.num = (p == '-') ? -(o.num) : o.num;
    		return c;
    	}
    	c = (c == '-' || c == '+') ? rdInt() : rdVal();
    	if ( out ) *out = o;
    	return c;
    }
    
    typedef struct str {
    	size_t pos;
    	size_t cap;
    	size_t len;
    	char * txt;
    } str_t;
    int rdstr( str_t *str ) {
    	return (str->pos < str->len) ? str->txt[str->pos++] : 0;
    }
    
    int main() {
    	uint i = 0;
    	int c;
    	num_out_t num_out = {0};
    	for ( ; i < 5; ++i ) {
    		(void)puts("Please enter a number");
    		rdNum(
    			(int_c_pvoid_t)getc, (void*)stdin, (c = getc(stdin)), &num_out );
    		if ( num_out.unSigned )
    			(void)printf("Number entered: %" PRIuLEAST64 "\n", num_out.num);
    		else
    			(void)printf("Number entered: %" PRIdLEAST64 "\n", num_out.num);
    	}
    	return 0;
    }
    Next I plan to read character and string literals, I also plan to add array support so things like this can be done:
    Code:
    #define _2STR(TXT) #TXT
    #define TOSTR(TXT) _2STR(TXT)
    #ifdef __INT_LEAST64_TYPE__
    #define TMP TOSTR(__INT_LEAST_TYPE__)
    #if TMP[0] == 'l'
    #if TMP[5] == 'l'
    #define PRI_L64 'll'
    #else
    #define PRI_L64 'l'
    #endif
    ...

  7. #7
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Just thought of another scenario where the 1st digit needs to be checked, say someone creates a literal like this:
    Code:
    0x 89
    Yes that ought to be treated as an error but I've not reached that point yet, instead I want it to cope at least until I implement a method to throw an error there since the means of detecting it is already there.

  8. #8
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Just noticed I didn't finish my response to the not standard C question, well guess you figured out that I was gonna say it doesn't matter anyway, once I got it all working I will consider bringing it to standard C level, then again maybe nested functions are supported in c11? I dunno I check what's available when I'm in the mood to research that stuff, this is after all a hobby project and should be considered unimportant until I actually complete enough of it that it compiles/reads most of the windows & linux headers without issue (which is one of the features I plan to implement besides total portabilty).

  9. #9
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Tried something out just because I didn't like supporting just i8, i16, i32 & i64 ms style integer literals, I now have support for integer literals of any bit size upto 64 bits, possibly more since it depends on the typedef int_least64_t, look at the results of my test:
    Code:
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$ make expr
    cc -Wall  -D OUT=main.elf -o expr.elf expr.c
    ./expr.elf
    Please enter a number
    0xfffi9
    Number entered: 511
    Please enter a number
    0xfffi11
    Number entered: 2047
    Please enter a number
    0xfffffi12
    Number entered: 4095
    Please enter a number
    0xfffffffffffffffffi17
    Number entered: 131071
    Please enter a number
    0xfffffffffffffffffi62
    Number entered: 4611686018427387903
    rm expr.elf
    lee@lee-pc-linux:/media/lee/ZXUIJI_1TB/github/mc$

  10. #10
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    I'm still unsure why you're "hiding" the function pointers using typedefs... I find that reading

    Code:
    int rdU64_base62( int_c_pvoid_t getchr, void *source, int c,
        uint base, _Bool lowercase1st, uint_least64_t *num ) {
    is harder to read than say:

    Code:
    int rdU64_base62( int getchr(FILE *), void *source, int c,
        uint base, _Bool lowercase1st, uint_least64_t *num ) {
    and I can't understand the benefit of typedef'ing the function pointer because it's hiding information that would seem to be beneficial
    (maybe it's related to the same reason you're casting FILE* to void* ... I don't understand the thinking behind that, in this case, either)

  11. #11
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Also, I like your i suffixes... except if you plan to support base 62, how will you convert something like "iiiIIi8" to decimal (2540174730920)?

  12. #12
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    Also, I like your i suffixes... except if you plan to support base 62, how will you convert something like "iiiIIi8" to decimal (2540174730920)?
    I'll reply to this one first, base62 is something that will be supported a different way if at all, I'm thinking have a function like sizeof() replace it with an integer the compiler can recognize via the preprocessor, anyway I did upto base 62 just because I could, nothing to do with what I planned to actually support.

  13. #13
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    I'm still unsure why you're "hiding" the function pointers using typedefs... I find that reading

    Code:
    int rdU64_base62( int_c_pvoid_t getchr, void *source, int c,
        uint base, _Bool lowercase1st, uint_least64_t *num ) {
    is harder to read than say:

    Code:
    int rdU64_base62( int getchr(FILE *), void *source, int c,
        uint base, _Bool lowercase1st, uint_least64_t *num ) {
    and I can't understand the benefit of typedef'ing the function pointer because it's hiding information that would seem to be beneficial
    (maybe it's related to the same reason you're casting FILE* to void* ... I don't understand the thinking behind that, in this case, either)
    You'll see in my folowing post in a minute, just look for 'void printNum'.

  14. #14
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    I expect this to be my last post about manually reading an integer literal, first I'll start with the output since it shorter:
    Code:
    make expr (in directory: /media/lee/ZXUIJI_1TB/github/mc)
    cc -Wall  -D OUT=main.elf -o expr.elf expr.c
    ./expr.elf
    Random Number Generated: '1804289383'
    rdNum(): 1804289383
    rdNum2(): 1804289383
    Testing sgetc()
    1804289383
    Testing rdNum()
    846930886: rdNum(): 846930886
    1681692777: rdNum(): 1681692777
    1714636915: rdNum(): 1714636915
    Testing rdNum2()
    1957747793, rdNum2(): 1957747793
    424238335, rdNum2(): 424238335
    719885386, rdNum2(): 719885386
    Cycles: rdNum() 18446603486401109081, rdNum2() 96469135899041
    rm expr.elf
    Compilation finished successfully.
    The code
    Code:
    #include <errno.h>
    #include <limits.h>
    #include <ctype.h>
    #include <inttypes.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    typedef signed char schar;
    typedef unsigned char uchar;
    typedef signed long long sllong;
    typedef unsigned long long ullong;
    
    typedef int (*int_c_void_t)();
    typedef int (*int_c_pvoid_t)( void *src );
    
    #define bitsof(T) (sizeof(T) * CHAR_BIT)
    #define BASE_NUM "0123456789"
    #define BASE_a2z "abcdefghijklmnopqrstuvqxyz"
    #define BASE_A2Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    char upper_base62_text[] = BASE_NUM BASE_A2Z BASE_a2z;
    char lower_base62_text[] = BASE_NUM BASE_a2z BASE_A2Z;
    int rdU64_base62( int_c_pvoid_t getchr, void *source, int c,
    	uint base, _Bool lowercase1st, uint_least64_t *num ) {
    	uint i = 0;
    	uint_least64_t n = 0;
    	int rdU64_high() {
    		char *base_text =
    			lowercase1st ? lower_base62_text : upper_base62_text;
    		for ( i = 0; i < base && c != base_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base; n += i;
    			for ( i = 0; i < base && c != base_text[i]; ++i );
    		}
    		if ( num ) *num = ((i < base) ? (n * base) + i : n);
    		return c;
    	}
    	int rdU64_both() {
    		for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		i = (i < base) ? i : 0;
    		while ( i < base && (c = getchr(source)) ) {
    			n *= base;
    			n += i;
    			for ( i = 0; i < base &&
    				c != upper_base62_text[i] &&
    				c != lower_base62_text[i]; ++i );
    		}
    		if ( num ) *num = ((i < base) ? (n * base) + i : n);
    		return c;
    	}
    	return (base < 2) ? -1 :
    		((base < 37) ? rdU64_both() : ((base < 63) ? rdU64_high() : -1));
    }
    typedef struct num_out {
    	uint unSigned : 1;
    	uint isSigned : 1;
    	uint use_base : 8;
    	uint bitcount : 16;
    	uint_least64_t num;
    } num_out_t;
    int rdNum( int_c_pvoid_t getchr, void *source, int c, num_out_t *out ) {
    	num_out_t o = {0};
    	o.use_base = 10;
    	int rdUint() {
    		int cropH() {
    			int p = c;
    			o.num = ((c = getchr(source)) == p) ?
    				(uchar)(o.num) : (ushort)(o.num);
    			o.bitcount = (c == p) ? CHAR_BIT : bitsof(short);
    			return c;
    		}
    		int cropL() {
    			int p = c;
    			o.num = ((c = getchr(source)) == p) ?
    				(ullong)(o.num) : (ulong)(o.num);
    			o.bitcount = (c == p) ? bitsof(sllong) : bitsof(long);
    			return c;
    		}
    		int cropI() {
    			uint_least64_t size = 0;
    			uint_least64_t cropV() {
    				uint_least64_t bit = -1;
    				bit <<= size;
    				o.num &= (~bit);
    				return o.num;
    			}
    			c = ((c == 'i' || c == 'I') && isdigit((c = getchr(source)))) ?
    				rdU64_base62( getchr, source, c, 10, 0, &size ) : c;
    			o.num = (size == 64) ? (o.num) :
    				((size == 32) ? (uint_least32_t)(o.num) :
    				((size == 16) ? (uint_least16_t)(o.num) :
    				((size == 8) ? (uint_least8_t)(o.num) :
    				(size ? cropV() : (uint)(o.num)))));
    			o.bitcount = size ? size : bitsof(int);
    			return c;
    		}
    		c = getchr(source);
    		o.use_base = (c == 'x' || c == 'X') ? 16 :
    			((c == 'b' || c == 'B') ? 2 : 8);
    		c = (o.use_base == 8) ? c : getchr(source);
    		c = rdU64_base62( getchr, source, c, o.use_base, 0, &(o.num) );
    		if ( c == 'u' || c == 'U' ) {
    			c = getchr(source);
    			o.unSigned = 1;
    		}
    		return (c == 'l' || c == 'L') ? cropL() :
    			((c == 'h' || c == 'H') ? cropH() : cropI());
    	}
    	int rdVal() {
    		return (c == '0') ? rdUint() :
    			rdU64_base62( getchr, source, c, 10, 0, &(o.num) );
    	}
    	int rdInt() {
    		int p = c;
    		o.isSigned = 1;
    		c = getchr(source);
    		c = rdVal();
    		o.num = (p == '-') ? -(o.num) : o.num;
    		return c;
    	}
    	c = (c == '-' || c == '+') ? rdInt() : rdVal();
    	if ( out ) *out = o;
    	return c;
    }
    int rdNum2( int_c_pvoid_t getchr, void *source, int c, num_out_t *out ) {
    	num_out_t o = {0};
    	o.use_base = 10;
    	int rdUint() {
    		int cropH() {
    			int p = c;
    			o.num = ((c = getchr(source)) == p) ?
    				(uchar)(o.num) : (ushort)(o.num);
    			o.bitcount = (c == p) ? CHAR_BIT : CHAR_BIT * sizeof(short);
    			return c;
    		}
    		int cropL() {
    			int p = c;
    			o.num = ((c = getchr(source)) == p) ?
    				(ullong)(o.num) : (ulong)(o.num);
    			o.bitcount = (c == p) ? CHAR_BIT * sizeof(sllong) :
    				CHAR_BIT * sizeof(long);
    			return c;
    		}
    		int cropI() {
    			uint_least64_t size = 0;
    			uint_least64_t cropV() {
    				uint_least64_t bit = -1;
    				bit <<= size;
    				o.num &= (~bit);
    				return o.num;
    			}
    			switch (c) {
    			case 'i': case 'I':
    				c = getchr(source);
    				if ( isdigit(c) )
    					c = rdU64_base62( getchr, source, c, 10, 0, &size );
    			}
    			switch ( size ) {
    			case 64: break;
    			case 32: o.num = (uint_least32_t)(o.num); break;
    			case 16: o.num = (uint_least16_t)(o.num); break;
    			case 8: o.num = (uint_least8_t)(o.num); break;
    			case 0: o.num = (uint)(o.num);
    				size = CHAR_BIT * sizeof(int); break;
    			default: o.num = cropV();
    			}
    			o.bitcount = size;
    			return c;
    		}
    		c = getchr(source);
    		switch ( c ) {
    		case 'x': case 'X': o.use_base = 16; break;
    		case 'b': case 'B': o.use_base = 2; break;
    		default: o.use_base = 8;
    		}
    		c = (o.use_base == 8) ? c : getchr(source);
    		c = rdU64_base62( getchr, source, c, o.use_base, 0, &(o.num) );
    		if ( c == 'u' || c == 'U' ) {
    			c = getchr(source);
    			o.unSigned = 1;
    		}
    		switch (c) {
    		case 'h': case 'H': return cropH();
    		case 'l': case 'L': return cropL();
    		}
    		return cropI();
    	}
    	int rdVal() {
    		return (c == '0') ? rdUint() :
    			rdU64_base62( getchr, source, c, 10, 0, &(o.num) );
    	}
    	int rdInt() {
    		int p = c;
    		o.isSigned = 1;
    		c = getchr(source);
    		c = rdVal();
    		o.num = (p == '-') ? -(o.num) : o.num;
    		return c;
    	}
    	c = (c == '-' || c == '+') ? rdInt() : rdVal();
    	if ( out ) *out = o;
    	return c;
    }
    
    typedef struct str {
    	long pos;
    	long cap;
    	long len;
    	char * txt;
    } str_t;
    int sgetc( str_t *str ) {
    	return str ? (((str->pos) >= 0) ?
    		(((str->pos) < (str->len)) ? str->txt[(str->pos)++] : 0) : -ERANGE)
    		: -EADDRNOTAVAIL;
    }
    
    void printNum( str_t str ) {
    	num_out_t num_out = {0};
    	char *rdNumU = "rdNum(): %" PRIuLEAST64 "\n",
    		*rdNumS = "rdNum(): %" PRIdLEAST64 "\n";
    	str.pos = 0;
    	(void)rdNum( (int_c_pvoid_t)sgetc, &str, sgetc(&str), &num_out );
    	(void)printf( num_out.unSigned ? rdNumU : rdNumS, num_out.num );
    }
    void printNum2( str_t str ) {
    	num_out_t num_out = {0};
    	char *rdNumU = "rdNum2(): %" PRIuLEAST64 "\n",
    		*rdNumS = "rdNum2(): %" PRIdLEAST64 "\n";
    	str.pos = 0;
    	(void)rdNum2( (int_c_pvoid_t)sgetc, &str, sgetc(&str), &num_out );
    	(void)printf( num_out.unSigned ? rdNumU : rdNumS, num_out.num );
    }
    
    typedef volatile uint_least64_t counter_t;
    #if defined( __x86_64__ ) || defined( __i386__ )
    counter_t INIT_TSC( void ) {
    	uint32_t a, d;
    	__asm__ __volatile__ (
    #if (defined(__x86_64__) || defined( __SSE2__ )) & defined( SYNC_MEM )
    	"mfence\n\t"
    #endif
    	"xorl %%eax,%%eax\n\t"
    	"cpuid\n\t"
    	"rdtsc" : "=a" (a), "=d" (d) ::
    #ifdef __x86_64__
    		"%rbx", "%rcx"
    #else
    		"%ebx", "%ecx"
    #endif
    	);
    	return a | ((uint64_t)d << 32);
    }
    void KILL_TSC( counter_t *cptr )
    {
    	uint32_t a, d;
    	__asm__ __volatile__ (
    		"cpuid\n\t"
    		"rdtscp" : "=a" (a), "=d" (d) ::
    #ifdef _x86_64__
    		"%rcx"
    #else
    		"%ecx"
    #endif
    	);
    	*cptr = (a | ((uint64_t)d << 32)) - *cptr;;
    }
    #else
    #define INIT_TSC() time(NULL)
    #define KILL_TSC(P) (*(P) = time(NULL))
    #endif
    
    int main() {
    	uint i, max = 3;
    	int c;
    	counter_t cinit, cstop, took1, took2;
    	char text[65] = {0};
    	str_t str = {0};
    	str.txt = text;
    	str.cap = 65;
    	(void)sprintf( text, "%d", rand() );
    	str.len = strlen( text );
    	(void)printf( "Random Number Generated: '%s'\n", text );
    	printNum( str );
    	printNum2( str );
    	puts("Testing sgetc()");
    	str.pos = 0;
    	while ( (c = sgetc(&str)) ) {
    		if ( c > 0 ) fputc( c, stdout );
    		else (void)printf("#%ld", str.pos);
    	}
    	fputc( '\n', stdout );
    	if ( str.pos < str.len ) return 1;
    	puts("Testing rdNum()");
    	cinit = INIT_TSC();
    	for ( i = 0; i < max; ++i ) {
    		(void)sprintf( text, "%d", rand() );
    		str.len = strlen( text );
    		(void)printf( "%s: ", text );
    		printNum( str );
    	}
    	KILL_TSC(&cstop);
    	took1 = cstop - cinit;
    	puts("Testing rdNum2()");
    	cinit = INIT_TSC();
    	for ( i = 0; i < max; ++i ) {
    		(void)sprintf( text, "%d", rand() );
    		str.len = strlen( text );
    		(void)printf( "%s, ", text );
    		printNum2( str );
    	}
    	KILL_TSC(&cstop);
    	took2 = cstop - cinit;
    	printf("Cycles: rdNum() %llu, rdNum2() %llu\n",
    		(ullong)took1, (ullong)took2 );
    	return 0;
    }
    If there's any suggetions on simplifying rdNum2() then please do suggest away, I'm gonna focus on reading character literals next in prep for string literals, also seems like while simple code likes the conditional syntax better for speed, the complex code seems to like if syntax better for speed

  15. #15
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Well, I'm glad it works. To me it looks like a maintenance nightmare, but you obviously understand so everything's cool! (I, on the other hand, can barely read it... to me it's spaghetti code)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. byte array plus integer literal question
    By pauljcx in forum C Programming
    Replies: 2
    Last Post: 08-04-2011, 01:31 PM
  2. Reading integer from string
    By dr_kaufman in forum C Programming
    Replies: 2
    Last Post: 04-30-2011, 09:40 AM
  3. Reading an integer from file
    By 843 in forum C Programming
    Replies: 18
    Last Post: 11-27-2010, 07:43 AM
  4. Reading integer from file.
    By esben in forum C Programming
    Replies: 4
    Last Post: 03-04-2006, 12:39 PM
  5. Appended integer literal to std::string
    By Tonto in forum C++ Programming
    Replies: 7
    Last Post: 07-30-2005, 11:49 AM

Tags for this Thread