evalexpr/src/eval/eval.c

72 lines
1.4 KiB
C

#include "eval.h"
#define UNREACHABLE() __builtin_unreachable()
static int my_pow(int lhs, int rhs)
{
if (!rhs)
return 1;
int rec = my_pow(lhs * lhs, rhs / 2);
if (rhs & 1)
rec *= lhs;
return rec;
}
static int my_fact(int num)
{
int ret = 1;
while (num > 1)
ret *= num--;
return ret;
}
static int eval_unop(const struct unop_node *un_op)
{
switch (un_op->op)
{
case UNOP_IDENTITY:
return eval_ast(un_op->tree);
case UNOP_NEGATE:
return -eval_ast(un_op->tree);
case UNOP_FACT:
return my_fact(eval_ast(un_op->tree));
default:
UNREACHABLE();
}
}
static int eval_binop(const struct binop_node *bin_op)
{
#define EVAL_OP(OP, TREE) (eval_ast((TREE)->lhs) OP eval_ast((TREE)->rhs))
switch (bin_op->op)
{
case BINOP_PLUS:
return EVAL_OP(+, bin_op);
case BINOP_MINUS:
return EVAL_OP(-, bin_op);
case BINOP_TIMES:
return EVAL_OP(*, bin_op);
case BINOP_DIVIDES:
return EVAL_OP(/, bin_op);
case BINOP_POW:
return my_pow(eval_ast(bin_op->lhs), eval_ast(bin_op->rhs));
default:
UNREACHABLE();
}
#undef EVAL_OP
}
int eval_ast(const struct ast_node *ast)
{
switch (ast->kind)
{
case NODE_NUM:
return ast->val.num;
case NODE_UNOP:
return eval_unop(&ast->val.un_op);
case NODE_BINOP:
return eval_binop(&ast->val.bin_op);
}
UNREACHABLE();
}