(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.

142 lines
3.5 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. long min(long x, long y) {
  27. if (x <= y) {
  28. return x;
  29. } else {
  30. return y;
  31. }
  32. }
  33. long max(long x, long y) {
  34. if (x >= y) {
  35. return x;
  36. } else {
  37. return y;
  38. }
  39. }
  40. /* Use operator string to see which operation to perform */
  41. long eval_op(long x, char* op, long y) {
  42. if (strcmp(op, "+") == 0) {return x + y;}
  43. if (strcmp(op, "-") == 0) {return x - y;}
  44. if (strcmp(op, "*") == 0) {return x * y;}
  45. if (strcmp(op, "/") == 0) {return x / y;}
  46. if (strcmp(op, "%") == 0) {return x % y;}
  47. if (strcmp(op, "^") == 0) {return pow(x, y);}
  48. if (strcmp(op, "min") == 0) {return min(x, y);}
  49. if (strcmp(op, "max") == 0) {return max(x, y);}
  50. return 0;
  51. }
  52. long eval(mpc_ast_t* t) {
  53. /* If tagged as number return it directly */
  54. if (strstr(t->tag, "number")) {
  55. return atoi(t->contents);
  56. }
  57. /* The operator is always second child */
  58. char* op = t->children[1]->contents;
  59. /* We store the third children in x */
  60. long x = eval(t->children[2]);
  61. /* Iterate the remaining children and combining */
  62. unsigned int i = 3;
  63. while (strstr(t->children[i]->tag, "expr")) {
  64. x = eval_op(x, op, eval(t->children[i]));
  65. i++;
  66. }
  67. return x;
  68. }
  69. int main(int argc, char const *argv[]) {
  70. /* Create some parsers */
  71. mpc_parser_t* Number = mpc_new("number");
  72. mpc_parser_t* Operator = mpc_new("operator");
  73. mpc_parser_t* Expr = mpc_new("expr");
  74. mpc_parser_t* Lispy = mpc_new("lispy");
  75. /* Define them with the following language */
  76. mpca_lang(MPCA_LANG_DEFAULT,
  77. " \
  78. number : /-?[0-9]+/ ; \
  79. operator : '+' | '-' | '*' | '/' | '%' | '^' | \
  80. \"min\" | \"max\" ; \
  81. expr : <number> | '(' <operator> <expr>+ ')' ; \
  82. lispy : /^/ <operator> <expr>+ /$/ ; \
  83. ",
  84. Number, Operator, Expr, Lispy);
  85. /* Print version and exit information */
  86. puts("Lispy version 0.0.0.0.3");
  87. puts("Press Ctrl+c to exit\n");
  88. /* In a never ending loop */
  89. while (1) {
  90. /* Output our prompt and get input */
  91. char* input = readline("lispy> ");
  92. /* Add input to history */
  93. add_history(input);
  94. /* Attempt to parse the user input */
  95. mpc_result_t r;
  96. if (mpc_parse("<stdin>", input, Lispy, &r)) {
  97. /* On success evaluate the user input */
  98. long result = eval(r.output);
  99. printf("%li\n", result);
  100. mpc_ast_delete(r.output);
  101. } else {
  102. /* Otherwise print the error */
  103. mpc_err_print(r.error);
  104. mpc_err_delete(r.error);
  105. }
  106. /* Free retrieved input */
  107. free(input);
  108. }
  109. /* Undefine and delete our parsers */
  110. mpc_cleanup(4, Number, Operator, Expr, Lispy);
  111. return 0;
  112. }