|
|
- #include <stdio.h>
- #include <stdlib.h>
- #include "../mpc/mpc.h"
-
-
- /* If we are on Windows compile these functions */
- #ifdef _WIN32
- #include <string.h>
- #include <assert.h>
-
- 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 <editline/readline.h>
- #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 : <number> | '(' <operator> <expr>+ ')' ; \
- lispy : /^/ <operator> <expr>+ /$/ ; \
- ",
- 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("<stdin>", 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;
- }
|