Add floating-point constant

This commit is contained in:
Rui Ueyama 2020-09-27 19:43:03 +09:00
parent 1fad2595d6
commit 1e57f72d8a
6 changed files with 82 additions and 7 deletions

View File

@ -44,6 +44,7 @@ struct Token {
TokenKind kind; // Token kind
Token *next; // Next token
int64_t val; // If kind is TK_NUM, its value
double fval; // If kind is TK_NUM, its value
char *loc; // Token location
int len; // Token length
Type *ty; // Used if TK_NUM or TK_STR
@ -200,6 +201,7 @@ struct Node {
// Numeric literal
int64_t val;
double fval;
};
Node *new_cast(Node *expr, Type *ty);
@ -216,6 +218,8 @@ typedef enum {
TY_SHORT,
TY_INT,
TY_LONG,
TY_FLOAT,
TY_DOUBLE,
TY_ENUM,
TY_PTR,
TY_FUNC,
@ -282,7 +286,11 @@ extern Type *ty_ushort;
extern Type *ty_uint;
extern Type *ty_ulong;
extern Type *ty_float;
extern Type *ty_double;
bool is_integer(Type *ty);
bool is_flonum(Type *ty);
Type *copy_type(Type *ty);
Type *pointer_to(Type *base);
Type *func_type(Type *return_ty);

View File

@ -187,9 +187,25 @@ static void gen_expr(Node *node) {
switch (node->kind) {
case ND_NULL_EXPR:
return;
case ND_NUM:
case ND_NUM: {
union { float f32; double f64; uint32_t u32; uint64_t u64; } u;
switch (node->ty->kind) {
case TY_FLOAT:
u.f32 = node->fval;
println(" mov $%u, %%eax # float %f", u.u32, node->fval);
println(" movq %%rax, %%xmm0");
return;
case TY_DOUBLE:
u.f64 = node->fval;
println(" mov $%lu, %%rax # double %f", u.u64, node->fval);
println(" movq %%rax, %%xmm0");
return;
}
println(" mov $%ld, %%rax", node->val);
return;
}
case ND_NEG:
gen_expr(node->lhs);
println(" neg %%rax");

View File

@ -2236,7 +2236,14 @@ static Node *primary(Token **rest, Token *tok) {
}
if (tok->kind == TK_NUM) {
Node *node = new_num(tok->val, tok);
Node *node;
if (is_flonum(tok->ty)) {
node = new_node(ND_NUM, tok);
node->fval = tok->fval;
} else {
node = new_num(tok->val, tok);
}
node->ty = tok->ty;
*rest = tok->next;
return node;

View File

@ -78,6 +78,19 @@ int main() {
ASSERT(-1, 0x1 << 31 >> 31);
ASSERT(-1, 0b1 << 31 >> 31);
0.0;
1.0;
3e+8;
0x10.1p0;
.1E4f;
ASSERT(4, sizeof(8f));
ASSERT(4, sizeof(0.3F));
ASSERT(8, sizeof(0.));
ASSERT(8, sizeof(.0));
ASSERT(8, sizeof(5.l));
ASSERT(8, sizeof(2.0L));
printf("OK\n");
return 0;
}

View File

@ -289,9 +289,6 @@ static Token *read_int_literal(char *start) {
u = true;
}
if (isalnum(*p))
error_at(p, "invalid digit");
// Infer a type.
Type *ty;
if (base == 10) {
@ -326,6 +323,33 @@ static Token *read_int_literal(char *start) {
return tok;
}
static Token *read_number(char *start) {
// Try to parse as an integer constant.
Token *tok = read_int_literal(start);
if (!strchr(".eEfF", start[tok->len]))
return tok;
// If it's not an integer, it must be a floating point constant.
char *end;
double val = strtod(start, &end);
Type *ty;
if (*end == 'f' || *end == 'F') {
ty = ty_float;
end++;
} else if (*end == 'l' || *end == 'L') {
ty = ty_double;
end++;
} else {
ty = ty_double;
}
tok = new_token(TK_NUM, start, end);
tok->fval = val;
tok->ty = ty;
return tok;
}
static void convert_keywords(Token *tok) {
for (Token *t = tok; t->kind != TK_EOF; t = t->next)
if (is_keyword(t))
@ -379,8 +403,8 @@ static Token *tokenize(char *filename, char *p) {
}
// Numeric literal
if (isdigit(*p)) {
cur = cur->next = read_int_literal(p);
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
cur = cur->next = read_number(p);
p += cur->len;
continue;
}

7
type.c
View File

@ -13,6 +13,9 @@ 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};
Type *ty_float = &(Type){TY_FLOAT, 4, 4};
Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
static Type *new_type(TypeKind kind, int size, int align) {
Type *ty = calloc(1, sizeof(Type));
ty->kind = kind;
@ -27,6 +30,10 @@ bool is_integer(Type *ty) {
k == TY_INT || k == TY_LONG || k == TY_ENUM;
}
bool is_flonum(Type *ty) {
return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE;
}
Type *copy_type(Type *ty) {
Type *ret = calloc(1, sizeof(Type));
*ret = *ty;