lval *lval_read_double(mpc_ast_t *t) { errno = 0; double x = strtof(t->contents, NULL); if (errno == ERANGE) { return lval_err("invalid double"); } else { return lval_double(x); } }
lval eval(mpc_ast_t* t) { if (strstr(t->tag, "number")) { errno = 0; if (strstr(t->contents, ".")) { double d = strtod(t->contents, NULL); return errno != ERANGE ? lval_double(d) : lval_err(LERR_BAD_NUM); } else { long x = strtol(t->contents, NULL, 10); return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM); } } char *op = t->children[1]->contents; lval x = eval(t->children[2]); int i = 3; while (strstr(t->children[i]->tag, "expr")) { x = eval_op(x, op, eval(t->children[i])); i++; } return x; }
lval eval_op(lval x, char* op, lval y) { if (x.type == LVAL_ERR) { return x; } if (y.type == LVAL_ERR) { return y; } if (strcmp(op, "+") == 0) { if (x.type == y.type) { if (x.type == LVAL_NUM) { return lval_num(x.l + y.l); } else { return lval_double(x.d + y.d); } } else if (x.type == LVAL_DOUBLE) { return lval_double(x.d + y.l); } else if (y.type == LVAL_DOUBLE) { return lval_double(x.l + y.d); } } if (strcmp(op, "-") == 0) { if (x.type == y.type) { if (x.type == LVAL_NUM) { return lval_num(x.l - y.l); } else { return lval_double(x.d - y.d); } } else if (x.type == LVAL_DOUBLE) { return lval_double(x.d - y.l); } else if (y.type == LVAL_DOUBLE) { return lval_double(x.l - y.d); } } if (strcmp(op, "*") == 0) { if (x.type == y.type) { if (x.type == LVAL_NUM) { return lval_num(x.l * y.l); } else { return lval_double(x.d * y.d); } } else if (x.type == LVAL_DOUBLE) { return lval_double(x.d * y.l); } else if (y.type == LVAL_DOUBLE) { return lval_double(x.l * y.d); } } if (strcmp(op, "/") == 0) { if ((y.type == LVAL_NUM && y.l == 0) || (y.type == LVAL_DOUBLE && y.d == 0)) { return lval_err(LERR_DIV_ZERO); } else { if (x.type == y.type) { if (x.type == LVAL_NUM) { return lval_num(x.l / y.l); } else { return lval_double(x.d / y.d); } } else if (x.type == LVAL_DOUBLE) { return lval_double(x.d / y.l); } else if (y.type == LVAL_DOUBLE) { return lval_double(x.l / y.d); } } } if (strcmp(op, "%") == 0) { if (! (x.type == LVAL_NUM && y.type == LVAL_NUM)) { return lval_err(LERR_BAD_OP); } else { if (y.l == 0) { return lval_err(LERR_DIV_ZERO); } else { return lval_num(x.l % y.l); } } } return lval_err(LERR_BAD_OP); }