#include #include #include #include #include "eval.h" static int evaluate_type(const struct Node* node, struct Type* out); static int evaluate_value(const struct Node* node, int64_t* out); static int evaluate_condition(const struct Node* node, bool* out); static int complain(const struct Node* node, const char* message) { (void)fprintf(stderr, "line %d: %s\n", node->line, message); return 1; } static int evaluate_operands(const struct Node* node, int64_t* left, int64_t* right) { if (evaluate_value(node->first, left)) return 1; return evaluate_value(node->second, right); } static int evaluate_value(const struct Node* node, int64_t* out) { int64_t left = 0; int64_t right = 0; struct Type type; bool truth = false; switch (node->kind) { case VALUE_DIFFERENCE: *out = (int64_t)node->first->character - (int64_t)node->second->character; return 0; case VALUE_SUM: if (evaluate_operands(node, &left, &right)) return 1; *out = left + right; return 0; case VALUE_PRODUCT: if (evaluate_operands(node, &left, &right)) return 1; *out = left * right; return 0; case VALUE_QUOTIENT: if (evaluate_operands(node, &left, &right)) return 1; if (right == 0) return complain(node, "division by zero"); *out = left / right; return 0; case VALUE_EXTENT: case VALUE_TUPLE_SIZE: if (evaluate_type(node->first, &type)) return 1; *out = type.kind == KIND_ARRAY ? type.number : 0; return 0; case VALUE_INTEGRAL_CONSTANT: return evaluate_value(node->first, out); case VALUE_CONDITIONAL: if (evaluate_condition(node->first, &truth)) return 1; return evaluate_value(truth ? node->second : node->third, out); default: break; } assert(!"the parser handed a non-value where a value goes"); return 1; } static int evaluate_type(const struct Node* node, struct Type* out) { out->kind = KIND_VOID; out->number = 0; struct Type element; bool truth = false; switch (node->kind) { case TYPE_VOID: return 0; case TYPE_INT32: out->kind = KIND_INT32; return 0; case TYPE_BYTE: out->kind = KIND_BYTE; return 0; case TYPE_SIZE: out->kind = KIND_SIZE; return 0; case TYPE_REMOVE_CV: return evaluate_type(node->first, out); case TYPE_ARRAY: if (evaluate_type(node->first, &element) || evaluate_value(node->second, &out->number)) return 1; out->kind = KIND_ARRAY; return 0; case TYPE_CONDITIONAL: if (evaluate_condition(node->first, &truth)) return 1; return evaluate_type(truth ? node->second : node->third, out); case TYPE_DECLTYPE: if (evaluate_value(node->first, &out->number)) return 1; out->kind = KIND_VALUE; return 0; default: break; } assert(!"the parser handed a non-type where a type goes"); return 1; } static bool same_type(const struct Type* left, const struct Type* right) { return left->kind == right->kind && left->number == right->number; } static int evaluate_condition(const struct Node* node, bool* out) { int64_t left = 0; int64_t right = 0; struct Type left_type; struct Type right_type; *out = false; switch (node->kind) { case COND_TRUE: *out = true; return 0; case COND_FALSE: return 0; case COND_IS_SAME: if (evaluate_type(node->first, &left_type) || evaluate_type(node->second, &right_type)) return 1; *out = same_type(&left_type, &right_type); return 0; case COND_EQUAL: if (evaluate_operands(node, &left, &right)) return 1; *out = left == right; return 0; case COND_LESS: if (evaluate_operands(node, &left, &right)) return 1; *out = left < right; return 0; default: break; } assert(!"the parser handed a non-condition where a condition goes"); return 1; } static enum RunStatus emit(const struct Node* node) { struct Type type; if (evaluate_type(node->first, &type)) return RUN_FAILED; switch (type.kind) { case KIND_VOID: break; case KIND_INT32: (void)printf("int32_t\n"); break; case KIND_BYTE: (void)printf("byte\n"); break; case KIND_SIZE: (void)printf("size_t\n"); break; case KIND_ARRAY: (void)printf("array[%" PRId64 "]\n", type.number); break; case KIND_VALUE: (void)printf("%" PRId64 "\n", type.number); break; } return RUN_DONE; } static enum RunStatus execute_one(const struct Node* node) { switch (node->kind) { case STMT_EMIT: return emit(node); default: break; } assert(!"the parser handed a non-statement where a statement goes"); return RUN_FAILED; } enum RunStatus execute(const struct Node* statement) { while (statement != NULL) { enum RunStatus status = execute_one(statement); if (status != RUN_DONE) return status; statement = statement->next; } return RUN_DONE; }