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

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