Commit c496fb7a authored by Matthias Braun's avatar Matthias Braun
Browse files

some cleanups in preparation for a new tarval_from_str interface

[r27179]
parent 8eee4801
......@@ -45,8 +45,6 @@
#define _digit(a) ((a)+SC_0)
#define _bitisset(digit, pos) (((digit) & SHIFT(pos)) != SC_0)
#define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__, __LINE__)
/* shortcut output for debugging */
# define sc_print_hex(a) sc_print((a), 0, SC_HEX, 0)
# define sc_print_dec(a) sc_print((a), 0, SC_DEC, 1)
......@@ -277,14 +275,6 @@ static const char *binary_table[16] = {
/*****************************************************************************
* private functions
*****************************************************************************/
static void _fail_char(const char *str, size_t len, const char fchar, int pos,
const char *file, int line) {
printf("ERROR:\n");
printf("Unexpected character '%c' in %s:%d\n", fchar, file, line);
while (len-- && *str) printf("%c", *str++); printf("\n");
while (--pos) printf(" "); printf("^\n");
exit(-1);
}
/**
* implements the bitwise NOT operation
......@@ -823,139 +813,85 @@ void sign_extend(void *buffer, ir_mode *mode)
}
}
/* FIXME doesn't check for overflows */
void sc_val_from_str(const char *str, unsigned int len, void *buffer, ir_mode *mode)
/* we assume that '0'-'9', 'a'-'z' and 'A'-'Z' are a range.
* The C-standard does theoretically allow otherwise. */
static inline void check_ascii(void)
{
const char *orig_str = str;
unsigned int orig_len = len;
assert('1'-'0' == 1
&& '2'-'0' == 2
&& '3'-'0' == 3
&& '4'-'0' == 4
&& '5'-'0' == 5
&& '6'-'0' == 6
&& '7'-'0' == 7
&& '8'-'0' == 8
&& '9'-'0' == 9);
assert('b'-'a' == 1
&& 'c'-'a' == 2
&& 'd'-'a' == 3
&& 'e'-'a' == 4
&& 'f'-'a' == 5);
assert('B'-'A' == 1
&& 'C'-'A' == 2
&& 'D'-'A' == 3
&& 'E'-'A' == 4
&& 'F'-'A' == 5);
}
char sign = 0;
char *base, *val;
int sc_val_from_str(char sign, unsigned base, const char *str,
unsigned int len, void *buffer)
{
char *sc_base, *val;
base = alloca(calc_buffer_size);
val = alloca(calc_buffer_size);
assert(sign == -1 || sign == 1);
assert(str != NULL);
assert(len > 0);
check_ascii();
/* verify valid pointers (not null) */
assert(str);
/* a string no characters long is an error */
assert(len);
assert(base > 1 && base <= 16);
sc_base = alloca(calc_buffer_size);
sc_val_from_ulong(base, sc_base);
if (buffer == NULL) buffer = calc_buffer;
val = alloca(calc_buffer_size);
if (buffer == NULL)
buffer = calc_buffer;
CLEAR_BUFFER(buffer);
CLEAR_BUFFER(base);
CLEAR_BUFFER(val);
/* strip leading spaces */
while ((len > 0) && (*str == ' ')) { len--; str++; }
/* if the first two characters are 0x or 0X -> hex
* if the first is a 0 -> oct
* else dec, strip leading -/+ and remember sign
*
* only a + or - sign is no number resulting in an error */
if (len >= 2) {
switch (str[0]) {
case '0':
if (str[1] == 'x' || str[1] == 'X') { /* hex */
str += 2;
len -= 2;
base[1] = SC_1; base[0] = SC_0;
} else { /* oct */
str += 1;
len -= 1;
base[1] = SC_0; base[0] = SC_8;
}
break;
case '+':
str += 1;
len -= 1;
base[1] = SC_0; base[0] = SC_A;
break;
case '-':
str += 1;
len -= 1;
sign = 1;
base[1] = SC_0; base[0] = SC_A;
break;
default: /* dec, else would have begun with 0x or 0 */
base[1] = SC_0; base[0] = SC_A;
}
} else { /* dec, else would have begun with 0x or 0 */
base[1] = SC_0; base[0] = SC_A;
}
/* BEGIN string evaluation, from left to right */
while (len > 0) {
switch (*str) {
case 'f':
case 'e':
case 'd':
case 'c':
case 'b':
case 'a':
if (base[0] > SC_A || base[1] > SC_0) { /* (base > 10) */
val[0] = _digit((*str)-'a'+10);
}
else
fail_char(orig_str, orig_len, *str, str-orig_str+1);
break;
case 'F':
case 'E':
case 'D':
case 'C':
case 'B':
case 'A':
if (base[0] > SC_A || base[1] > SC_0) { /* (base > 10) */
val[0] = _digit((*str)-'A'+10);
}
else
fail_char(orig_str, orig_len, *str, str-orig_str+1);
break;
case '9':
case '8':
if (base[0] > SC_8 || base[1] > SC_0) { /* (base > 8) */
val[0] = _digit((*str)-'0');
}
else
fail_char(orig_str, orig_len, *str, str-orig_str+1);
break;
case '7':
case '6':
case '5':
case '4':
case '3':
case '2':
case '1':
case '0':
val[0] = _digit((*str)-'0');
break;
char c = *str;
unsigned v;
if (c >= '0' && c <= '9')
v = c - '0';
else if (c >= 'A' && c <= 'Z')
v = c - 'A';
else if (c >= 'a' && c <= 'z')
v = c - 'z';
else
return 0;
default:
fail_char(orig_str, orig_len, *str, str-orig_str+1);
} /* switch (*str) */
if (v >= base)
return 0;
val[0] = v;
/* Radix conversion from base b to base B:
* (UnUn-1...U1U0)b == ((((Un*b + Un-1)*b + ...)*b + U1)*b + U0)B */
do_mul(base, calc_buffer, calc_buffer); /* multiply current value with base */
do_add(val, calc_buffer, calc_buffer); /* add next digit to current value */
/* multiply current value with base */
do_mul(sc_base, buffer, buffer);
/* add next digit to current value */
do_add(val, buffer, buffer);
/* get ready for the next letter */
str++;
len--;
} /* while (len > 0 ) */
if (sign)
do_negate(calc_buffer, calc_buffer);
if (sign < 0)
do_negate(buffer, buffer);
/* beware: even if hex numbers have no sign, we need sign extension here */
sign_extend(calc_buffer, mode);
return 1;
}
void sc_val_from_long(long value, void *buffer)
......
......@@ -191,8 +191,12 @@ int sc_get_buffer_length(void);
void sign_extend(void *buffer, ir_mode *mode);
/** create an value form a string representation */
void sc_val_from_str(const char *str, unsigned int len, void *buffer, ir_mode *mode);
/**
* create an value form a string representation
* @return 1 if ok, 0 in case of parse error
*/
int sc_val_from_str(char sign, unsigned base, const char *str,
unsigned int len, void *buffer);
/** create a value from a long */
void sc_val_from_long(long l, void *buffer);
......
......@@ -325,6 +325,58 @@ static const ieee_descriptor_t *get_descriptor(const ir_mode *mode)
* public functions declared in tv.h
*/
static tarval *new_tarval_from_str_int(const char *str, size_t len,
ir_mode *mode)
{
void *buffer;
unsigned base = 10;
char sign = 1;
int ok;
/* skip leading spaces */
while (len > 0 && str[0] == ' ') {
++str;
--len;
}
if (len == 0)
return tarval_bad;
/* 1 sign character allowed */
if (str[0] == '-') {
sign = -1;
++str;
--len;
} else if (str[0] == '+') {
++str;
--len;
}
/* a number starting with '0x' is hexadeciaml,
* a number starting with '0' (and at least 1 more char) is octal */
if (len >= 2 && str[0] == '0') {
if (str[1] == 'x' || str[1] == 'X') {
str += 2;
len -= 2;
base = 16;
} else {
++str;
--len;
base = 8;
}
}
if (len == 0)
return tarval_bad;
buffer = alloca(sc_get_buffer_length());
ok = sc_val_from_str(sign, base, str, len, buffer);
if (!ok)
return tarval_bad;
sign_extend(buffer, mode);
return get_tarval_overflow(buffer, sc_get_buffer_length(), mode);
}
/*
* Constructors =============================================================
*/
......@@ -362,8 +414,7 @@ tarval *new_tarval_from_str(const char *str, size_t len, ir_mode *mode)
return get_tarval_null(mode);
/* FALLTHROUGH */
case irms_int_number:
sc_val_from_str(str, len, NULL, mode);
return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode);
return new_tarval_from_str_int(str, len, mode);
}
panic("Unsupported tarval creation with mode %F", mode);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment