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

226 lines
5.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. /* Declare new lval struct */
  27. typedef struct {
  28. int type;
  29. long num;
  30. int err;
  31. } lval;
  32. /* Create enumeration of possible lval types */
  33. enum {LVAL_NUM, LVAL_ERR};
  34. /* Create enumeration of possible error types */
  35. enum {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM};
  36. /* Create a new number of type lval */
  37. lval lval_num(long x) {
  38. lval v;
  39. v.type = LVAL_NUM;
  40. v.num = x;
  41. return v;
  42. }
  43. /* Create a new error type lval */
  44. lval lval_err(int x) {
  45. lval v;
  46. v.type = LVAL_ERR;
  47. v.err = x;
  48. return v;
  49. }
  50. /* Print an lval */
  51. void lval_print(lval v) {
  52. switch (v.type) {
  53. /* In the case the type is a number print it
  54. Then break out of the switch */
  55. case LVAL_NUM:
  56. printf("%li", v.num);
  57. break;
  58. /* In the case the type is an error */
  59. case LVAL_ERR:
  60. /* Check what type of error it is & print it */
  61. if (v.err == LERR_DIV_ZERO) {
  62. printf("Error: Division by zero!");
  63. }
  64. if (v.err == LERR_BAD_OP) {
  65. printf("Error: Invalid operator!");
  66. }
  67. if (v.err == LERR_BAD_NUM) {
  68. printf("Error: Invalid number!");
  69. }
  70. break;
  71. }
  72. }
  73. /* Print an lval followed by a newline */
  74. void lval_println(lval v) {
  75. lval_print(v);
  76. putchar('\n');
  77. }
  78. long min(long x, long y) {
  79. if (x <= y) {
  80. return x;
  81. } else {
  82. return y;
  83. }
  84. }
  85. long max(long x, long y) {
  86. if (x >= y) {
  87. return x;
  88. } else {
  89. return y;
  90. }
  91. }
  92. /* Use operator string to see which operation to perform */
  93. lval eval_op(lval x, char* op, lval y) {
  94. /* If either value is an error return it */
  95. if (x.type == LVAL_ERR) {
  96. return x;
  97. }
  98. if (y.type == LVAL_ERR) {
  99. return y;
  100. }
  101. /* Otherwise do maths on the number values */
  102. if (strcmp(op, "+") == 0) {return lval_num(x.num + y.num);}
  103. if (strcmp(op, "-") == 0) {return lval_num(x.num - y.num);}
  104. if (strcmp(op, "*") == 0) {return lval_num(x.num * y.num);}
  105. if (strcmp(op, "/") == 0) {
  106. /* If second operand is zero return error */
  107. return y.num == 0 ? lval_err(LERR_DIV_ZERO)
  108. : lval_num(x.num / y.num);
  109. }
  110. if (strcmp(op, "%") == 0) {return lval_num(x.num % y.num);}
  111. if (strcmp(op, "^") == 0) {return lval_num(pow(x.num, y.num));}
  112. if (strcmp(op, "min") == 0) {return lval_num(min(x.num, y.num));}
  113. if (strcmp(op, "max") == 0) {return lval_num(max(x.num, y.num));}
  114. return lval_err(LERR_BAD_OP);
  115. }
  116. lval eval(mpc_ast_t* t) {
  117. if (strstr(t->tag, "number")) {
  118. /* Check if there is some error in conversion */
  119. errno = 0;
  120. long x = strtol(t->contents, NULL, 10);
  121. return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM);
  122. }
  123. /* The operator is always second child */
  124. char* op = t->children[1]->contents;
  125. /* We store the third children in x */
  126. lval x = eval(t->children[2]);
  127. /* Iterate the remaining children and combining */
  128. unsigned int i = 3;
  129. while (strstr(t->children[i]->tag, "expr")) {
  130. x = eval_op(x, op, eval(t->children[i]));
  131. i++;
  132. }
  133. return x;
  134. }
  135. int main(int argc, char const *argv[]) {
  136. /* Create some parsers */
  137. mpc_parser_t* Number = mpc_new("number");
  138. mpc_parser_t* Operator = mpc_new("operator");
  139. mpc_parser_t* Expr = mpc_new("expr");
  140. mpc_parser_t* Lispy = mpc_new("lispy");
  141. /* Define them with the following language */
  142. mpca_lang(MPCA_LANG_DEFAULT,
  143. " \
  144. number : /-?[0-9]+/ ; \
  145. operator : '+' | '-' | '*' | '/' | '%' | '^' | \
  146. \"min\" | \"max\" ; \
  147. expr : <number> | '(' <operator> <expr>+ ')' ; \
  148. lispy : /^/ <operator> <expr>+ /$/ ; \
  149. ",
  150. Number, Operator, Expr, Lispy);
  151. /* Print version and exit information */
  152. puts("Lispy version 0.0.0.0.4");
  153. puts("Press Ctrl+c to exit\n");
  154. /* In a never ending loop */
  155. while (1) {
  156. /* Output our prompt and get input */
  157. char* input = readline("lispy> ");
  158. /* Add input to history */
  159. add_history(input);
  160. /* Attempt to parse the user input */
  161. mpc_result_t r;
  162. if (mpc_parse("<stdin>", input, Lispy, &r)) {
  163. /* On success evaluate the user input */
  164. lval result = eval(r.output);
  165. lval_println(result);
  166. mpc_ast_delete(r.output);
  167. } else {
  168. /* Otherwise print the error */
  169. mpc_err_print(r.error);
  170. mpc_err_delete(r.error);
  171. }
  172. /* Free retrieved input */
  173. free(input);
  174. }
  175. /* Undefine and delete our parsers */
  176. mpc_cleanup(4, Number, Operator, Expr, Lispy);
  177. return 0;
  178. }