cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

eval.c (6645B)


      1 #include <stdbool.h>
      2 #include <stddef.h>
      3 #include <stdint.h>
      4 #include "util.h"
      5 #include "cc.h"
      6 
      7 #define F (1<<8)
      8 #define S (2<<8)
      9 static void
     10 cast(struct expr *expr)
     11 {
     12 	unsigned size;
     13 
     14 	size = expr->type->size;
     15 	if (expr->type->prop & PROPFLOAT)
     16 		size |= F;
     17 	else if (expr->type->prop & PROPINT && expr->type->basic.issigned)
     18 		size |= S;
     19 	switch (size) {
     20 	case 1:   expr->constant.i = (uint8_t)expr->constant.i;  break;
     21 	case 1|S: expr->constant.i = (int8_t)expr->constant.i;   break;
     22 	case 2:   expr->constant.i = (uint16_t)expr->constant.i; break;
     23 	case 2|S: expr->constant.i = (int16_t)expr->constant.i;  break;
     24 	case 4:   expr->constant.i = (uint32_t)expr->constant.i; break;
     25 	case 4|S: expr->constant.i = (int32_t)expr->constant.i;  break;
     26 	case 4|F: expr->constant.f = (float)expr->constant.f;    break;
     27 	}
     28 }
     29 
     30 static void
     31 binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r)
     32 {
     33 	expr->kind = EXPRCONST;
     34 	if (l->type->prop & PROPFLOAT)
     35 		op |= F;
     36 	else if (l->type->prop & PROPINT && l->type->basic.issigned)
     37 		op |= S;
     38 	switch (op) {
     39 	case TMUL:
     40 	case TMUL|S:    expr->constant.i = l->constant.i * r->constant.i; break;
     41 	case TMUL|F:    expr->constant.f = l->constant.f * r->constant.f; break;
     42 	case TDIV:      expr->constant.i = l->constant.i / r->constant.i; break;
     43 	case TDIV|S:    expr->constant.i = (int64_t)l->constant.i / (int64_t)r->constant.i; break;
     44 	case TDIV|F:    expr->constant.f = l->constant.f / r->constant.f; break;
     45 	case TMOD:      expr->constant.i = l->constant.i % r->constant.i; break;
     46 	case TMOD|S:    expr->constant.i = (int64_t)l->constant.i % (int64_t)r->constant.i; break;
     47 	case TADD:
     48 	case TADD|S:    expr->constant.i = l->constant.i + r->constant.i; break;
     49 	case TADD|F:    expr->constant.f = l->constant.f + r->constant.f; break;
     50 	case TSUB:
     51 	case TSUB|S:    expr->constant.i = l->constant.i - r->constant.i; break;
     52 	case TSUB|F:    expr->constant.f = l->constant.f - r->constant.f; break;
     53 	case TSHL:
     54 	case TSHL|S:    expr->constant.i = l->constant.i << r->constant.i; break;
     55 	case TSHR:      expr->constant.i = l->constant.i >> r->constant.i; break;
     56 	case TSHR|S:    expr->constant.i = (int64_t)l->constant.i >> r->constant.i; break;
     57 	case TBAND:
     58 	case TBAND|S:   expr->constant.i = l->constant.i & r->constant.i; break;
     59 	case TBOR:
     60 	case TBOR|S:    expr->constant.i = l->constant.i | r->constant.i; break;
     61 	case TXOR:
     62 	case TXOR|S:    expr->constant.i = l->constant.i ^ r->constant.i; break;
     63 	case TLESS:     expr->constant.i = l->constant.i < r->constant.i; break;
     64 	case TLESS|S:   expr->constant.i = (int64_t)l->constant.i < (int64_t)r->constant.i; break;
     65 	case TLESS|F:   expr->constant.i = l->constant.f < r->constant.f; break;
     66 	case TGREATER:  expr->constant.i = l->constant.i > r->constant.i; break;
     67 	case TGREATER|S: expr->constant.i = (int64_t)l->constant.i > (int64_t)r->constant.i; break;
     68 	case TGREATER|F: expr->constant.i = l->constant.f > r->constant.f; break;
     69 	case TLEQ:      expr->constant.i = l->constant.i <= r->constant.i; break;
     70 	case TLEQ|S:    expr->constant.i = (int64_t)l->constant.i <= (int64_t)r->constant.i; break;
     71 	case TLEQ|F:    expr->constant.i = l->constant.f <= r->constant.f; break;
     72 	case TGEQ:      expr->constant.i = l->constant.i >= r->constant.i; break;
     73 	case TGEQ|S:    expr->constant.i = (int64_t)l->constant.i >= (int64_t)r->constant.i; break;
     74 	case TGEQ|F:    expr->constant.i = l->constant.f >= r->constant.f; break;
     75 	case TEQL:
     76 	case TEQL|S:    expr->constant.i = l->constant.i == r->constant.i; break;
     77 	case TEQL|F:    expr->constant.i = l->constant.f == r->constant.f; break;
     78 	case TNEQ:
     79 	case TNEQ|S:    expr->constant.i = l->constant.i != r->constant.i; break;
     80 	case TNEQ|F:    expr->constant.i = l->constant.f != r->constant.f; break;
     81 	default:
     82 		fatal("internal error; unknown binary expression");
     83 	}
     84 	cast(expr);
     85 }
     86 #undef F
     87 #undef S
     88 
     89 struct expr *
     90 eval(struct expr *expr, enum evalkind kind)
     91 {
     92 	struct expr *l, *r, *c;
     93 	struct decl *d;
     94 
     95 	switch (expr->kind) {
     96 	case EXPRIDENT:
     97 		if (expr->ident.decl->kind != DECLCONST)
     98 			break;
     99 		expr->kind = EXPRCONST;
    100 		expr->constant.i = intconstvalue(expr->ident.decl->value);
    101 		break;
    102 	case EXPRCOMPOUND:
    103 		if (kind != EVALINIT)
    104 			break;
    105 		d = mkdecl(DECLOBJECT, expr->type, expr->qual, LINKNONE);
    106 		d->value = mkglobal(NULL, true);
    107 		emitdata(d, expr->compound.init);
    108 		expr->kind = EXPRIDENT;
    109 		expr->ident.decl = d;
    110 		break;
    111 	case EXPRUNARY:
    112 		l = eval(expr->base, kind);
    113 		if (expr->op != TBAND)
    114 			break;
    115 		switch (l->kind) {
    116 		case EXPRUNARY:
    117 			if (l->op == TMUL)
    118 				expr = eval(l->base, kind);
    119 			break;
    120 		case EXPRSTRING:
    121 			if (kind != EVALINIT)
    122 				break;
    123 			l->ident.decl = stringdecl(l);
    124 			l->kind = EXPRIDENT;
    125 			expr->base = l;
    126 			break;
    127 		}
    128 		break;
    129 	case EXPRCAST:
    130 		l = eval(expr->base, kind);
    131 		if (l->kind == EXPRCONST) {
    132 			expr->kind = EXPRCONST;
    133 			if (l->type->prop & PROPINT && expr->type->prop & PROPFLOAT)
    134 				expr->constant.f = l->constant.i;
    135 			else if (l->type->prop & PROPFLOAT && expr->type->prop & PROPINT)
    136 				expr->constant.i = l->constant.f;
    137 			else
    138 				expr->constant = l->constant;
    139 			cast(expr);
    140 		} else if (l->type->kind == TYPEPOINTER) {
    141 			/*
    142 			A cast from a pointer to integer is not a valid constant
    143 			expression, but C11 allows implementations to recognize
    144 			other forms of constant expressions (6.6p10), and some
    145 			programs expect this functionality.
    146 			*/
    147 			if (expr->type->kind == TYPEPOINTER || expr->type->prop & PROPINT && expr->type->size == typelong.size)
    148 				expr = l;
    149 		}
    150 		break;
    151 	case EXPRBINARY:
    152 		l = eval(expr->binary.l, kind);
    153 		r = eval(expr->binary.r, kind);
    154 		expr->binary.l = l;
    155 		expr->binary.r = r;
    156 		switch (expr->op) {
    157 		case TADD:
    158 			if (r->kind == EXPRBINARY)
    159 				c = l, l = r, r = c;
    160 			if (r->kind != EXPRCONST)
    161 				break;
    162 			if (l->kind == EXPRCONST) {
    163 				binary(expr, expr->op, l, r);
    164 			} else if (l->kind == EXPRBINARY && l->type->kind == TYPEPOINTER && l->binary.r->kind == EXPRCONST) {
    165 				if (l->op == TADD || l->op == TSUB) {
    166 					/* (P ± C1) + C2  ->  P + (C2 ± C1) */
    167 					expr->binary.l = l->binary.l;
    168 					binary(expr->binary.r, l->op, r, l->binary.r);
    169 				}
    170 			}
    171 			break;
    172 		/* TODO: TSUB pointer handling */
    173 		case TLOR:
    174 			if (l->kind != EXPRCONST)
    175 				break;
    176 			return l->constant.i ? l : r;
    177 		case TLAND:
    178 			if (l->kind != EXPRCONST)
    179 				break;
    180 			return l->constant.i ? r : l;
    181 		default:
    182 			if (l->kind != EXPRCONST || r->kind != EXPRCONST)
    183 				break;
    184 			binary(expr, expr->op, l, r);
    185 		}
    186 		break;
    187 	case EXPRCOND:
    188 		l = expr->cond.t;
    189 		r = expr->cond.f;
    190 		c = eval(expr->base, kind);
    191 		if (c->kind != EXPRCONST)
    192 			break;
    193 		return eval(c->constant.i ? l : r, kind);
    194 	}
    195 
    196 	return expr;
    197 }