Add flonum constant expression

This commit is contained in:
Rui Ueyama 2020-05-01 19:30:17 +09:00
parent e452cf7215
commit ffea4219b1
2 changed files with 55 additions and 0 deletions

49
parse.c
View File

@ -130,6 +130,7 @@ static int64_t eval_rval(Node *node, char **label);
static Node *assign(Token **rest, Token *tok);
static Node *logor(Token **rest, Token *tok);
static int64_t const_expr(Token **rest, Token *tok);
static double eval_double(Node *node);
static Node *conditional(Token **rest, Token *tok);
static Node *logand(Token **rest, Token *tok);
static Node *bitor(Token **rest, Token *tok);
@ -1101,6 +1102,16 @@ write_gvar_data(Relocation *cur, Initializer *init, Type *ty, char *buf, int off
if (!init->expr)
return cur;
if (ty->kind == TY_FLOAT) {
*(float *)(buf + offset) = eval_double(init->expr);
return cur;
}
if (ty->kind == TY_DOUBLE) {
*(double *)(buf + offset) = eval_double(init->expr);
return cur;
}
char *label = NULL;
uint64_t val = eval2(init->expr, &label);
@ -1427,6 +1438,9 @@ static int64_t eval(Node *node) {
static int64_t eval2(Node *node, char **label) {
add_type(node);
if (is_flonum(node->ty))
return eval_double(node);
switch (node->kind) {
case ND_ADD:
return eval2(node->lhs, label) + eval(node->rhs);
@ -1534,6 +1548,41 @@ static int64_t const_expr(Token **rest, Token *tok) {
return eval(node);
}
static double eval_double(Node *node) {
add_type(node);
if (is_integer(node->ty)) {
if (node->ty->is_unsigned)
return (unsigned long)eval(node);
return eval(node);
}
switch (node->kind) {
case ND_ADD:
return eval_double(node->lhs) + eval_double(node->rhs);
case ND_SUB:
return eval_double(node->lhs) - eval_double(node->rhs);
case ND_MUL:
return eval_double(node->lhs) * eval_double(node->rhs);
case ND_DIV:
return eval_double(node->lhs) / eval_double(node->rhs);
case ND_NEG:
return -eval_double(node->lhs);
case ND_COND:
return eval_double(node->cond) ? eval_double(node->then) : eval_double(node->els);
case ND_COMMA:
return eval_double(node->rhs);
case ND_CAST:
if (is_flonum(node->lhs->ty))
return eval_double(node->lhs);
return eval(node->lhs);
case ND_NUM:
return node->fval;
}
error_tok(node->tok, "not a compile-time constant");
}
// Convert `A op= B` to `tmp = &A, *tmp = *tmp op B`
// where tmp is a fresh pointer variable.
static Node *to_assign(Node *binary) {

View File

@ -1,5 +1,8 @@
#include "test.h"
float g40 = 1.5;
double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0);
int main() {
ASSERT(10, ({ enum { ten=1+2+3+4 }; ten; }));
ASSERT(1, ({ int i=0; switch(3) { case 5-2+0*3: i++; } i; }));
@ -44,6 +47,9 @@ int main() {
ASSERT(1, ({ char x[(unsigned)1<-1]; sizeof(x); }));
ASSERT(1, ({ char x[(unsigned)1<=-1]; sizeof(x); }));
ASSERT(1, g40==1.5);
ASSERT(1, g41==11);
printf("OK\n");
return 0;
}