fork download
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5.  
  6. // a node in the abstract syntax tree. Either a
  7. // value or a call
  8. struct Ast {
  9. bool isCall;
  10. union {
  11. int value;
  12. struct {
  13. char const * operator;
  14. size_t countOperands;
  15. struct Ast * operands;
  16. } call;
  17. };
  18. };
  19.  
  20. // unified function type. Could've also passed an
  21. // int array, but then evaluate would've needed
  22. // a memory allocation, so ...
  23. typedef int (*Function)(struct Ast *, size_t);
  24.  
  25.  
  26. // implementation of + function. Sums the values of
  27. // parameters. (which are hopefully evaluated)
  28. int sum(struct Ast * parameters, size_t num) {
  29. int result = 0;
  30. while (num > 0) {
  31. --num;
  32. result += parameters [num]. value;
  33. }
  34. return result;
  35. }
  36.  
  37. // implementation of ? function, ignores any
  38. // parameters and just asks for an integer.
  39. int ask (struct Ast * parameters, size_t num) {
  40. int value;
  41. scanf("%d", & value);
  42. return value;
  43. }
  44.  
  45. // poor man's lookup table
  46. static Function const functions [] = {sum, ask};
  47. static char const * const function_names [] = {"+", "?"};
  48.  
  49. // poor man's lookup from above static arrays
  50. Function lookup (char const * name) {
  51. size_t it = sizeof (functions) / sizeof (functions [0]);
  52. while (it > 0) {
  53. --it;
  54. if (strcmp(name, function_names [it]) == 0) {
  55. return functions [it];
  56. }
  57. }
  58. exit(1);
  59. }
  60.  
  61. // evaluate an Ast. Normally one wouldn't return
  62. // an Ast node but rather some value_t (assuming
  63. // dynamic typing)
  64. // this function is also destructive on call Ast nodes,
  65. // in order to get around any memory management.
  66. // so be careful!
  67. struct Ast * evaluate (struct Ast * node) {
  68. if (! node->isCall) {
  69. // anything that's not a call is a value, thus
  70. // self evaluating, return it unchanged!
  71. return node;
  72. }
  73. // so it's a call. Get the associated function from
  74. // the lookup table!
  75. Function f = lookup(node->call.operator);
  76. // unconditionally evaluate all operands of the call.
  77. // thus no macros or conditionals, sorry!
  78. size_t o;
  79. for (o = 0; o < node->call.countOperands; ++o) {
  80. // destructive!
  81. node->call.operands[o] = *evaluate(&(node->call.operands[o]));
  82. }
  83. // use the call node to store the result value.
  84. // this will blow up if any call node uses any
  85. // allocated memory!
  86. node->isCall = false;
  87. // call the function with the evaluated operands and
  88. // store the result
  89. node->value = f(node->call.operands, node->call.countOperands);
  90. return node;
  91. }
  92.  
  93. int main () {
  94. // I didn't want to write a parser, so here's a
  95. // static Ast of (+ 21 10 (?))
  96. struct Ast nodes [] = {
  97. {.isCall=false, .value=21},
  98. {.isCall=false, .value=10},
  99. {.isCall=true, .call = {
  100. .operator="?", .countOperands=0}},
  101. {.isCall=true, .call = {
  102. .operator="+", .countOperands=3,
  103. .operands=nodes}}};
  104. struct Ast * result = evaluate(&(nodes [3]));
  105. printf("(+ 21 10 (?)) => %d\n", result->value);
  106. return 0;
  107. }
Success #stdin #stdout 0s 2160KB
stdin
11
stdout
(+ 21 10 (?)) => 42