diff --git a/chapter_07/Makefile b/chapter_07/Makefile new file mode 100644 index 0000000..e831f5c --- /dev/null +++ b/chapter_07/Makefile @@ -0,0 +1,13 @@ +MPC_DIR := ../mpc + + +all: lispy + + +%: %.c + cc -std=c11 -Wall $@.c ${MPC_DIR}/mpc.c -ledit -o $@ + + +.PHONY: clean +clean: + rm -rf lispy diff --git a/chapter_07/lispy.c b/chapter_07/lispy.c new file mode 100644 index 0000000..fe10429 --- /dev/null +++ b/chapter_07/lispy.c @@ -0,0 +1,119 @@ +#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 + + +/* Use operator string to see which operation to perform */ +long eval_op(long x, char* op, long y) { + if (strcmp(op, "+") == 0) {return x + y;} + if (strcmp(op, "-") == 0) {return x - y;} + if (strcmp(op, "*") == 0) {return x * y;} + if (strcmp(op, "/") == 0) {return x / y;} + return 0; +} + + +long eval(mpc_ast_t* t) { + + /* If tagged as number return it directly */ + if (strstr(t->tag, "number")) { + return atoi(t->contents); + } + + /* The operator is always second child */ + char* op = t->children[1]->contents; + + /* We store the third children in x */ + long 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]+/ ; \ + operator : '+' | '-' | '*' | '/' ; \ + expr : | '(' + ')' ; \ + lispy : /^/ + /$/ ; \ + ", + Number, Operator, Expr, Lispy); + + /* Print version and exit information */ + puts("Lispy version 0.0.0.0.3"); + 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 */ + long result = eval(r.output); + printf("%li\n", 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; +}