参考

{% collapse title=”error_handling.c” %}

  1. #include "mpc.h"
  2. #ifdef _WIN32
  3. static char buffer[2048];
  4. char* readline(char* prompt) {
  5. fputs(prompt, stdout);
  6. fgets(buffer, 2048, stdin);
  7. char* cpy = malloc(strlen(buffer)+1);
  8. strcpy(cpy, buffer);
  9. cpy[strlen(cpy)-1] = '\0';
  10. return cpy;
  11. }
  12. void add_history(char* unused) {}
  13. #else
  14. #include <editline/readline.h>
  15. #include <editline/history.h>
  16. #endif
  17. /* Create Enumeration of Possible Error Types */
  18. enum { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM };
  19. /* Create Enumeration of Possible lval Types */
  20. enum { LVAL_NUM, LVAL_ERR };
  21. /* Declare New lval Struct */
  22. typedef struct {
  23. int type;
  24. long num;
  25. int err;
  26. } lval;
  27. /* Create a new number type lval */
  28. lval lval_num(long x) {
  29. lval v;
  30. v.type = LVAL_NUM;
  31. v.num = x;
  32. return v;
  33. }
  34. /* Create a new error type lval */
  35. lval lval_err(int x) {
  36. lval v;
  37. v.type = LVAL_ERR;
  38. v.err = x;
  39. return v;
  40. }
  41. /* Print an "lval" */
  42. void lval_print(lval v) {
  43. switch (v.type) {
  44. /* In the case the type is a number print it */
  45. /* Then 'break' out of the switch. */
  46. case LVAL_NUM: printf("%li", v.num); break;
  47. /* In the case the type is an error */
  48. case LVAL_ERR:
  49. /* Check what type of error it is and print it */
  50. if (v.err == LERR_DIV_ZERO) {
  51. printf("Error: Division By Zero!");
  52. }
  53. if (v.err == LERR_BAD_OP) {
  54. printf("Error: Invalid Operator!");
  55. }
  56. if (v.err == LERR_BAD_NUM) {
  57. printf("Error: Invalid Number!");
  58. }
  59. break;
  60. }
  61. }
  62. /* Print an "lval" followed by a newline */
  63. void lval_println(lval v) { lval_print(v); putchar('\n'); }
  64. lval eval_op(lval x, char* op, lval y) {
  65. /* If either value is an error return it */
  66. if (x.type == LVAL_ERR) { return x; }
  67. if (y.type == LVAL_ERR) { return y; }
  68. /* Otherwise do maths on the number values */
  69. if (strcmp(op, "+") == 0) { return lval_num(x.num + y.num); }
  70. if (strcmp(op, "-") == 0) { return lval_num(x.num - y.num); }
  71. if (strcmp(op, "*") == 0) { return lval_num(x.num * y.num); }
  72. if (strcmp(op, "/") == 0) {
  73. /* If second operand is zero return error */
  74. return y.num == 0
  75. ? lval_err(LERR_DIV_ZERO)
  76. : lval_num(x.num / y.num);
  77. }
  78. return lval_err(LERR_BAD_OP);
  79. }
  80. lval eval(mpc_ast_t* t) {
  81. if (strstr(t->tag, "number")) {
  82. /* Check if there is some error in conversion */
  83. errno = 0;
  84. long x = strtol(t->contents, NULL, 10);
  85. return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM);
  86. }
  87. char* op = t->children[1]->contents;
  88. lval x = eval(t->children[2]);
  89. int i = 3;
  90. while (strstr(t->children[i]->tag, "expr")) {
  91. x = eval_op(x, op, eval(t->children[i]));
  92. i++;
  93. }
  94. return x;
  95. }
  96. int main(int argc, char** argv) {
  97. mpc_parser_t* Number = mpc_new("number");
  98. mpc_parser_t* Operator = mpc_new("operator");
  99. mpc_parser_t* Expr = mpc_new("expr");
  100. mpc_parser_t* Lispy = mpc_new("lispy");
  101. mpca_lang(MPCA_LANG_DEFAULT,
  102. " \
  103. number : /-?[0-9]+/ ; \
  104. operator : '+' | '-' | '*' | '/' ; \
  105. expr : <number> | '(' <operator> <expr>+ ')' ; \
  106. lispy : /^/ <operator> <expr>+ /$/ ; \
  107. ",
  108. Number, Operator, Expr, Lispy);
  109. puts("Lispy Version 0.0.0.0.4");
  110. puts("Press Ctrl+c to Exit\n");
  111. while (1) {
  112. char* input = readline("lispy> ");
  113. add_history(input);
  114. mpc_result_t r;
  115. if (mpc_parse("<stdin>", input, Lispy, &r)) {
  116. lval result = eval(r.output);
  117. lval_println(result);
  118. mpc_ast_delete(r.output);
  119. } else {
  120. mpc_err_print(r.error);
  121. mpc_err_delete(r.error);
  122. }
  123. free(input);
  124. }
  125. mpc_cleanup(4, Number, Operator, Expr, Lispy);
  126. return 0;
  127. }

{% endcollapse %}