#include <stdio.h> #include <math.h> #include "MEM.h" #include "DBG.h" #include "calc.h" static Value eval_int_expression(int int_value) { Value v; v.type = INT_VALUE; v.u.int_value = int_value; return v; } static Value eval_double_expression(double double_value) { Value v; v.type = DOUBLE_VALUE; v.u.double_value = double_value; return v; } static Value eval_identifier_expression(LocalEnvironment *env, char *identifier) { Value v; Value *vp; vp = clc_search_local_variable(env, identifier); if (vp != NULL) { v = *vp; return v; } vp = clc_search_global_variable(identifier); if (vp != NULL) { v = *vp; return v; } clc_runtime_error(VARIABLE_NOT_FOUND_ERR, "(%s)\n", identifier); return v; /* dummy. make compiler happy. */ } static Value eval_expression(LocalEnvironment *env, Expression *expr); static Value eval_expression_list_expression(LocalEnvironment *env, Expression *expression, Expression *next) { Value v; v = eval_expression(env, expression); if (next) { v = eval_expression(env, next); } return v; } static Value eval_assign_expression(LocalEnvironment *env, char *identifier, Expression *expression) { Value v; Value *left; v = eval_expression(env, expression); left = clc_search_local_variable(env, identifier); if (left == NULL) { left = clc_search_global_variable(identifier); } if (left != NULL) { /* Notice! Overwriting variable by pointer. */ *left = v; } else { if (env != NULL) { clc_add_local_variable(env, identifier, &v); } else { clc_add_global_variable(identifier, &v); } } return v; } static int eval_binary_int(ExpressionType operator, int left, int right) { int result; switch (operator) { case INT_EXPRESSION: /* FALLTHRU */ case DOUBLE_EXPRESSION: /* FALLTHRU */ case IDENTIFIER_EXPRESSION: /* FALLTHRU */ case EXPRESSION_LIST_EXPRESSION: /* FALLTHRU */ case ASSIGN_EXPRESSION: DBG_assert(0, ("bad case...%d", operator)); break; case ADD_EXPRESSION: result = left + right; break; case SUB_EXPRESSION: result = left - right; break; case MUL_EXPRESSION: result = left * right; break; case DIV_EXPRESSION: result = left / right; break; case MOD_EXPRESSION: result = left % right; break; case EQ_EXPRESSION: result = left == right; break; case NE_EXPRESSION: result = left != right; break; case GT_EXPRESSION: result = left > right; break; case GE_EXPRESSION: result = left >= right; break; case LT_EXPRESSION: result = left < right; break; case LE_EXPRESSION: result = left <= right; break; case MINUS_EXPRESSION: /* FALLTHRU */ case IF_EXPRESSION: /* FALLTHRU */ case WHILE_EXPRESSION: /* FALLTHRU */ case FUNCTION_CALL_EXPRESSION: /* FALLTHRU */ case EXPRESSION_TYPE_NUM: /* FALLTHRU */ default: DBG_assert(0, ("bad case...%d", operator)); } return result; } static void eval_binary_double(ExpressionType operator, double left, double right, Value *result) { if (operator == ADD_EXPRESSION || operator == SUB_EXPRESSION || operator == MUL_EXPRESSION || operator == DIV_EXPRESSION || operator == MOD_EXPRESSION) { result->type = DOUBLE_VALUE; } else { DBG_assert(operator == EQ_EXPRESSION || operator == NE_EXPRESSION || operator == GT_EXPRESSION || operator == GE_EXPRESSION || operator == LT_EXPRESSION || operator == LE_EXPRESSION, ("operator..%d\n", operator)); result->type = INT_VALUE; } switch (operator) { case INT_EXPRESSION: /* FALLTHRU */ case DOUBLE_EXPRESSION: /* FALLTHRU */ case IDENTIFIER_EXPRESSION: /* FALLTHRU */ case EXPRESSION_LIST_EXPRESSION: /* FALLTHRU */ case ASSIGN_EXPRESSION: DBG_assert(0, ("bad case...%d", operator)); break; case ADD_EXPRESSION: result->u.double_value = left + right; break; case SUB_EXPRESSION: result->u.double_value = left - right; break; case MUL_EXPRESSION: result->u.double_value = left * right; break; case DIV_EXPRESSION: result->u.double_value = left / right; break; case MOD_EXPRESSION: result->u.double_value = fmod(left, right); break; case EQ_EXPRESSION: result->u.int_value = left == right; break; case NE_EXPRESSION: result->u.int_value = left != right; break; case GT_EXPRESSION: result->u.int_value = left > right; break; case GE_EXPRESSION: result->u.int_value = left >= right; break; case LT_EXPRESSION: result->u.int_value = left < right; break; case LE_EXPRESSION: result->u.int_value = left <= right; break; case MINUS_EXPRESSION: /* FALLTHRU */ case IF_EXPRESSION: /* FALLTHRU */ case WHILE_EXPRESSION: /* FALLTHRU */ case FUNCTION_CALL_EXPRESSION: /* FALLTHRU */ case EXPRESSION_TYPE_NUM: /* FALLTHRU */ default: DBG_assert(0, ("bad default...%d", operator)); } } Value clc_eval_binary_expression(LocalEnvironment *env, ExpressionType operator, Expression *left, Expression *right) { Value left_val; Value right_val; Value result; left_val = eval_expression(env, left); right_val = eval_expression(env, right); if (left_val.type == INT_VALUE && right_val.type == INT_VALUE) { result.type = INT_VALUE; result.u.int_value = eval_binary_int(operator, left_val.u.int_value, right_val.u.int_value); } else if (left_val.type == DOUBLE_VALUE && right_val.type == DOUBLE_VALUE) { eval_binary_double(operator, left_val.u.double_value, right_val.u.double_value, &result); } else { /* cast int to double */ if (left_val.type == INT_VALUE) { left_val.u.double_value = left_val.u.int_value; } else { right_val.u.double_value = right_val.u.int_value; } eval_binary_double(operator, left_val.u.double_value, right_val.u.double_value, &result); } return result; } Value clc_eval_minus_expression(LocalEnvironment *env, Expression *operand) { Value operand_val; Value result; operand_val = eval_expression(env, operand); if (operand_val.type == INT_VALUE) { result.type = INT_VALUE; result.u.int_value = -operand_val.u.int_value; } else { DBG_assert(operand_val.type == DOUBLE_VALUE, ("operand_val.type..%d", operand_val.type)); result.type = DOUBLE_VALUE; result.u.double_value = -operand_val.u.double_value; } return result; } static Value eval_if_expression(LocalEnvironment *env, Expression *condition, Expression *then_expression, Expression *else_expression) { Value condition_val; Value result; condition_val = eval_expression(env, condition); if (condition_val.type != INT_VALUE) { clc_runtime_error(BOOLEAN_EXPECTED_ERR, NULL); } if (condition_val.u.int_value) { result = eval_expression(env, then_expression); } else { result = eval_expression(env, else_expression); } return result; } static Value eval_while_expression(LocalEnvironment *env, Expression *condition, Expression *expression_list) { Value condition_val; Value result; for (;;) { condition_val = eval_expression(env, condition); if (condition_val.type != INT_VALUE) { clc_runtime_error(BOOLEAN_EXPECTED_ERR, NULL); } if (!condition_val.u.int_value) break; result = eval_expression(env, expression_list); } return result; } static LocalEnvironment * alloc_local_environment() { LocalEnvironment *ret; ret = MEM_malloc(sizeof(LocalEnvironment)); ret->variable = NULL; return ret; } static void dispose_local_environment(LocalEnvironment *env) { while (env->variable) { Variable *temp; temp = env->variable->next; MEM_free(env->variable); env->variable = temp; } MEM_free(env); } static Value eval_function_call_expression(LocalEnvironment *env, char *identifier, Expression *argument) { Value result; Expression *arg_p; ParameterList *param_p; LocalEnvironment *local_env; FunctionDefinition *func; func = clc_search_function(identifier); if (func == NULL) { clc_runtime_error(FUNCTION_NOT_FOUND_ERR, "name..%s\n", identifier); } local_env = alloc_local_environment(); DBG_assert(argument->type == EXPRESSION_LIST_EXPRESSION, ("type..%d\n", argument->type)); for (arg_p = argument, param_p = func->parameter; arg_p; arg_p = arg_p->u.expression_list.next, param_p = param_p->next) { Value arg_val; if (param_p == NULL) { clc_runtime_error(ARGUMENT_TOO_MANY_ERR, NULL); } arg_val = eval_expression(env, arg_p->u.expression_list.expression); clc_add_local_variable(local_env, param_p->name, &arg_val); } if (param_p) { clc_runtime_error(ARGUMENT_TOO_FEW_ERR, NULL); } result = eval_expression(local_env, func->expression_list); dispose_local_environment(local_env); return result; } static Value eval_expression(LocalEnvironment *env, Expression *expr) { Value v; switch (expr->type) { case INT_EXPRESSION: v = eval_int_expression(expr->u.int_value); break; case DOUBLE_EXPRESSION: v = eval_double_expression(expr->u.double_value); break; case IDENTIFIER_EXPRESSION: v = eval_identifier_expression(env, expr->u.identifier); break; case EXPRESSION_LIST_EXPRESSION: v = eval_expression_list_expression (env, expr->u.expression_list.expression, expr->u.expression_list.next); break; case ASSIGN_EXPRESSION: v = eval_assign_expression(env, expr->u.assign_expression.variable, expr->u.assign_expression.operand); break; case ADD_EXPRESSION: /* FALLTHRU */ case SUB_EXPRESSION: /* FALLTHRU */ case MUL_EXPRESSION: /* FALLTHRU */ case DIV_EXPRESSION: /* FALLTHRU */ case MOD_EXPRESSION: /* FALLTHRU */ case EQ_EXPRESSION: /* FALLTHRU */ case NE_EXPRESSION: /* FALLTHRU */ case GT_EXPRESSION: /* FALLTHRU */ case GE_EXPRESSION: /* FALLTHRU */ case LT_EXPRESSION: /* FALLTHRU */ case LE_EXPRESSION: /* FALLTHRU */ v = clc_eval_binary_expression(env, expr->type, expr->u.binary_expression.left, expr->u.binary_expression.right); break; case MINUS_EXPRESSION: v = clc_eval_minus_expression(env, expr->u.minus_expression); break; case IF_EXPRESSION: v = eval_if_expression(env, expr->u.if_expression.condition, expr->u.if_expression.then_expression, expr->u.if_expression.else_expression); break; case WHILE_EXPRESSION: v = eval_while_expression(env, expr->u.while_expression.condition, expr->u.while_expression.expression_list); break; case FUNCTION_CALL_EXPRESSION: v = eval_function_call_expression (env, expr->u.function_call_expression.identifier, expr->u.function_call_expression.argument); break; case EXPRESSION_TYPE_NUM: /* FALLTHRU */ default: DBG_assert(0, ("bad case. type..%d\n", expr->type)); } return v; } void clc_eval_expression(Expression *expression) { Value v; RuntimeError error_id; if ((error_id = (RuntimeError)setjmp(clc_current_interpreter ->error_recovery_environment)) == 0) { v = eval_expression(NULL, expression); if (clc_current_interpreter->input_mode == CLC_TTY_INPUT_MODE) { if (v.type == INT_VALUE) { printf(">>%d\n", v.u.int_value); } else if (v.type == DOUBLE_VALUE) { printf(">>%f\n", v.u.double_value); } else { printf("<void>\n"); } } } else { } clc_reopen_current_storage(); }