Browse Source

Implement some bonus marks

master
T. Meissner 6 years ago
parent
commit
64721ec25b
1 changed files with 59 additions and 18 deletions
  1. +59
    -18
      chapter_08/lispy.c

+ 59
- 18
chapter_08/lispy.c View File

@ -34,17 +34,20 @@ void add_history(char* unused) {}
/* Declare new lval struct */ /* Declare new lval struct */
typedef struct { typedef struct {
int type; int type;
long num;
union {
long num;
double dec;
};
int err; int err;
} lval; } lval;
/* Create enumeration of possible lval types */ /* 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 */ /* 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 */ /* 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 */ /* Create a new error type lval */
lval lval_err(int x) { lval lval_err(int x) {
lval v; lval v;
@ -73,6 +85,11 @@ void lval_print(lval v) {
case LVAL_NUM: case LVAL_NUM:
printf("%li", v.num); printf("%li", v.num);
break; 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 */ /* In the case the type is an error */
case LVAL_ERR: case LVAL_ERR:
/* Check what type of error it is & print it */ /* 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 */ /* 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); return lval_err(LERR_BAD_OP);
} }
@ -150,8 +185,14 @@ lval eval(mpc_ast_t* t) {
if (strstr(t->tag, "number")) { if (strstr(t->tag, "number")) {
/* Check if there is some error in conversion */ /* Check if there is some error in conversion */
errno = 0; 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 */ /* The operator is always second child */
@ -182,7 +223,7 @@ int main(int argc, char const *argv[]) {
/* Define them with the following language */ /* Define them with the following language */
mpca_lang(MPCA_LANG_DEFAULT, mpca_lang(MPCA_LANG_DEFAULT,
" \ " \
number : /-?[0-9]+/ ; \
number : /-?[0-9]+([.][0-9]*|[0-9]*)/ ; \
operator : '+' | '-' | '*' | '/' | '%' | '^' | \ operator : '+' | '-' | '*' | '/' | '%' | '^' | \
\"min\" | \"max\" ; \ \"min\" | \"max\" ; \
expr : <number> | '(' <operator> <expr>+ ')' ; \ expr : <number> | '(' <operator> <expr>+ ')' ; \


Loading…
Cancel
Save