mirror of https://github.com/rui314/chibicc
Add unsigned integral types
This commit is contained in:
parent
3f59ce7955
commit
34ab83bdf4
|
@ -227,6 +227,7 @@ struct Type {
|
||||||
TypeKind kind;
|
TypeKind kind;
|
||||||
int size; // sizeof() value
|
int size; // sizeof() value
|
||||||
int align; // alignment
|
int align; // alignment
|
||||||
|
bool is_unsigned; // unsigned or signed
|
||||||
|
|
||||||
// Pointer-to or array-of type. We intentionally use the same member
|
// Pointer-to or array-of type. We intentionally use the same member
|
||||||
// to represent pointer/array duality in C.
|
// to represent pointer/array duality in C.
|
||||||
|
@ -274,6 +275,11 @@ extern Type *ty_short;
|
||||||
extern Type *ty_int;
|
extern Type *ty_int;
|
||||||
extern Type *ty_long;
|
extern Type *ty_long;
|
||||||
|
|
||||||
|
extern Type *ty_uchar;
|
||||||
|
extern Type *ty_ushort;
|
||||||
|
extern Type *ty_uint;
|
||||||
|
extern Type *ty_ulong;
|
||||||
|
|
||||||
bool is_integer(Type *ty);
|
bool is_integer(Type *ty);
|
||||||
Type *copy_type(Type *ty);
|
Type *copy_type(Type *ty);
|
||||||
Type *pointer_to(Type *base);
|
Type *pointer_to(Type *base);
|
||||||
|
|
68
codegen.c
68
codegen.c
|
@ -81,15 +81,17 @@ static void load(Type *ty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *insn = ty->is_unsigned ? "movz" : "movs";
|
||||||
|
|
||||||
// When we load a char or a short value to a register, we always
|
// When we load a char or a short value to a register, we always
|
||||||
// extend them to the size of int, so we can assume the lower half of
|
// extend them to the size of int, so we can assume the lower half of
|
||||||
// a register always contains a valid value. The upper half of a
|
// a register always contains a valid value. The upper half of a
|
||||||
// register for char, short and int may contain garbage. When we load
|
// register for char, short and int may contain garbage. When we load
|
||||||
// a long value to a register, it simply occupies the entire register.
|
// a long value to a register, it simply occupies the entire register.
|
||||||
if (ty->size == 1)
|
if (ty->size == 1)
|
||||||
println(" movsbl (%%rax), %%eax");
|
println(" %sbl (%%rax), %%eax", insn);
|
||||||
else if (ty->size == 2)
|
else if (ty->size == 2)
|
||||||
println(" movswl (%%rax), %%eax");
|
println(" %swl (%%rax), %%eax", insn);
|
||||||
else if (ty->size == 4)
|
else if (ty->size == 4)
|
||||||
println(" movsxd (%%rax), %%rax");
|
println(" movsxd (%%rax), %%rax");
|
||||||
else
|
else
|
||||||
|
@ -125,30 +127,40 @@ static void cmp_zero(Type *ty) {
|
||||||
println(" cmp $0, %%rax");
|
println(" cmp $0, %%rax");
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { I8, I16, I32, I64 };
|
enum { I8, I16, I32, I64, U8, U16, U32, U64 };
|
||||||
|
|
||||||
static int getTypeId(Type *ty) {
|
static int getTypeId(Type *ty) {
|
||||||
switch (ty->kind) {
|
switch (ty->kind) {
|
||||||
case TY_CHAR:
|
case TY_CHAR:
|
||||||
return I8;
|
return ty->is_unsigned ? U8 : I8;
|
||||||
case TY_SHORT:
|
case TY_SHORT:
|
||||||
return I16;
|
return ty->is_unsigned ? U16 : I16;
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
return I32;
|
return ty->is_unsigned ? U32 : I32;
|
||||||
|
case TY_LONG:
|
||||||
|
return ty->is_unsigned ? U64 : I64;
|
||||||
}
|
}
|
||||||
return I64;
|
return U64;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The table for type casts
|
// The table for type casts
|
||||||
static char i32i8[] = "movsbl %al, %eax";
|
static char i32i8[] = "movsbl %al, %eax";
|
||||||
|
static char i32u8[] = "movzbl %al, %eax";
|
||||||
static char i32i16[] = "movswl %ax, %eax";
|
static char i32i16[] = "movswl %ax, %eax";
|
||||||
|
static char i32u16[] = "movzwl %ax, %eax";
|
||||||
static char i32i64[] = "movsxd %eax, %rax";
|
static char i32i64[] = "movsxd %eax, %rax";
|
||||||
|
static char u32i64[] = "mov %eax, %eax";
|
||||||
|
|
||||||
static char *cast_table[][10] = {
|
static char *cast_table[][10] = {
|
||||||
{NULL, NULL, NULL, i32i64}, // i8
|
// i8 i16 i32 i64 u8 u16 u32 u64
|
||||||
{i32i8, NULL, NULL, i32i64}, // i16
|
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i8
|
||||||
{i32i8, i32i16, NULL, i32i64}, // i32
|
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i16
|
||||||
{i32i8, i32i16, NULL, NULL}, // i64
|
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i32
|
||||||
|
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL}, // i64
|
||||||
|
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64}, // u8
|
||||||
|
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64}, // u16
|
||||||
|
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64}, // u32
|
||||||
|
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL}, // u64
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cast(Type *from, Type *to) {
|
static void cast(Type *from, Type *to) {
|
||||||
|
@ -300,9 +312,15 @@ static void gen_expr(Node *node) {
|
||||||
println(" movzx %%al, %%eax");
|
println(" movzx %%al, %%eax");
|
||||||
return;
|
return;
|
||||||
case TY_CHAR:
|
case TY_CHAR:
|
||||||
|
if (node->ty->is_unsigned)
|
||||||
|
println(" movzbl %%al, %%eax");
|
||||||
|
else
|
||||||
println(" movsbl %%al, %%eax");
|
println(" movsbl %%al, %%eax");
|
||||||
return;
|
return;
|
||||||
case TY_SHORT:
|
case TY_SHORT:
|
||||||
|
if (node->ty->is_unsigned)
|
||||||
|
println(" movzwl %%ax, %%eax");
|
||||||
|
else
|
||||||
println(" movswl %%ax, %%eax");
|
println(" movswl %%ax, %%eax");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -315,14 +333,16 @@ static void gen_expr(Node *node) {
|
||||||
gen_expr(node->lhs);
|
gen_expr(node->lhs);
|
||||||
pop("%rdi");
|
pop("%rdi");
|
||||||
|
|
||||||
char *ax, *di;
|
char *ax, *di, *dx;
|
||||||
|
|
||||||
if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) {
|
if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) {
|
||||||
ax = "%rax";
|
ax = "%rax";
|
||||||
di = "%rdi";
|
di = "%rdi";
|
||||||
|
dx = "%rdx";
|
||||||
} else {
|
} else {
|
||||||
ax = "%eax";
|
ax = "%eax";
|
||||||
di = "%edi";
|
di = "%edi";
|
||||||
|
dx = "%edx";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
|
@ -337,11 +357,16 @@ static void gen_expr(Node *node) {
|
||||||
return;
|
return;
|
||||||
case ND_DIV:
|
case ND_DIV:
|
||||||
case ND_MOD:
|
case ND_MOD:
|
||||||
|
if (node->ty->is_unsigned) {
|
||||||
|
println(" mov $0, %s", dx);
|
||||||
|
println(" div %s", di);
|
||||||
|
} else {
|
||||||
if (node->lhs->ty->size == 8)
|
if (node->lhs->ty->size == 8)
|
||||||
println(" cqo");
|
println(" cqo");
|
||||||
else
|
else
|
||||||
println(" cdq");
|
println(" cdq");
|
||||||
println(" idiv %s", di);
|
println(" idiv %s", di);
|
||||||
|
}
|
||||||
|
|
||||||
if (node->kind == ND_MOD)
|
if (node->kind == ND_MOD)
|
||||||
println(" mov %%rdx, %%rax");
|
println(" mov %%rdx, %%rax");
|
||||||
|
@ -361,14 +386,21 @@ static void gen_expr(Node *node) {
|
||||||
case ND_LE:
|
case ND_LE:
|
||||||
println(" cmp %s, %s", di, ax);
|
println(" cmp %s, %s", di, ax);
|
||||||
|
|
||||||
if (node->kind == ND_EQ)
|
if (node->kind == ND_EQ) {
|
||||||
println(" sete %%al");
|
println(" sete %%al");
|
||||||
else if (node->kind == ND_NE)
|
} else if (node->kind == ND_NE) {
|
||||||
println(" setne %%al");
|
println(" setne %%al");
|
||||||
else if (node->kind == ND_LT)
|
} else if (node->kind == ND_LT) {
|
||||||
|
if (node->lhs->ty->is_unsigned)
|
||||||
|
println(" setb %%al");
|
||||||
|
else
|
||||||
println(" setl %%al");
|
println(" setl %%al");
|
||||||
else if (node->kind == ND_LE)
|
} else if (node->kind == ND_LE) {
|
||||||
|
if (node->lhs->ty->is_unsigned)
|
||||||
|
println(" setbe %%al");
|
||||||
|
else
|
||||||
println(" setle %%al");
|
println(" setle %%al");
|
||||||
|
}
|
||||||
|
|
||||||
println(" movzb %%al, %%rax");
|
println(" movzb %%al, %%rax");
|
||||||
return;
|
return;
|
||||||
|
@ -378,8 +410,8 @@ static void gen_expr(Node *node) {
|
||||||
return;
|
return;
|
||||||
case ND_SHR:
|
case ND_SHR:
|
||||||
println(" mov %%rdi, %%rcx");
|
println(" mov %%rdi, %%rcx");
|
||||||
if (node->ty->size == 8)
|
if (node->lhs->ty->is_unsigned)
|
||||||
println(" sar %%cl, %s", ax);
|
println(" shr %%cl, %s", ax);
|
||||||
else
|
else
|
||||||
println(" sar %%cl, %s", ax);
|
println(" sar %%cl, %s", ax);
|
||||||
return;
|
return;
|
||||||
|
|
24
parse.c
24
parse.c
|
@ -344,7 +344,7 @@ static void push_tag_scope(Token *tok, Type *ty) {
|
||||||
|
|
||||||
// declspec = ("void" | "_Bool" | "char" | "short" | "int" | "long"
|
// declspec = ("void" | "_Bool" | "char" | "short" | "int" | "long"
|
||||||
// | "typedef" | "static" | "extern"
|
// | "typedef" | "static" | "extern"
|
||||||
// | "signed"
|
// | "signed" | "unsigned"
|
||||||
// | struct-decl | union-decl | typedef-name
|
// | struct-decl | union-decl | typedef-name
|
||||||
// | enum-specifier)+
|
// | enum-specifier)+
|
||||||
//
|
//
|
||||||
|
@ -373,6 +373,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
||||||
LONG = 1 << 10,
|
LONG = 1 << 10,
|
||||||
OTHER = 1 << 12,
|
OTHER = 1 << 12,
|
||||||
SIGNED = 1 << 13,
|
SIGNED = 1 << 13,
|
||||||
|
UNSIGNED = 1 << 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type *ty = ty_int;
|
Type *ty = ty_int;
|
||||||
|
@ -446,6 +447,8 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
||||||
counter += LONG;
|
counter += LONG;
|
||||||
else if (equal(tok, "signed"))
|
else if (equal(tok, "signed"))
|
||||||
counter |= SIGNED;
|
counter |= SIGNED;
|
||||||
|
else if (equal(tok, "unsigned"))
|
||||||
|
counter |= UNSIGNED;
|
||||||
else
|
else
|
||||||
unreachable();
|
unreachable();
|
||||||
|
|
||||||
|
@ -460,17 +463,28 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
||||||
case SIGNED + CHAR:
|
case SIGNED + CHAR:
|
||||||
ty = ty_char;
|
ty = ty_char;
|
||||||
break;
|
break;
|
||||||
|
case UNSIGNED + CHAR:
|
||||||
|
ty = ty_uchar;
|
||||||
|
break;
|
||||||
case SHORT:
|
case SHORT:
|
||||||
case SHORT + INT:
|
case SHORT + INT:
|
||||||
case SIGNED + SHORT:
|
case SIGNED + SHORT:
|
||||||
case SIGNED + SHORT + INT:
|
case SIGNED + SHORT + INT:
|
||||||
ty = ty_short;
|
ty = ty_short;
|
||||||
break;
|
break;
|
||||||
|
case UNSIGNED + SHORT:
|
||||||
|
case UNSIGNED + SHORT + INT:
|
||||||
|
ty = ty_ushort;
|
||||||
|
break;
|
||||||
case INT:
|
case INT:
|
||||||
case SIGNED:
|
case SIGNED:
|
||||||
case SIGNED + INT:
|
case SIGNED + INT:
|
||||||
ty = ty_int;
|
ty = ty_int;
|
||||||
break;
|
break;
|
||||||
|
case UNSIGNED:
|
||||||
|
case UNSIGNED + INT:
|
||||||
|
ty = ty_uint;
|
||||||
|
break;
|
||||||
case LONG:
|
case LONG:
|
||||||
case LONG + INT:
|
case LONG + INT:
|
||||||
case LONG + LONG:
|
case LONG + LONG:
|
||||||
|
@ -481,6 +495,12 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
||||||
case SIGNED + LONG + LONG + INT:
|
case SIGNED + LONG + LONG + INT:
|
||||||
ty = ty_long;
|
ty = ty_long;
|
||||||
break;
|
break;
|
||||||
|
case UNSIGNED + LONG:
|
||||||
|
case UNSIGNED + LONG + INT:
|
||||||
|
case UNSIGNED + LONG + LONG:
|
||||||
|
case UNSIGNED + LONG + LONG + INT:
|
||||||
|
ty = ty_ulong;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error_tok(tok, "invalid type");
|
error_tok(tok, "invalid type");
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1087,7 @@ static void gvar_initializer(Token **rest, Token *tok, Obj *var) {
|
||||||
static bool is_typename(Token *tok) {
|
static bool is_typename(Token *tok) {
|
||||||
static char *kw[] = {
|
static char *kw[] = {
|
||||||
"void", "_Bool", "char", "short", "int", "long", "struct", "union",
|
"void", "_Bool", "char", "short", "int", "long", "struct", "union",
|
||||||
"typedef", "enum", "static", "extern", "_Alignas", "signed",
|
"typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||||
|
|
30
test/cast.c
30
test/cast.c
|
@ -11,6 +11,36 @@ int main() {
|
||||||
|
|
||||||
(void)1;
|
(void)1;
|
||||||
|
|
||||||
|
ASSERT(-1, (char)255);
|
||||||
|
ASSERT(-1, (signed char)255);
|
||||||
|
ASSERT(255, (unsigned char)255);
|
||||||
|
ASSERT(-1, (short)65535);
|
||||||
|
ASSERT(65535, (unsigned short)65535);
|
||||||
|
ASSERT(-1, (int)0xffffffff);
|
||||||
|
ASSERT(0xffffffff, (unsigned)0xffffffff);
|
||||||
|
|
||||||
|
ASSERT(1, -1<1);
|
||||||
|
ASSERT(0, -1<(unsigned)1);
|
||||||
|
ASSERT(254, (char)127+(char)127);
|
||||||
|
ASSERT(65534, (short)32767+(short)32767);
|
||||||
|
ASSERT(-1, -1>>1);
|
||||||
|
ASSERT(-1, (unsigned long)-1);
|
||||||
|
ASSERT(2147483647, ((unsigned)-1)>>1);
|
||||||
|
ASSERT(-50, (-100)/2);
|
||||||
|
ASSERT(2147483598, ((unsigned)-100)/2);
|
||||||
|
ASSERT(9223372036854775758, ((unsigned long)-100)/2);
|
||||||
|
ASSERT(0, ((long)-1)/(unsigned)100);
|
||||||
|
ASSERT(-2, (-100)%7);
|
||||||
|
ASSERT(2, ((unsigned)-100)%7);
|
||||||
|
ASSERT(6, ((unsigned long)-100)%9);
|
||||||
|
|
||||||
|
ASSERT(65535, (int)(unsigned short)65535);
|
||||||
|
ASSERT(65535, ({ unsigned short x = 65535; x; }));
|
||||||
|
ASSERT(65535, ({ unsigned short x = 65535; (int)x; }));
|
||||||
|
|
||||||
|
ASSERT(-1, ({ typedef short T; T x = 65535; (int)x; }));
|
||||||
|
ASSERT(65535, ({ typedef unsigned short T; T x = 65535; (int)x; }));
|
||||||
|
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,12 @@ int true_fn() { return 513; }
|
||||||
int char_fn() { return (2<<8)+3; }
|
int char_fn() { return (2<<8)+3; }
|
||||||
int short_fn() { return (2<<16)+5; }
|
int short_fn() { return (2<<16)+5; }
|
||||||
|
|
||||||
|
int uchar_fn() { return (2<<10)-1-4; }
|
||||||
|
int ushort_fn() { return (2<<20)-1-7; }
|
||||||
|
|
||||||
|
int schar_fn() { return (2<<10)-1-4; }
|
||||||
|
int sshort_fn() { return (2<<20)-1-7; }
|
||||||
|
|
||||||
int add_all(int n, ...) {
|
int add_all(int n, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, n);
|
va_start(ap, n);
|
||||||
|
|
|
@ -70,6 +70,12 @@ _Bool false_fn();
|
||||||
char char_fn();
|
char char_fn();
|
||||||
short short_fn();
|
short short_fn();
|
||||||
|
|
||||||
|
unsigned char uchar_fn();
|
||||||
|
unsigned short ushort_fn();
|
||||||
|
|
||||||
|
char schar_fn();
|
||||||
|
short sshort_fn();
|
||||||
|
|
||||||
int add_all(int n, ...);
|
int add_all(int n, ...);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -146,6 +152,12 @@ int main() {
|
||||||
|
|
||||||
ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
|
ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); }));
|
||||||
|
|
||||||
|
ASSERT(251, uchar_fn());
|
||||||
|
ASSERT(65528, ushort_fn());
|
||||||
|
ASSERT(-5, schar_fn());
|
||||||
|
ASSERT(-8, sshort_fn());
|
||||||
|
|
||||||
|
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,25 +39,47 @@ int main() {
|
||||||
ASSERT(1, sizeof(char));
|
ASSERT(1, sizeof(char));
|
||||||
ASSERT(1, sizeof(signed char));
|
ASSERT(1, sizeof(signed char));
|
||||||
ASSERT(1, sizeof(signed char signed));
|
ASSERT(1, sizeof(signed char signed));
|
||||||
|
ASSERT(1, sizeof(unsigned char));
|
||||||
|
ASSERT(1, sizeof(unsigned char unsigned));
|
||||||
|
|
||||||
ASSERT(2, sizeof(short));
|
ASSERT(2, sizeof(short));
|
||||||
ASSERT(2, sizeof(int short));
|
ASSERT(2, sizeof(int short));
|
||||||
ASSERT(2, sizeof(short int));
|
ASSERT(2, sizeof(short int));
|
||||||
ASSERT(2, sizeof(signed short));
|
ASSERT(2, sizeof(signed short));
|
||||||
ASSERT(2, sizeof(int short signed));
|
ASSERT(2, sizeof(int short signed));
|
||||||
|
ASSERT(2, sizeof(unsigned short));
|
||||||
|
ASSERT(2, sizeof(int short unsigned));
|
||||||
|
|
||||||
ASSERT(4, sizeof(int));
|
ASSERT(4, sizeof(int));
|
||||||
ASSERT(4, sizeof(signed int));
|
ASSERT(4, sizeof(signed int));
|
||||||
ASSERT(4, sizeof(signed));
|
ASSERT(4, sizeof(signed));
|
||||||
ASSERT(4, sizeof(signed signed));
|
ASSERT(4, sizeof(signed signed));
|
||||||
|
ASSERT(4, sizeof(unsigned int));
|
||||||
|
ASSERT(4, sizeof(unsigned));
|
||||||
|
ASSERT(4, sizeof(unsigned unsigned));
|
||||||
|
|
||||||
ASSERT(8, sizeof(long));
|
ASSERT(8, sizeof(long));
|
||||||
ASSERT(8, sizeof(signed long));
|
ASSERT(8, sizeof(signed long));
|
||||||
ASSERT(8, sizeof(signed long int));
|
ASSERT(8, sizeof(signed long int));
|
||||||
|
ASSERT(8, sizeof(unsigned long));
|
||||||
|
ASSERT(8, sizeof(unsigned long int));
|
||||||
|
|
||||||
ASSERT(8, sizeof(long long));
|
ASSERT(8, sizeof(long long));
|
||||||
ASSERT(8, sizeof(signed long long));
|
ASSERT(8, sizeof(signed long long));
|
||||||
ASSERT(8, sizeof(signed long long int));
|
ASSERT(8, sizeof(signed long long int));
|
||||||
|
ASSERT(8, sizeof(unsigned long long));
|
||||||
|
ASSERT(8, sizeof(unsigned long long int));
|
||||||
|
|
||||||
|
ASSERT(1, sizeof((char)1));
|
||||||
|
ASSERT(2, sizeof((short)1));
|
||||||
|
ASSERT(4, sizeof((int)1));
|
||||||
|
ASSERT(8, sizeof((long)1));
|
||||||
|
|
||||||
|
ASSERT(4, sizeof((char)1 + (char)1));
|
||||||
|
ASSERT(4, sizeof((short)1 + (short)1));
|
||||||
|
ASSERT(4, sizeof(1?2:3));
|
||||||
|
ASSERT(4, sizeof(1?(short)2:(char)3));
|
||||||
|
ASSERT(8, sizeof(1?(long)2:(char)3));
|
||||||
|
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -134,6 +134,7 @@ static bool is_keyword(Token *tok) {
|
||||||
"struct", "union", "short", "long", "void", "typedef", "_Bool",
|
"struct", "union", "short", "long", "void", "typedef", "_Bool",
|
||||||
"enum", "static", "goto", "break", "continue", "switch", "case",
|
"enum", "static", "goto", "break", "continue", "switch", "case",
|
||||||
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
|
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
|
||||||
|
"unsigned",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||||
|
@ -259,7 +260,7 @@ static Token *read_int_literal(char *start) {
|
||||||
base = 8;
|
base = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
long val = strtoul(p, &p, base);
|
int64_t val = strtoul(p, &p, base);
|
||||||
if (isalnum(*p))
|
if (isalnum(*p))
|
||||||
error_at(p, "invalid digit");
|
error_at(p, "invalid digit");
|
||||||
|
|
||||||
|
|
20
type.c
20
type.c
|
@ -8,6 +8,11 @@ Type *ty_short = &(Type){TY_SHORT, 2, 2};
|
||||||
Type *ty_int = &(Type){TY_INT, 4, 4};
|
Type *ty_int = &(Type){TY_INT, 4, 4};
|
||||||
Type *ty_long = &(Type){TY_LONG, 8, 8};
|
Type *ty_long = &(Type){TY_LONG, 8, 8};
|
||||||
|
|
||||||
|
Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
|
||||||
|
Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
|
||||||
|
Type *ty_uint = &(Type){TY_INT, 4, 4, true};
|
||||||
|
Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
|
||||||
|
|
||||||
static Type *new_type(TypeKind kind, int size, int align) {
|
static Type *new_type(TypeKind kind, int size, int align) {
|
||||||
Type *ty = calloc(1, sizeof(Type));
|
Type *ty = calloc(1, sizeof(Type));
|
||||||
ty->kind = kind;
|
ty->kind = kind;
|
||||||
|
@ -59,9 +64,18 @@ Type *struct_type(void) {
|
||||||
static Type *get_common_type(Type *ty1, Type *ty2) {
|
static Type *get_common_type(Type *ty1, Type *ty2) {
|
||||||
if (ty1->base)
|
if (ty1->base)
|
||||||
return pointer_to(ty1->base);
|
return pointer_to(ty1->base);
|
||||||
if (ty1->size == 8 || ty2->size == 8)
|
|
||||||
return ty_long;
|
if (ty1->size < 4)
|
||||||
return ty_int;
|
ty1 = ty_int;
|
||||||
|
if (ty2->size < 4)
|
||||||
|
ty2 = ty_int;
|
||||||
|
|
||||||
|
if (ty1->size != ty2->size)
|
||||||
|
return (ty1->size < ty2->size) ? ty2 : ty1;
|
||||||
|
|
||||||
|
if (ty2->is_unsigned)
|
||||||
|
return ty2;
|
||||||
|
return ty1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For many binary operators, we implicitly promote operands so that
|
// For many binary operators, we implicitly promote operands so that
|
||||||
|
|
Loading…
Reference in New Issue