Skip to content

Commit 953db19

Browse files
committed
Support unions with designated initializers
Add the necessary casts for storing ints in pointers or vice versa, convert float/double compile time constants into their integer representation. If a 32 bit field is stored via a 64 bit field on big endian, the value should be shifted up. This doesn't handle things that can't be done with casts or as float/double binary representations.
1 parent 1c9972b commit 953db19

File tree

1 file changed

+146
-1
lines changed

1 file changed

+146
-1
lines changed

convert.c

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <clang-c/Index.h>
2222
#include <string.h>
2323
#include <stdlib.h>
24+
#include <inttypes.h>
2425

2526
/*
2627
* The basic idea of the token parser is to "stack" ordered tokens
@@ -1542,6 +1543,103 @@ static enum CXChildVisitResult callback(CXCursor cursor, CXCursor parent,
15421543
return CXChildVisit_Continue;
15431544
}
15441545

1546+
static double eval_expr(CXToken *tokens, unsigned *n, unsigned last);
1547+
1548+
static double eval_prim(CXToken *tokens, unsigned *n, unsigned last) {
1549+
CXString s;
1550+
const char *str;
1551+
if (*n > last) {
1552+
fprintf(stderr, "Unable to parse an expression primary, no more tokens\n");
1553+
exit(1);
1554+
}
1555+
s = clang_getTokenSpelling(TU, tokens[*n]);
1556+
str = clang_getCString(s);
1557+
if (!strcmp(str, "-")) {
1558+
(*n)++;
1559+
clang_disposeString(s);
1560+
return -eval_prim(tokens, n, last);
1561+
} else if (!strcmp(str, "(")) {
1562+
double d;
1563+
(*n)++;
1564+
clang_disposeString(s);
1565+
d = eval_expr(tokens, n, last);
1566+
if (*n >= last) {
1567+
fprintf(stderr, "No right parenthesis found\n");
1568+
exit(1);
1569+
}
1570+
s = clang_getTokenSpelling(TU, tokens[*n]);
1571+
str = clang_getCString(s);
1572+
if (!strcmp(str, ")")) {
1573+
clang_disposeString(s);
1574+
(*n)++;
1575+
} else {
1576+
fprintf(stderr, "No right parenthesis found\n");
1577+
exit(1);
1578+
}
1579+
return d;
1580+
} else {
1581+
char *end;
1582+
double d = strtod(str, &end);
1583+
if (*end != '\0') {
1584+
fprintf(stderr, "Unable to parse %s as expression primary\n", str);
1585+
exit(1);
1586+
}
1587+
(*n)++;
1588+
clang_disposeString(s);
1589+
return d;
1590+
}
1591+
}
1592+
1593+
static double eval_term(CXToken *tokens, unsigned *n, unsigned last) {
1594+
double left = eval_prim(tokens, n, last);
1595+
while (*n <= last) {
1596+
CXString s = clang_getTokenSpelling(TU, tokens[*n]);
1597+
const char *str = clang_getCString(s);
1598+
if (!strcmp(str, "*")) {
1599+
(*n)++;
1600+
left *= eval_prim(tokens, n, last);
1601+
} else if (!strcmp(str, "/")) {
1602+
(*n)++;
1603+
left /= eval_prim(tokens, n, last);
1604+
} else {
1605+
clang_disposeString(s);
1606+
return left;
1607+
}
1608+
clang_disposeString(s);
1609+
}
1610+
return left;
1611+
}
1612+
1613+
static double eval_expr(CXToken *tokens, unsigned *n, unsigned last) {
1614+
double left = eval_term(tokens, n, last);
1615+
while (*n <= last) {
1616+
CXString s = clang_getTokenSpelling(TU, tokens[*n]);
1617+
const char *str = clang_getCString(s);
1618+
if (!strcmp(str, "-")) {
1619+
(*n)++;
1620+
left -= eval_term(tokens, n, last);
1621+
} else if (!strcmp(str, "+")) {
1622+
(*n)++;
1623+
left += eval_term(tokens, n, last);
1624+
} else {
1625+
clang_disposeString(s);
1626+
return left;
1627+
}
1628+
clang_disposeString(s);
1629+
}
1630+
return left;
1631+
}
1632+
1633+
static double eval_tokens(CXToken *tokens, unsigned first, unsigned last) {
1634+
unsigned n = first;
1635+
double d = eval_expr(tokens, &n, last);
1636+
if (n <= last) {
1637+
fprintf(stderr, "Unable to parse tokens as expression\n");
1638+
exit(1);
1639+
}
1640+
return d;
1641+
}
1642+
15451643
static void get_token_position(CXToken token, unsigned *lnum,
15461644
unsigned *pos, unsigned *off)
15471645
{
@@ -1804,6 +1902,10 @@ static void replace_struct_array(unsigned *_saidx, unsigned *_clidx,
18041902
CXToken *tokens, unsigned n_tokens)
18051903
{
18061904
unsigned saidx = *_saidx, off, i, n = *_n, j;
1905+
StructArrayList *sal = &struct_array_lists[saidx];
1906+
StructDeclaration *decl = sal->struct_decl_idx != (unsigned) -1 ?
1907+
&structs[sal->struct_decl_idx] : NULL;
1908+
int is_union = decl ? decl->is_union : 0;
18071909

18081910
// we assume here the indenting for the first opening token,
18091911
// i.e. the '{', is already taken care of
@@ -1817,7 +1919,9 @@ static void replace_struct_array(unsigned *_saidx, unsigned *_clidx,
18171919
unsigned expr_off_s, expr_off_e, val_idx, val_off_s, val_off_e, saidx2,
18181920
indent_token_end, next_indent_token_start, val_token_start,
18191921
val_token_end;
1922+
int print_normal = 1;
18201923
CXString spelling;
1924+
StructMember *member = decl ? &decl->entries[j] : NULL;
18211925

18221926
val_idx = find_value_index(&struct_array_lists[saidx], j);
18231927

@@ -1826,6 +1930,8 @@ static void replace_struct_array(unsigned *_saidx, unsigned *_clidx,
18261930
if (val_idx == (unsigned) -1) {
18271931
unsigned depth = struct_array_lists[saidx].array_depth;
18281932
unsigned idx = struct_array_lists[saidx].struct_decl_idx;
1933+
if (is_union) // Don't print the filler zeros for unions
1934+
continue;
18291935
if (depth > 1) {
18301936
print_literal_text("{ 0 }", lnum, cpos);
18311937
} else if (depth == 1) {
@@ -1861,8 +1967,44 @@ static void replace_struct_array(unsigned *_saidx, unsigned *_clidx,
18611967
// adjust position
18621968
get_token_position(tokens[val_token_start], lnum, cpos, &off);
18631969

1970+
if (is_union && j != 0) {
1971+
StructMember *first_member = &decl->entries[0];
1972+
if ((!strcmp(first_member->type, "double") ||
1973+
!strcmp(first_member->type, "float")) && !first_member->n_ptrs) {
1974+
fprintf(stderr, "Can't convert type %s to %s for union\n",
1975+
member->type, first_member->type);
1976+
exit(1);
1977+
}
1978+
if (first_member->n_ptrs)
1979+
print_literal_text("(void*) ", lnum, cpos);
1980+
if (member->n_ptrs)
1981+
print_literal_text("(intptr_t) ", lnum, cpos);
1982+
1983+
if ((!strcmp(member->type, "double") ||
1984+
!strcmp(member->type, "float")) && !member->n_ptrs) {
1985+
// Convert a literal floating pointer number (not a pointer to
1986+
// one of them) to its binary representation
1987+
union {
1988+
uint64_t i;
1989+
double f;
1990+
} if64;
1991+
char buf[20];
1992+
if64.f = eval_tokens(tokens, val_token_start, val_token_end);
1993+
if (!strcmp(member->type, "float")) {
1994+
union {
1995+
uint32_t i;
1996+
float f;
1997+
} if32;
1998+
if32.f = if64.f;
1999+
if64.i = if32.i;
2000+
}
2001+
snprintf(buf, sizeof(buf), "%#"PRIx64, if64.i);
2002+
print_literal_text(buf, lnum, cpos);
2003+
print_normal = 0;
2004+
}
2005+
}
18642006
// print values out of order
1865-
for (n = val_token_start; n <= val_token_end; n++) {
2007+
for (n = val_token_start; n <= val_token_end && print_normal; n++) {
18662008
print_token_wrapper(tokens, n_tokens, &n, lnum, cpos,
18672009
&saidx2, _clidx, off);
18682010
if (n != val_token_end)
@@ -1885,6 +2027,9 @@ static void replace_struct_array(unsigned *_saidx, unsigned *_clidx,
18852027
struct_array_lists[saidx].value_offset.end);
18862028
}
18872029

2030+
if (is_union) // Unions should be initialized by only one element
2031+
break;
2032+
18882033
for (; n < indent_token_end; n++) {
18892034
print_token(tokens[n], lnum, cpos);
18902035
indent_for_token(tokens[n + 1], lnum, cpos, &off);

0 commit comments

Comments
 (0)