#include #include #include "../mpc/mpc.h" /* If we are on Windows compile these functions */ #ifdef _WIN32 #include #include static char buffer[2048]; /* Fake readline function */ char* readline(char* prompt) { fputs(prompt, stdout); fgets(buffer, 2048, stdin); char* cpy = malloc(strlen(buffer)+1); assert(cpy != NULL) strcpy(cpy, buffer); cpy[strlen(cpy)-1] = '\0'; return cpy; } /* Fake add_history function */ void add_history(char* unused) {} /* Otherwise include the editline headers could use __APPLE__ for detection of OSX */ #else #include #endif /* Declare new lval struct */ typedef struct { int type; union { long num; double dec; int err; }; } lval; /* Create enumeration of possible lval types */ enum lval_types {LVAL_NUM, LVAL_DEC, LVAL_ERR}; /* Create enumeration of possible error types */ enum lval_errors {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM}; /* Create a new number of type lval */ lval lval_num(long x) { lval v; v.type = LVAL_NUM; v.num = x; return v; } /* 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; v.type = LVAL_ERR; v.err = x; return v; } /* Print an lval */ void lval_print(lval v) { switch (v.type) { /* In the case the type is a number print it Then break out of the switch */ 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 */ if (v.err == LERR_DIV_ZERO) { printf("Error: Division by zero!"); } if (v.err == LERR_BAD_OP) { printf("Error: Invalid operator!"); } if (v.err == LERR_BAD_NUM) { printf("Error: Invalid number!"); } break; } } /* Print an lval followed by a newline */ void lval_println(lval v) { lval_print(v); putchar('\n'); } long min(long x, long y) { if (x <= y) { return x; } else { return y; } } long max(long x, long y) { if (x >= y) { return x; } else { return y; } } /* Use operator string to see which operation to perform */ lval eval_op(lval x, char* op, lval y) { /* If either value is an error return it */ if (x.type == LVAL_ERR) { return x; } if (y.type == LVAL_ERR) { return y; } /* Otherwise do maths on the number values */ 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));} } return lval_err(LERR_BAD_OP); } lval eval(mpc_ast_t* t) { if (strstr(t->tag, "number")) { /* Check if there is some error in conversion */ errno = 0; /* 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 */ char* op = t->children[1]->contents; /* We store the third children in x */ lval x = eval(t->children[2]); /* Iterate the remaining children and combining */ unsigned int i = 3; while (strstr(t->children[i]->tag, "expr")) { x = eval_op(x, op, eval(t->children[i])); i++; } return x; } int main(int argc, char const *argv[]) { /* Create some parsers */ mpc_parser_t* Number = mpc_new("number"); mpc_parser_t* Operator = mpc_new("operator"); mpc_parser_t* Expr = mpc_new("expr"); mpc_parser_t* Lispy = mpc_new("lispy"); /* Define them with the following language */ mpca_lang(MPCA_LANG_DEFAULT, " \ number : /-?[0-9]+([.][0-9]*|[0-9]*)/ ; \ operator : '+' | '-' | '*' | '/' | '%' | '^' | \ \"min\" | \"max\" ; \ expr : | '(' + ')' ; \ lispy : /^/ + /$/ ; \ ", Number, Operator, Expr, Lispy); /* Print version and exit information */ puts("Lispy version 0.0.0.0.4"); puts("Press Ctrl+c to exit\n"); /* In a never ending loop */ while (1) { /* Output our prompt and get input */ char* input = readline("lispy> "); /* Add input to history */ add_history(input); /* Attempt to parse the user input */ mpc_result_t r; if (mpc_parse("", input, Lispy, &r)) { /* On success evaluate the user input */ lval result = eval(r.output); lval_println(result); mpc_ast_delete(r.output); } else { /* Otherwise print the error */ mpc_err_print(r.error); mpc_err_delete(r.error); } /* Free retrieved input */ free(input); } /* Undefine and delete our parsers */ mpc_cleanup(4, Number, Operator, Expr, Lispy); return 0; }