sin,cos,tanと累乗(^)を扱えるようにした。大まかな流れとしては、
< 関連性のない式 > : = < 後置式 > | < 前置式 > < 前置式 > : = ßin" < 後置式 > | "cos" < 後置式 > | "tan" < 後置式 > | "-" < 後置式 > < 後置式 > : = < 一次式 > | < 一次式 > "^" < 後置式 >
それをBisonの定義にし、アクションを追加すると
type < expression > prefix_expressionunary_expression : postfix_expression | prefix_expression ;prefix_expression : SIN postfix_expression { $$ = clc_create_sin_expression($2); } | COS postfix_expression { $$ = clc_create_cos_expression($2); } | TAN postfix_expression { $$ = clc_create_tan_expression($2); } | SUB unary_expression { $$ = clc_create_minus_expression($2); } ;postfix_expression : primary_expression | primary_expression POW postfix_expression { $$ = clc_create_binary_expression(POW_EXPRESSION, $1, $3); } ;
のようになる。
typedef enum { ... POW_EXPRESSION, SIN_EXPRESSION, COS_EXPRESSION, TAN_EXPRESSION, ...} ExpressionType;Expression *clc_create_sin_expression(Expression *operand);Expression *clc_create_cos_expression(Expression *operand);Expression *clc_create_tan_expression(Expression *operand);Value clc_eval_sin_expression(LocalEnvironment *env, Expression *operand);Value clc_eval_cos_expression(LocalEnvironment *env, Expression *operand);Value clc_eval_tan_expression(LocalEnvironment *env, Expression *operand);
(tan)Expression *clc_create_tan_expression(Expression *operand){ if (operand- > type = = INT_EXPRESSION || operand- > type = = DOUBLE_EXPRESSION) { Value v; v = clc_eval_tan_expression(NULL, operand); /* Notice! Overwriting operand expression. */ *operand = convert_value_to_expression(&v); return operand; } else { Expression *exp; exp = clc_alloc_expression(TAN_EXPRESSION); exp- > u.minus_expression = operand; return exp; }}
static int eval_binary_int(ExpressionType operator, int left, int right) { ... case POW_EXPRESSION: result = (int)pow(left,right); break; ... case MINUS_EXPRESSION: /* FALLTHRU */ case SIN_EXPRESSION: /* FALLTHRU */ /* sin追加 */ case COS_EXPRESSION: /* FALLTHRU */ /* cos追加 */ case TAN_EXPRESSION: /* FALLTHRU */ /* tan追加 */ ... } 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 || operator == POW_EXPRESSION) { result->type = DOUBLE_VALUE; } ... case POW_EXPRESSION: result->u.double_value = pow(left, right); break; ... case MINUS_EXPRESSION: /* FALLTHRU */ case SIN_EXPRESSION: /* FALLTHRU */ case COS_EXPRESSION: /* FALLTHRU */ case TAN_EXPRESSION: /* FALLTHRU */ ... }
続いてsin,cos,tanの各評価関数を追加。
Value clc_eval_sin_expression(LocalEnvironment *env, Expression *operand) { Value operand_val; Value result; operand_val = eval_expression(env, operand); if (operand_val.type == INT_VALUE) { result.type = DOUBLE_VALUE; result.u.double_value = sin(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 = sin(operand_val.u.double_value); } return result; } Value clc_eval_cos_expression(LocalEnvironment *env, Expression *operand) { Value operand_val; Value result; operand_val = eval_expression(env, operand); if (operand_val.type == INT_VALUE) { result.type = DOUBLE_VALUE; result.u.double_value = cos(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 = cos(operand_val.u.double_value); } return result; } Value clc_eval_tan_expression(LocalEnvironment *env, Expression *operand) { Value operand_val; Value result; operand_val = eval_expression(env, operand); if (operand_val.type == INT_VALUE) { result.type = DOUBLE_VALUE; result.u.double_value = tan(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 = tan(operand_val.u.double_value); } return result; } static Value eval_expression(LocalEnvironment *env, Expression *expr) { ... case POW_EXPRESSION: /* FALLTHRU */ ... case MINUS_EXPRESSION: v = clc_eval_minus_expression(env, expr->u.minus_expression); break; case SIN_EXPRESSION: v = clc_eval_sin_expression(env, expr->u.minus_expression); break; case COS_EXPRESSION: v = clc_eval_cos_expression(env, expr->u.minus_expression); break; case TAN_EXPRESSION: v = clc_eval_tan_expression(env, expr->u.minus_expression); break; ... }
%{ #undef YY_INPUT #define YY_INPUT(buf, result, max_size) (result = my_yyinput(buf, max_size)) #include <stdio.h> #include <string.h> #include <readline/readline.h> #include "DBG.h" #include "calc.h" #include "y.tab.h" static int my_yyinput(char *buf, int max_size); %} %start COMMENT %% <INITIAL>"define" return DEFINE; <INITIAL>"if" return IF; <INITIAL>"else" return ELSE; <INITIAL>"while" return WHILE; <INITIAL>"for" return FOR; <INITIAL>"i" return I; <INITIAL>"(" return LP; <INITIAL>")" return RP; <INITIAL>"{" return LC; <INITIAL>"}" return RC; <INITIAL>";" return SEMICOLON; <INITIAL>"," return COMMA; <INITIAL>"=" return ASSIGN; <INITIAL>"==" return EQ; <INITIAL>"!=" return NE; <INITIAL>">" return GT; <INITIAL>">=" return GE; <INITIAL>"<" return LT; <INITIAL>"<=" return LE; <INITIAL>"+" return ADD; <INITIAL>"-" return SUB; 以下は前橋氏と同じなので省略
%{ #include <stdio.h> #include "calc.h" #define YYDEBUG 1 %} %union { char *identifier; ParameterList *parameter_list; Expression *expression; } %token <expression> INT_LITERAL %token <expression> DOUBLE_LITERAL %token <identifier> IDENTIFIER %token DEFINE IF ELSE WHILE FOR I LP RP LC RC SEMICOLON COMMA ASSIGN EQ NE GT GE LT LE ADD SUB MUL DIV MOD %type <parameter_list> parameter_list %type <expression> expression expression_list equality_expression relational_expression additive_expression multiplicative_expression unary_expression postfix_expression primary_expression if_expression while_expression for_expression %% translation_unit : definition_or_expression | translation_unit definition_or_expression ; 省略 primary_expression : IDENTIFIER LP expression_list RP { $$ = clc_create_function_call_expression($1, $3); } | IDENTIFIER LP RP { $$ = clc_create_function_call_expression($1, NULL); } | if_expression | while_expression | for_expression | LP expression RP { $$ = $2; } | IDENTIFIER { $$ = clc_create_identifier_expression($1); } | INT_LITERAL I { $$ = clc_create_complex_expression($1); } | DOUBLE_LITERAL I { $$ = clc_create_complex_expression($1); } | INT_LITERAL | DOUBLE_LITERAL ; if_expression : IF expression LC expression_list RC { $$ = clc_create_if_expression($2, $4, NULL); } | IF expression LC expression_list RC ELSE LC expression_list RC { $$ = clc_create_if_expression($2, $4, $8); } ; while_expression : WHILE expression LC expression_list RC { $$ = clc_create_while_expression($2, $4); } ; for_expression : FOR LP expression SEMICOLON expression SEMICOLON expression RP LC expression_list RC { $$ = clc_create_for_expression($3, $5, $7, $10); } ; %%
#ifndef PRIVATE_CALC_H_INCLUDED #define PRIVATE_CALC_H_INCLUDED #include <stdio.h> #include <setjmp.h> #include "MEM.h" #include "CLC.h" #define smaller(a, b) ((a) < (b) ? (a) : (b)) #define larger(a, b) ((a) > (b) ? (a) : (b)) struct symrec { char *name; double (*fnctptr)(); struct symrec *next; }; typedef struct symrec symrec; extern symrec *sym_table; symrec *putsym (); symrec *getsym (); 省略 typedef enum { INT_EXPRESSION = 1, DOUBLE_EXPRESSION, COMPLEX_EXPRESSION, IDENTIFIER_EXPRESSION, EXPRESSION_LIST_EXPRESSION, ASSIGN_EXPRESSION, ADD_EXPRESSION, SUB_EXPRESSION, MUL_EXPRESSION, DIV_EXPRESSION, MOD_EXPRESSION, EQ_EXPRESSION, NE_EXPRESSION, GT_EXPRESSION, GE_EXPRESSION, LT_EXPRESSION, LE_EXPRESSION, MINUS_EXPRESSION, IF_EXPRESSION, WHILE_EXPRESSION, FOR_EXPRESSION, FUNCTION_CALL_EXPRESSION, EXPRESSION_TYPE_NUM } ExpressionType; 省略 typedef struct { Expression *condition1; Expression *condition2; Expression *condition3; Expression *expression_list; } ForExpression; typedef struct { char *identifier; Expression *argument; } FunctionCallExpression; typedef struct { double r; double i; } Complex; struct Expression_tag { ExpressionType type; union { int int_value; double double_value; Complex complex_value; char *identifier; ExpressionList expression_list; AssignExpression assign_expression; BinaryExpression binary_expression; Expression *minus_expression; IfExpression if_expression; FunctionCallExpression function_call_expression; WhileExpression while_expression; ForExpression for_expression; } u; }; typedef struct ParameterList_tag { char *name; struct ParameterList_tag *next; } ParameterList; typedef struct FunctionDefinition_tag { char *name; ParameterList *parameter; Expression *expression_list; MEM_Storage storage; struct FunctionDefinition_tag *next; } FunctionDefinition; typedef enum { INT_VALUE = 1, DOUBLE_VALUE, COMPLEX_VALUE, NULL_VALUE } ValueType; typedef struct { ValueType type; union { int int_value; double double_value; Complex complex_value; } u; } Value; 省略
Expression * clc_create_complex_expression(Expression *operand) { if (operand->type == INT_EXPRESSION) { operand->u.complex_value.i = operand->u.int_value; } else { operand->u.complex_value.i = operand->u.double_value; } operand->u.complex_value.r = 0; operand->type = COMPLEX_EXPRESSION; return operand; } Expression * clc_create_for_expression(Expression *condition1, Expression *condition2, Expression *condition3, Expression *expression) { Expression *exp; exp = clc_alloc_expression(FOR_EXPRESSION); exp->u.for_expression.condition1 = condition1; exp->u.for_expression.condition2 = condition2; exp->u.for_expression.condition3 = condition3; exp->u.for_expression.expression_list = expression; return exp; }
#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_complex_expression(Complex complex_value) { Value v; v.type = COMPLEX_VALUE; v.u.complex_value.r = complex_value.r; v.u.complex_value.i = complex_value.i; return v; } 省略 static void eval_binary_complex(ExpressionType operator, Complex left, Complex right, Value *result) { if (operator == ADD_EXPRESSION || operator == SUB_EXPRESSION || operator == MUL_EXPRESSION ) { result->type = COMPLEX_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.complex_value.r = left.r + right.r; result->u.complex_value.i = left.i + right.i; break; case SUB_EXPRESSION: result->u.complex_value.r = left.r - right.r; result->u.complex_value.i = left.i - right.i; break; case MUL_EXPRESSION: result->u.complex_value.r = left.r * right.r - left.i * right.i; result->u.complex_value.i = left.i * right.r + left.r * right.i; break; case DIV_EXPRESSION: case MOD_EXPRESSION: case EQ_EXPRESSION: case NE_EXPRESSION: case GT_EXPRESSION: case GE_EXPRESSION: case LT_EXPRESSION: case LE_EXPRESSION: case MINUS_EXPRESSION: /* FALLTHRU */ case IF_EXPRESSION: /* FALLTHRU */ case WHILE_EXPRESSION: /* FALLTHRU */ case FOR_EXPRESSION: /* FALLTHRU */ case FUNCTION_CALL_EXPRESSION: /* FALLTHRU */ case EXPRESSION_TYPE_NUM: /* FALLTHRU */ default: DBG_assert(0, ("bad default...%d", operator)); } } void convert_value_to_complex(Value *v) { if (v->type == INT_VALUE) { v->u.complex_value.r = v->u.int_value; } else { v->u.complex_value.r = v->u.double_value; } v->type = COMPLEX_EXPRESSION; v->u.complex_value.i = 0; } 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 == COMPLEX_VALUE && right_val.type == COMPLEX_VALUE) { eval_binary_complex(operator, left_val.u.complex_value, right_val.u.complex_value, &result); } else if (left_val.type == COMPLEX_VALUE) { convert_value_to_complex(&right_val); eval_binary_complex(operator, left_val.u.complex_value, right_val.u.complex_value, &result); } else if (right_val.type == COMPLEX_VALUE) { convert_value_to_complex(&left_val); eval_binary_complex(operator, left_val.u.complex_value, right_val.u.complex_value, &result); } else 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 if (operand_val.type == DOUBLE_VALUE) { 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; } else { DBG_assert(operand_val.type == COMPLEX_VALUE, ("operand_val.type..%d", operand_val.type)); result.type = COMPLEX_VALUE; result.u.complex_value.r = -operand_val.u.complex_value.r; result.u.complex_value.i = -operand_val.u.complex_value.i; } return result; } 省略 static Value eval_for_expression(LocalEnvironment *env, Expression *condition1, Expression *condition2, Expression *condition3, Expression *expression_list) { Value condition_val; Value result; condition_val = eval_expression(env, condition1); for (;;) { condition_val = eval_expression(env, condition2); 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); condition_val = eval_expression(env, condition3); } 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; symrec *s; s = getsym (identifier); if (s != 0){ result = eval_expression(env, argument->u.expression_list.expression); if (result.type == INT_VALUE) { /* cast int to double */ result.u.double_value = result.u.int_value; } result.u.double_value = (*(s->fnctptr))(result.u.double_value); result.type = DOUBLE_VALUE; return result; } 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 COMPLEX_EXPRESSION: v = eval_complex_expression(expr->u.complex_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 FOR_EXPRESSION: v = eval_for_expression(env, expr->u.for_expression.condition1, expr->u.for_expression.condition2, expr->u.for_expression.condition3, expr->u.for_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 if (v.type == COMPLEX_VALUE) { printf(">>%f + %f i\n", v.u.complex_value.r, v.u.complex_value.i); } else { printf("<void>\n"); } } } else { } clc_reopen_current_storage(); }
#include <stdio.h> #include <math.h> #include "CLC.h" #include "calc.h" int main(int argc, char **argv) { CLC_Interpreter interpreter; printf("---- Wellcome ----"); printf("\n"); init_table (); interpreter = CLC_create_interpreter(); CLC_interpret(interpreter, stdin, CLC_TTY_INPUT_MODE); CLC_dispose_interpreter(interpreter); return 0; } struct init { char *fname; double (*fnct)(); }; struct init arith_fncts[] = { "sin", sin, "cos", cos, "asin", asin, "acos", acos, "atan", atan, "ln", log, "exp", exp, "sqrt", sqrt, "tan",tan, 0, 0 }; symrec *sym_table = (symrec *)0; void init_table () { int i; symrec *ptr; for (i = 0; arith_fncts[i].fname != 0; i++) { ptr = putsym (arith_fncts[i].fname); ptr->fnctptr = arith_fncts[i].fnct; } } symrec * putsym (sym_name) char *sym_name; { symrec *ptr; ptr = (symrec *) malloc (sizeof (symrec)); ptr->name = (char *) malloc (strlen (sym_name) + 1); strcpy (ptr->name,sym_name); ptr->next = (struct symrec *)sym_table; sym_table = ptr; return ptr; } symrec * getsym (sym_name) char *sym_name; { symrec *ptr; for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) if (strcmp (ptr->name,sym_name) == 0) return ptr; return 0; }