(Somewhat adapted) code and solutions from the book "Build Your Own Lisp" http://www.buildyourownlisp.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.1 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "../mpc/mpc.h"
  4. /* If we are on Windows compile these functions */
  5. #ifdef _WIN32
  6. #include <string.h>
  7. #include <assert.h>
  8. static char buffer[2048];
  9. /* Fake readline function */
  10. char* readline(char* prompt) {
  11. fputs(prompt, stdout);
  12. fgets(buffer, 2048, stdin);
  13. char* cpy = malloc(strlen(buffer)+1);
  14. assert(cpy != NULL)
  15. strcpy(cpy, buffer);
  16. cpy[strlen(cpy)-1] = '\0';
  17. return cpy;
  18. }
  19. /* Fake add_history function */
  20. void add_history(char* unused) {}
  21. /* Otherwise include the editline headers
  22. could use __APPLE__ for detection of OSX */
  23. #else
  24. #include <editline/readline.h>
  25. #endif
  26. /* Use operator string to see which operation to perform */
  27. long eval_op(long x, char* op, long y) {
  28. if (strcmp(op, "+") == 0) {return x + y;}
  29. if (strcmp(op, "-") == 0) {return x - y;}
  30. if (strcmp(op, "*") == 0) {return x * y;}
  31. if (strcmp(op, "/") == 0) {return x / y;}
  32. return 0;
  33. }
  34. long eval(mpc_ast_t* t) {
  35. /* If tagged as number return it directly */
  36. if (strstr(t->tag, "number")) {
  37. return atoi(t->contents);
  38. }
  39. /* The operator is always second child */
  40. char* op = t->children[1]->contents;
  41. /* We store the third children in x */
  42. long x = eval(t->children[2]);
  43. /* Iterate the remaining children and combining */
  44. unsigned int i = 3;
  45. while (strstr(t->children[i]->tag, "expr")) {
  46. x = eval_op(x, op, eval(t->children[i]));
  47. i++;
  48. }
  49. return x;
  50. }
  51. int main(int argc, char const *argv[])
  52. {
  53. /* Create some parsers */
  54. mpc_parser_t* Number = mpc_new("number");
  55. mpc_parser_t* Operator = mpc_new("operator");
  56. mpc_parser_t* Expr = mpc_new("expr");
  57. mpc_parser_t* Lispy = mpc_new("lispy");
  58. /* Define them with the following language */
  59. mpca_lang(MPCA_LANG_DEFAULT,
  60. " \
  61. number : /-?[0-9]+/ ; \
  62. operator : '+' | '-' | '*' | '/' ; \
  63. expr : <number> | '(' <operator> <expr>+ ')' ; \
  64. lispy : /^/ <operator> <expr>+ /$/ ; \
  65. ",
  66. Number, Operator, Expr, Lispy);
  67. /* Print version and exit information */
  68. puts("Lispy version 0.0.0.0.3");
  69. puts("Press Ctrl+c to exit\n");
  70. /* In a never ending loop */
  71. while (1) {
  72. /* Output our prompt and get input */
  73. char* input = readline("lispy> ");
  74. /* Add input to history */
  75. add_history(input);
  76. /* Attempt to parse the user input */
  77. mpc_result_t r;
  78. if (mpc_parse("<stdin>", input, Lispy, &r)) {
  79. /* On success evaluate the user input */
  80. long result = eval(r.output);
  81. printf("%li\n", result);
  82. mpc_ast_delete(r.output);
  83. } else {
  84. /* Otherwise print the error */
  85. mpc_err_print(r.error);
  86. mpc_err_delete(r.error);
  87. }
  88. /* Free retrieved input */
  89. free(input);
  90. }
  91. /* Undefine and delete our parsers */
  92. mpc_cleanup(4, Number, Operator, Expr, Lispy);
  93. return 0;
  94. }