|
|
@ -34,17 +34,20 @@ void add_history(char* unused) {} |
|
|
|
/* Declare new lval struct */ |
|
|
|
typedef struct { |
|
|
|
int type; |
|
|
|
long num; |
|
|
|
union { |
|
|
|
long num; |
|
|
|
double dec; |
|
|
|
}; |
|
|
|
int err; |
|
|
|
} lval; |
|
|
|
|
|
|
|
|
|
|
|
/* Create enumeration of possible lval types */ |
|
|
|
enum {LVAL_NUM, LVAL_ERR}; |
|
|
|
enum lval_types {LVAL_NUM, LVAL_DEC, LVAL_ERR}; |
|
|
|
|
|
|
|
|
|
|
|
/* Create enumeration of possible error types */ |
|
|
|
enum {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM}; |
|
|
|
enum lval_errors {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM}; |
|
|
|
|
|
|
|
|
|
|
|
/* Create a new number of type lval */ |
|
|
@ -56,6 +59,15 @@ lval lval_num(long x) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Create a new decimal of type lval */ |
|
|
|
lval lval_dec(double x) { |
|
|
|
lval v; |
|
|
|
v.type = LVAL_DEC; |
|
|
|
v.dec = x; |
|
|
|
return v; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Create a new error type lval */ |
|
|
|
lval lval_err(int x) { |
|
|
|
lval v; |
|
|
@ -73,6 +85,11 @@ void lval_print(lval v) { |
|
|
|
case LVAL_NUM: |
|
|
|
printf("%li", v.num); |
|
|
|
break; |
|
|
|
/* In the case the type is a decimal print it |
|
|
|
Then break out of the switch */ |
|
|
|
case LVAL_DEC: |
|
|
|
printf("%.2f", v.dec); |
|
|
|
break; |
|
|
|
/* In the case the type is an error */ |
|
|
|
case LVAL_ERR: |
|
|
|
/* Check what type of error it is & print it */ |
|
|
@ -127,19 +144,37 @@ lval eval_op(lval x, char* op, lval y) { |
|
|
|
} |
|
|
|
|
|
|
|
/* Otherwise do maths on the number values */ |
|
|
|
|
|
|
|
if (strcmp(op, "+") == 0) {return lval_num(x.num + y.num);} |
|
|
|
if (strcmp(op, "-") == 0) {return lval_num(x.num - y.num);} |
|
|
|
if (strcmp(op, "*") == 0) {return lval_num(x.num * y.num);} |
|
|
|
if (strcmp(op, "/") == 0) { |
|
|
|
/* If second operand is zero return error */ |
|
|
|
return y.num == 0 ? lval_err(LERR_DIV_ZERO) |
|
|
|
: lval_num(x.num / y.num); |
|
|
|
if (x.type == LVAL_NUM && y.type == LVAL_NUM) { |
|
|
|
if (strcmp(op, "+") == 0) {return lval_num(x.num + y.num);} |
|
|
|
if (strcmp(op, "-") == 0) {return lval_num(x.num - y.num);} |
|
|
|
if (strcmp(op, "*") == 0) {return lval_num(x.num * y.num);} |
|
|
|
if (strcmp(op, "/") == 0) { |
|
|
|
/* If second operand is zero return error */ |
|
|
|
return y.num == 0 ? lval_err(LERR_DIV_ZERO) |
|
|
|
: lval_num(x.num / y.num); |
|
|
|
} |
|
|
|
if (strcmp(op, "%") == 0) {return lval_num(x.num % y.num);} |
|
|
|
if (strcmp(op, "^") == 0) {return lval_num(pow(x.num, y.num));} |
|
|
|
if (strcmp(op, "min") == 0) {return lval_num(min(x.num, y.num));} |
|
|
|
if (strcmp(op, "max") == 0) {return lval_num(max(x.num, y.num));} |
|
|
|
} else { |
|
|
|
/* Cast integer number into double if necessary */ |
|
|
|
double a = x.type == LVAL_NUM ? (double) x.num : x.dec; |
|
|
|
double b = y.type == LVAL_NUM ? (double) y.num : y.dec; |
|
|
|
/* Perform all operations on double */ |
|
|
|
if (strcmp(op, "+") == 0) {return lval_dec(a + b);} |
|
|
|
if (strcmp(op, "-") == 0) {return lval_dec(a - b);} |
|
|
|
if (strcmp(op, "*") == 0) {return lval_dec(a * b);} |
|
|
|
if (strcmp(op, "/") == 0) { |
|
|
|
/* If second operand is zero return error */ |
|
|
|
return b == 0 ? lval_err(LERR_DIV_ZERO) |
|
|
|
: lval_dec(a / b); |
|
|
|
} |
|
|
|
if (strcmp(op, "%") == 0) {return lval_dec(fmod(a, b));} |
|
|
|
if (strcmp(op, "^") == 0) {return lval_dec(pow(a, b));} |
|
|
|
if (strcmp(op, "min") == 0) {return lval_dec(fmin(a, b));} |
|
|
|
if (strcmp(op, "max") == 0) {return lval_dec(fmax(a, b));} |
|
|
|
} |
|
|
|
if (strcmp(op, "%") == 0) {return lval_num(x.num % y.num);} |
|
|
|
if (strcmp(op, "^") == 0) {return lval_num(pow(x.num, y.num));} |
|
|
|
if (strcmp(op, "min") == 0) {return lval_num(min(x.num, y.num));} |
|
|
|
if (strcmp(op, "max") == 0) {return lval_num(max(x.num, y.num));} |
|
|
|
|
|
|
|
return lval_err(LERR_BAD_OP); |
|
|
|
} |
|
|
@ -150,8 +185,14 @@ lval eval(mpc_ast_t* t) { |
|
|
|
if (strstr(t->tag, "number")) { |
|
|
|
/* Check if there is some error in conversion */ |
|
|
|
errno = 0; |
|
|
|
long x = strtol(t->contents, NULL, 10); |
|
|
|
return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM); |
|
|
|
/* Check for decimal or integer number */ |
|
|
|
if (strstr(t->contents, ".")) { |
|
|
|
double x = strtof(t->contents, NULL); |
|
|
|
return errno != ERANGE ? lval_dec(x) : lval_err(LERR_BAD_NUM); |
|
|
|
} else { |
|
|
|
long x = strtol(t->contents, NULL, 10); |
|
|
|
return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* The operator is always second child */ |
|
|
@ -182,7 +223,7 @@ int main(int argc, char const *argv[]) { |
|
|
|
/* Define them with the following language */ |
|
|
|
mpca_lang(MPCA_LANG_DEFAULT, |
|
|
|
" \ |
|
|
|
number : /-?[0-9]+/ ; \ |
|
|
|
number : /-?[0-9]+([.][0-9]*|[0-9]*)/ ; \ |
|
|
|
operator : '+' | '-' | '*' | '/' | '%' | '^' | \ |
|
|
|
\"min\" | \"max\" ; \ |
|
|
|
expr : <number> | '(' <operator> <expr>+ ')' ; \ |
|
|
|